diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ded7d9df068e0..e2635ffb3eaf0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,4 +1,34 @@ +# This file lists reviewers that are auto-assigned when a pull request modifies +# certain files or directories. If you add yourself to this file, you commit to +# reviewing a large fraction of pull requests in the relevant area. +# +# The GitHub "code owners" mechanism is used exclusively to auto-assign +# reviewers and does not carry significance beyond that. It is not necessary +# to receive an approval from a "code owner" in particular -- any LLVM project +# member can approve pull requests. +# +# Note that GitHub's concept of "code owner" is independent from LLVM's own +# "code owner" concept, they merely happen to share terminology. See +# https://llvm.org/docs/DeveloperPolicy.html#code-owners, as well as the +# CODE_OWNERS.txt files in the respective subproject directories. + /libcxx/ @llvm/reviewers-libcxx /libcxxabi/ @llvm/reviewers-libcxxabi /libunwind/ @llvm/reviewers-libunwind /runtimes/ @llvm/reviewers-libcxx + +/llvm/lib/Analysis/BasicAliasAnalysis.cpp @nikic +/llvm/lib/Analysis/InstructionSimplify.cpp @nikic +/llvm/lib/Analysis/LazyValueInfo.cpp @nikic +/llvm/lib/Analysis/ScalarEvolution.cpp @nikic +/llvm/lib/Analysis/ValueTracking.cpp @nikic +/llvm/lib/IR/ConstantRange.cpp @nikic +/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @nikic +/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp @nikic +/llvm/lib/Transforms/InstCombine/ @nikic + +/clang/test/CXX/drs/ @Endilll +/clang/www/cxx_dr_status.html @Endilll +/clang/www/make_cxx_dr_status @Endilll + +/lldb/ @JDevlieghere diff --git a/bolt/include/bolt/Core/MCPlus.h b/bolt/include/bolt/Core/MCPlus.h index b4a72ac274fad..31cc9071de76a 100644 --- a/bolt/include/bolt/Core/MCPlus.h +++ b/bolt/include/bolt/Core/MCPlus.h @@ -66,6 +66,7 @@ class MCAnnotation { kTailCall, /// Tail call. kConditionalTailCall, /// CTC. kOffset, /// Offset in the function. + kLabel, /// MCSymbol pointing to this instruction. kGeneric /// First generic annotation. }; diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h index 5e12a4ac14c9e..c9e0e5d599b1f 100644 --- a/bolt/include/bolt/Core/MCPlusBuilder.h +++ b/bolt/include/bolt/Core/MCPlusBuilder.h @@ -160,6 +160,7 @@ class MCPlusBuilder { const MCInstrAnalysis *Analysis; const MCInstrInfo *Info; const MCRegisterInfo *RegInfo; + const MCSubtargetInfo *STI; /// Map annotation name into an annotation index. StringMap AnnotationNameIndexMap; @@ -331,8 +332,8 @@ class MCPlusBuilder { public: MCPlusBuilder(const MCInstrAnalysis *Analysis, const MCInstrInfo *Info, - const MCRegisterInfo *RegInfo) - : Analysis(Analysis), Info(Info), RegInfo(RegInfo) { + const MCRegisterInfo *RegInfo, const MCSubtargetInfo *STI) + : Analysis(Analysis), Info(Info), RegInfo(RegInfo), STI(STI) { // Initialize the default annotation allocator with id 0 AnnotationAllocators.emplace(0, AnnotationAllocator()); MaxAllocatorId++; @@ -1179,6 +1180,13 @@ class MCPlusBuilder { /// Remove offset annotation. bool clearOffset(MCInst &Inst); + /// Return the label of \p Inst, if available. + std::optional getLabel(const MCInst &Inst) const; + + /// Set the label of \p Inst. This label will be emitted right before \p Inst + /// is emitted to MCStreamer. + bool setLabel(MCInst &Inst, MCSymbol *Label); + /// Return MCSymbol that represents a target of this instruction at a given /// operand number \p OpNum. If there's no symbol associated with /// the operand - return nullptr. @@ -2079,15 +2087,18 @@ class MCPlusBuilder { MCPlusBuilder *createX86MCPlusBuilder(const MCInstrAnalysis *, const MCInstrInfo *, - const MCRegisterInfo *); + const MCRegisterInfo *, + const MCSubtargetInfo *); MCPlusBuilder *createAArch64MCPlusBuilder(const MCInstrAnalysis *, const MCInstrInfo *, - const MCRegisterInfo *); + const MCRegisterInfo *, + const MCSubtargetInfo *); MCPlusBuilder *createRISCVMCPlusBuilder(const MCInstrAnalysis *, const MCInstrInfo *, - const MCRegisterInfo *); + const MCRegisterInfo *, + const MCSubtargetInfo *); } // namespace bolt } // namespace llvm diff --git a/bolt/include/bolt/Core/Relocation.h b/bolt/include/bolt/Core/Relocation.h index 6fc1057738285..bc16d952e7a29 100644 --- a/bolt/include/bolt/Core/Relocation.h +++ b/bolt/include/bolt/Core/Relocation.h @@ -98,6 +98,10 @@ struct Relocation { /// Return true if relocation type is for thread local storage. static bool isTLS(uint64_t Type); + /// Return true of relocation type is for referencing a specific instruction + /// (as opposed to a function, basic block, etc). + static bool isInstructionReference(uint64_t Type); + /// Return code for a NONE relocation static uint64_t getNone(); diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h index 1dacdc944f977..329fe356603d0 100644 --- a/bolt/include/bolt/Rewrite/RewriteInstance.h +++ b/bolt/include/bolt/Rewrite/RewriteInstance.h @@ -584,7 +584,8 @@ class RewriteInstance { MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch, const MCInstrAnalysis *Analysis, const MCInstrInfo *Info, - const MCRegisterInfo *RegInfo); + const MCRegisterInfo *RegInfo, + const MCSubtargetInfo *STI); } // namespace bolt } // namespace llvm diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp index 51ffe5cec5a8c..b5514228d7a25 100644 --- a/bolt/lib/Core/BinaryContext.cpp +++ b/bolt/lib/Core/BinaryContext.cpp @@ -1888,6 +1888,8 @@ void BinaryContext::printInstruction(raw_ostream &OS, const MCInst &Instruction, } if (std::optional Offset = MIB->getOffset(Instruction)) OS << " # Offset: " << *Offset; + if (auto Label = MIB->getLabel(Instruction)) + OS << " # Label: " << **Label; MIB->printAnnotations(Instruction, OS); diff --git a/bolt/lib/Core/BinaryEmitter.cpp b/bolt/lib/Core/BinaryEmitter.cpp index 95ab63521c06a..b1ee6cc221d71 100644 --- a/bolt/lib/Core/BinaryEmitter.cpp +++ b/bolt/lib/Core/BinaryEmitter.cpp @@ -498,6 +498,9 @@ void BinaryEmitter::emitFunctionBody(BinaryFunction &BF, FunctionFragment &FF, BB->getLocSyms().emplace_back(Offset, LocSym); } + if (auto Label = BC.MIB->getLabel(Instr)) + Streamer.emitLabel(*Label); + Streamer.emitInstruction(Instr, *BC.STI); LastIsPrefix = BC.MIB->isPrefix(Instr); } diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index 6cf1cfb50a9c1..c475e4f9035fe 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -1173,6 +1173,13 @@ bool BinaryFunction::disassemble() { // basic block. Labels[0] = Ctx->createNamedTempSymbol("BB0"); + // Map offsets in the function to a label that should always point to the + // corresponding instruction. This is used for labels that shouldn't point to + // the start of a basic block but always to a specific instruction. This is + // used, for example, on RISC-V where %pcrel_lo relocations point to the + // corresponding %pcrel_hi. + LabelsMapType InstructionLabels; + uint64_t Size = 0; // instruction size for (uint64_t Offset = 0; Offset < getSize(); Offset += Size) { MCInst Instruction; @@ -1329,9 +1336,23 @@ bool BinaryFunction::disassemble() { ItrE = Relocations.lower_bound(Offset + Size); Itr != ItrE; ++Itr) { const Relocation &Relocation = Itr->second; + MCSymbol *Symbol = Relocation.Symbol; + + if (Relocation::isInstructionReference(Relocation.Type)) { + uint64_t RefOffset = Relocation.Value - getAddress(); + LabelsMapType::iterator LI = InstructionLabels.find(RefOffset); + + if (LI == InstructionLabels.end()) { + Symbol = BC.Ctx->createNamedTempSymbol(); + InstructionLabels.emplace(RefOffset, Symbol); + } else { + Symbol = LI->second; + } + } + int64_t Value = Relocation.Value; const bool Result = BC.MIB->replaceImmWithSymbolRef( - Instruction, Relocation.Symbol, Relocation.Addend, Ctx.get(), Value, + Instruction, Symbol, Relocation.Addend, Ctx.get(), Value, Relocation.Type); (void)Result; assert(Result && "cannot replace immediate with relocation"); @@ -1366,6 +1387,13 @@ bool BinaryFunction::disassemble() { addInstruction(Offset, std::move(Instruction)); } + for (auto [Offset, Label] : InstructionLabels) { + InstrMapType::iterator II = Instructions.find(Offset); + assert(II != Instructions.end() && "reference to non-existing instruction"); + + BC.MIB->setLabel(II->second, Label); + } + // Reset symbolizer for the disassembler. BC.SymbolicDisAsm->setSymbolizer(nullptr); @@ -1761,7 +1789,8 @@ bool BinaryFunction::postProcessIndirectBranches( uint64_t LastJT = 0; uint16_t LastJTIndexReg = BC.MIB->getNoRegister(); for (BinaryBasicBlock &BB : blocks()) { - for (MCInst &Instr : BB) { + for (BinaryBasicBlock::iterator II = BB.begin(); II != BB.end(); ++II) { + MCInst &Instr = *II; if (!BC.MIB->isIndirectBranch(Instr)) continue; @@ -1789,7 +1818,7 @@ bool BinaryFunction::postProcessIndirectBranches( const MCExpr *DispExpr; MCInst *PCRelBaseInstr; IndirectBranchType Type = BC.MIB->analyzeIndirectBranch( - Instr, BB.begin(), BB.end(), PtrSize, MemLocInstr, BaseRegNum, + Instr, BB.begin(), II, PtrSize, MemLocInstr, BaseRegNum, IndexRegNum, DispValue, DispExpr, PCRelBaseInstr); if (Type != IndirectBranchType::UNKNOWN || MemLocInstr != nullptr) continue; @@ -4488,7 +4517,7 @@ void BinaryFunction::addRelocation(uint64_t Address, MCSymbol *Symbol, uint64_t Offset = Address - getAddress(); LLVM_DEBUG(dbgs() << "BOLT-DEBUG: addRelocation in " << formatv("{0}@{1:x} against {2}\n", *this, Offset, - Symbol->getName())); + (Symbol ? Symbol->getName() : ""))); bool IsCI = BC.isAArch64() && isInConstantIsland(Address); std::map &Rels = IsCI ? Islands->Relocations : Relocations; diff --git a/bolt/lib/Core/MCPlusBuilder.cpp b/bolt/lib/Core/MCPlusBuilder.cpp index 027cef1063ee3..0a5eb44e4876f 100644 --- a/bolt/lib/Core/MCPlusBuilder.cpp +++ b/bolt/lib/Core/MCPlusBuilder.cpp @@ -268,6 +268,17 @@ bool MCPlusBuilder::clearOffset(MCInst &Inst) { return true; } +std::optional MCPlusBuilder::getLabel(const MCInst &Inst) const { + if (auto Label = tryGetAnnotationAs(Inst, MCAnnotation::kLabel)) + return *Label; + return std::nullopt; +} + +bool MCPlusBuilder::setLabel(MCInst &Inst, MCSymbol *Label) { + getOrCreateAnnotationAs(Inst, MCAnnotation::kLabel) = Label; + return true; +} + bool MCPlusBuilder::hasAnnotation(const MCInst &Inst, unsigned Index) const { const MCInst *AnnotationInst = getAnnotationInst(Inst); if (!AnnotationInst) diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp index 6a4e7089bf248..e4d0f26c305f4 100644 --- a/bolt/lib/Core/Relocation.cpp +++ b/bolt/lib/Core/Relocation.cpp @@ -20,6 +20,13 @@ using namespace llvm; using namespace bolt; +namespace ELFReserved { +enum { + R_RISCV_TPREL_I = 49, + R_RISCV_TPREL_S = 50, +}; +} // namespace ELFReserved + Triple::ArchType Relocation::Arch; static bool isSupportedX86(uint64_t Type) { @@ -111,6 +118,13 @@ static bool isSupportedRISCV(uint64_t Type) { case ELF::R_RISCV_LO12_I: case ELF::R_RISCV_LO12_S: case ELF::R_RISCV_64: + case ELF::R_RISCV_TLS_GOT_HI20: + case ELF::R_RISCV_TPREL_HI20: + case ELF::R_RISCV_TPREL_ADD: + case ELF::R_RISCV_TPREL_LO12_I: + case ELF::R_RISCV_TPREL_LO12_S: + case ELFReserved::R_RISCV_TPREL_I: + case ELFReserved::R_RISCV_TPREL_S: return true; } } @@ -214,6 +228,7 @@ static size_t getSizeForTypeRISCV(uint64_t Type) { return 4; case ELF::R_RISCV_64: case ELF::R_RISCV_GOT_HI20: + case ELF::R_RISCV_TLS_GOT_HI20: // See extractValueRISCV for why this is necessary. return 8; } @@ -532,6 +547,7 @@ static uint64_t extractValueRISCV(uint64_t Type, uint64_t Contents, case ELF::R_RISCV_BRANCH: return extractBImmRISCV(Contents); case ELF::R_RISCV_GOT_HI20: + case ELF::R_RISCV_TLS_GOT_HI20: // We need to know the exact address of the GOT entry so we extract the // value from both the AUIPC and L[D|W]. We cannot rely on the symbol in the // relocation for this since it simply refers to the object that is stored @@ -600,6 +616,7 @@ static bool isGOTRISCV(uint64_t Type) { default: return false; case ELF::R_RISCV_GOT_HI20: + case ELF::R_RISCV_TLS_GOT_HI20: return true; } } @@ -636,6 +653,14 @@ static bool isTLSRISCV(uint64_t Type) { switch (Type) { default: return false; + case ELF::R_RISCV_TLS_GOT_HI20: + case ELF::R_RISCV_TPREL_HI20: + case ELF::R_RISCV_TPREL_ADD: + case ELF::R_RISCV_TPREL_LO12_I: + case ELF::R_RISCV_TPREL_LO12_S: + case ELFReserved::R_RISCV_TPREL_I: + case ELFReserved::R_RISCV_TPREL_S: + return true; } } @@ -733,6 +758,7 @@ static bool isPCRelativeRISCV(uint64_t Type) { case ELF::R_RISCV_RVC_JUMP: case ELF::R_RISCV_RVC_BRANCH: case ELF::R_RISCV_32_PCREL: + case ELF::R_RISCV_TLS_GOT_HI20: return true; } } @@ -832,6 +858,19 @@ bool Relocation::isTLS(uint64_t Type) { return isTLSX86(Type); } +bool Relocation::isInstructionReference(uint64_t Type) { + if (Arch != Triple::riscv64) + return false; + + switch (Type) { + default: + return false; + case ELF::R_RISCV_PCREL_LO12_I: + case ELF::R_RISCV_PCREL_LO12_S: + return true; + } +} + uint64_t Relocation::getNone() { if (Arch == Triple::aarch64) return ELF::R_AARCH64_NONE; diff --git a/bolt/lib/Passes/BinaryPasses.cpp b/bolt/lib/Passes/BinaryPasses.cpp index bb760ea93ad16..3ba53d7b2b798 100644 --- a/bolt/lib/Passes/BinaryPasses.cpp +++ b/bolt/lib/Passes/BinaryPasses.cpp @@ -575,6 +575,7 @@ bool CheckLargeFunctions::shouldOptimize(const BinaryFunction &BF) const { void LowerAnnotations::runOnFunctions(BinaryContext &BC) { std::vector> PreservedOffsetAnnotations; + std::vector> PreservedLabelAnnotations; for (auto &It : BC.getBinaryFunctions()) { BinaryFunction &BF = It.second; @@ -609,6 +610,8 @@ void LowerAnnotations::runOnFunctions(BinaryContext &BC) { if (BF.requiresAddressTranslation() && BC.MIB->getOffset(*II)) PreservedOffsetAnnotations.emplace_back(&(*II), *BC.MIB->getOffset(*II)); + if (auto Label = BC.MIB->getLabel(*II)) + PreservedLabelAnnotations.emplace_back(&*II, *Label); BC.MIB->stripAnnotations(*II); } } @@ -625,6 +628,8 @@ void LowerAnnotations::runOnFunctions(BinaryContext &BC) { // Reinsert preserved annotations we need during code emission. for (const std::pair &Item : PreservedOffsetAnnotations) BC.MIB->setOffset(*Item.first, Item.second); + for (auto [Instr, Label] : PreservedLabelAnnotations) + BC.MIB->setLabel(*Instr, Label); } // Check for dirty state in MCSymbol objects that might be a consequence diff --git a/bolt/lib/Passes/FixRISCVCallsPass.cpp b/bolt/lib/Passes/FixRISCVCallsPass.cpp index 963a8b04cf9db..e2984deda16dc 100644 --- a/bolt/lib/Passes/FixRISCVCallsPass.cpp +++ b/bolt/lib/Passes/FixRISCVCallsPass.cpp @@ -43,7 +43,12 @@ void FixRISCVCallsPass::runOnFunction(BinaryFunction &BF) { MCInst OldCall = *NextII; auto L = BC.scopeLock(); - MIB->createCall(*II, Target, Ctx); + + if (MIB->isTailCall(*NextII)) + MIB->createTailCall(*II, Target, Ctx); + else + MIB->createCall(*II, Target, Ctx); + MIB->moveAnnotations(std::move(OldCall), *II); // The original offset was set on the jalr of the auipc+jalr pair. Since diff --git a/bolt/lib/Passes/LongJmp.cpp b/bolt/lib/Passes/LongJmp.cpp index 31bb8000dda00..6f4d1170dbe2a 100644 --- a/bolt/lib/Passes/LongJmp.cpp +++ b/bolt/lib/Passes/LongJmp.cpp @@ -138,10 +138,13 @@ BinaryBasicBlock *LongJmpPass::lookupStubFromGroup( Cand = LeftCand; } int BitsAvail = BC.MIB->getPCRelEncodingSize(Inst) - 1; - uint64_t Mask = ~((1ULL << BitsAvail) - 1); + assert(BitsAvail < 63 && "PCRelEncodingSize is too large to use int64_t to" + "check for out-of-bounds."); + int64_t MaxVal = (1ULL << BitsAvail) - 1; + int64_t MinVal = -(1ULL << BitsAvail); uint64_t PCRelTgtAddress = Cand->first; - PCRelTgtAddress = DotAddress > PCRelTgtAddress ? DotAddress - PCRelTgtAddress - : PCRelTgtAddress - DotAddress; + int64_t PCOffset = (int64_t)(PCRelTgtAddress - DotAddress); + LLVM_DEBUG({ if (Candidates.size() > 1) dbgs() << "Considering stub group with " << Candidates.size() @@ -149,7 +152,7 @@ BinaryBasicBlock *LongJmpPass::lookupStubFromGroup( << ", chosen candidate address is " << Twine::utohexstr(Cand->first) << "\n"; }); - return PCRelTgtAddress & Mask ? nullptr : Cand->second; + return (PCOffset < MinVal || PCOffset > MaxVal) ? nullptr : Cand->second; } BinaryBasicBlock * @@ -512,13 +515,15 @@ bool LongJmpPass::needsStub(const BinaryBasicBlock &BB, const MCInst &Inst, } int BitsAvail = BC.MIB->getPCRelEncodingSize(Inst) - 1; - uint64_t Mask = ~((1ULL << BitsAvail) - 1); + assert(BitsAvail < 63 && "PCRelEncodingSize is too large to use int64_t to" + "check for out-of-bounds."); + int64_t MaxVal = (1ULL << BitsAvail) - 1; + int64_t MinVal = -(1ULL << BitsAvail); uint64_t PCRelTgtAddress = getSymbolAddress(BC, TgtSym, TgtBB); - PCRelTgtAddress = DotAddress > PCRelTgtAddress ? DotAddress - PCRelTgtAddress - : PCRelTgtAddress - DotAddress; + int64_t PCOffset = (int64_t)(PCRelTgtAddress - DotAddress); - return PCRelTgtAddress & Mask; + return PCOffset < MinVal || PCOffset > MaxVal; } bool LongJmpPass::relax(BinaryFunction &Func) { diff --git a/bolt/lib/Rewrite/MachORewriteInstance.cpp b/bolt/lib/Rewrite/MachORewriteInstance.cpp index b827a196c8265..8be8257f15c1c 100644 --- a/bolt/lib/Rewrite/MachORewriteInstance.cpp +++ b/bolt/lib/Rewrite/MachORewriteInstance.cpp @@ -56,25 +56,28 @@ namespace bolt { extern MCPlusBuilder *createX86MCPlusBuilder(const MCInstrAnalysis *, const MCInstrInfo *, - const MCRegisterInfo *); + const MCRegisterInfo *, + const MCSubtargetInfo *); extern MCPlusBuilder *createAArch64MCPlusBuilder(const MCInstrAnalysis *, const MCInstrInfo *, - const MCRegisterInfo *); + const MCRegisterInfo *, + const MCSubtargetInfo *); namespace { MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch, const MCInstrAnalysis *Analysis, const MCInstrInfo *Info, - const MCRegisterInfo *RegInfo) { + const MCRegisterInfo *RegInfo, + const MCSubtargetInfo *STI) { #ifdef X86_AVAILABLE if (Arch == Triple::x86_64) - return createX86MCPlusBuilder(Analysis, Info, RegInfo); + return createX86MCPlusBuilder(Analysis, Info, RegInfo, STI); #endif #ifdef AARCH64_AVAILABLE if (Arch == Triple::aarch64) - return createAArch64MCPlusBuilder(Analysis, Info, RegInfo); + return createAArch64MCPlusBuilder(Analysis, Info, RegInfo, STI); #endif llvm_unreachable("architecture unsupported by MCPlusBuilder"); @@ -106,8 +109,9 @@ MachORewriteInstance::MachORewriteInstance(object::MachOObjectFile *InputFile, return; } BC = std::move(BCOrErr.get()); - BC->initializeTarget(std::unique_ptr(createMCPlusBuilder( - BC->TheTriple->getArch(), BC->MIA.get(), BC->MII.get(), BC->MRI.get()))); + BC->initializeTarget(std::unique_ptr( + createMCPlusBuilder(BC->TheTriple->getArch(), BC->MIA.get(), + BC->MII.get(), BC->MRI.get(), BC->STI.get()))); if (opts::Instrument) BC->setRuntimeLibrary(std::make_unique()); } diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 5cbbd1a5a8aca..8b821eb984b95 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -272,20 +272,21 @@ extern const char *BoltRevision; MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch, const MCInstrAnalysis *Analysis, const MCInstrInfo *Info, - const MCRegisterInfo *RegInfo) { + const MCRegisterInfo *RegInfo, + const MCSubtargetInfo *STI) { #ifdef X86_AVAILABLE if (Arch == Triple::x86_64) - return createX86MCPlusBuilder(Analysis, Info, RegInfo); + return createX86MCPlusBuilder(Analysis, Info, RegInfo, STI); #endif #ifdef AARCH64_AVAILABLE if (Arch == Triple::aarch64) - return createAArch64MCPlusBuilder(Analysis, Info, RegInfo); + return createAArch64MCPlusBuilder(Analysis, Info, RegInfo, STI); #endif #ifdef RISCV_AVAILABLE if (Arch == Triple::riscv64) - return createRISCVMCPlusBuilder(Analysis, Info, RegInfo); + return createRISCVMCPlusBuilder(Analysis, Info, RegInfo, STI); #endif llvm_unreachable("architecture unsupported by MCPlusBuilder"); @@ -348,8 +349,9 @@ RewriteInstance::RewriteInstance(ELFObjectFileBase *File, const int Argc, return; } BC = std::move(BCOrErr.get()); - BC->initializeTarget(std::unique_ptr(createMCPlusBuilder( - BC->TheTriple->getArch(), BC->MIA.get(), BC->MII.get(), BC->MRI.get()))); + BC->initializeTarget(std::unique_ptr( + createMCPlusBuilder(BC->TheTriple->getArch(), BC->MIA.get(), + BC->MII.get(), BC->MRI.get(), BC->STI.get()))); BAT = std::make_unique(); @@ -408,8 +410,9 @@ static bool checkOffsets(const typename ELFT::Phdr &Phdr, return true; // Only non-empty sections can be at the end of a segment. - uint64_t SectionSize = Sec.sh_size ? Sec.sh_size : 1; - AddressRange SectionAddressRange(Sec.sh_offset, Sec.sh_offset + SectionSize); + uint64_t SectionSize = Sec.sh_size ? Sec.sh_size : 1ull; + AddressRange SectionAddressRange((uint64_t)Sec.sh_offset, + Sec.sh_offset + SectionSize); AddressRange SegmentAddressRange(Phdr.p_offset, Phdr.p_offset + Phdr.p_filesz); if (SegmentAddressRange.contains(SectionAddressRange)) @@ -425,8 +428,9 @@ template static bool checkVMA(const typename ELFT::Phdr &Phdr, const typename ELFT::Shdr &Sec, bool &Overlap) { // Only non-empty sections can be at the end of a segment. - uint64_t SectionSize = Sec.sh_size ? Sec.sh_size : 1; - AddressRange SectionAddressRange(Sec.sh_addr, Sec.sh_addr + SectionSize); + uint64_t SectionSize = Sec.sh_size ? Sec.sh_size : 1ull; + AddressRange SectionAddressRange((uint64_t)Sec.sh_addr, + Sec.sh_addr + SectionSize); AddressRange SegmentAddressRange(Phdr.p_vaddr, Phdr.p_vaddr + Phdr.p_memsz); if (SegmentAddressRange.contains(SectionAddressRange)) @@ -2332,7 +2336,8 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection, if (BC->isX86()) return; - // The non-got related TLS relocations on AArch64 also could be skipped. + // The non-got related TLS relocations on AArch64 and RISC-V also could be + // skipped. if (!Relocation::isGOT(RType)) return; } @@ -2541,7 +2546,17 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection, // Adjust the point of reference to a code location inside a function. if (ReferencedBF->containsAddress(Address, /*UseMaxSize = */ true)) { RefFunctionOffset = Address - ReferencedBF->getAddress(); - if (RefFunctionOffset) { + if (Relocation::isInstructionReference(RType)) { + // Instruction labels are created while disassembling so we just leave + // the symbol empty for now. Since the extracted value is typically + // unrelated to the referenced symbol (e.g., %pcrel_lo in RISC-V + // references an instruction but the patched value references the low + // bits of a data address), we set the extracted value to the symbol + // address in order to be able to correctly reconstruct the reference + // later. + ReferencedSymbol = nullptr; + ExtractedValue = Address; + } else if (RefFunctionOffset) { if (ContainingBF && ContainingBF != ReferencedBF) { ReferencedSymbol = ReferencedBF->addEntryPointAtOffset(RefFunctionOffset); diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp index bf77244102a21..c2a4607411a49 100644 --- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp +++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp @@ -128,9 +128,7 @@ static InstructionListType createIncMemory(MCPhysReg RegTo, MCPhysReg RegTmp) { } class AArch64MCPlusBuilder : public MCPlusBuilder { public: - AArch64MCPlusBuilder(const MCInstrAnalysis *Analysis, const MCInstrInfo *Info, - const MCRegisterInfo *RegInfo) - : MCPlusBuilder(Analysis, Info, RegInfo) {} + using MCPlusBuilder::MCPlusBuilder; bool equals(const MCTargetExpr &A, const MCTargetExpr &B, CompFuncTy Comp) const override { @@ -1654,8 +1652,9 @@ namespace bolt { MCPlusBuilder *createAArch64MCPlusBuilder(const MCInstrAnalysis *Analysis, const MCInstrInfo *Info, - const MCRegisterInfo *RegInfo) { - return new AArch64MCPlusBuilder(Analysis, Info, RegInfo); + const MCRegisterInfo *RegInfo, + const MCSubtargetInfo *STI) { + return new AArch64MCPlusBuilder(Analysis, Info, RegInfo, STI); } } // namespace bolt diff --git a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp index c2e64039a2500..af7645f568471 100644 --- a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp +++ b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp @@ -46,6 +46,7 @@ class RISCVMCPlusBuilder : public MCPlusBuilder { case ELF::R_RISCV_HI20: case ELF::R_RISCV_LO12_I: case ELF::R_RISCV_LO12_S: + case ELF::R_RISCV_TLS_GOT_HI20: return true; default: llvm_unreachable("Unexpected RISCV relocation type in code"); @@ -86,6 +87,7 @@ class RISCVMCPlusBuilder : public MCPlusBuilder { return false; case RISCV::JALR: case RISCV::C_JALR: + case RISCV::C_JR: return true; } } @@ -157,6 +159,17 @@ class RISCVMCPlusBuilder : public MCPlusBuilder { DispValue = 0; DispExpr = nullptr; PCRelBaseOut = nullptr; + + // Check for the following long tail call sequence: + // 1: auipc xi, %pcrel_hi(sym) + // jalr zero, %pcrel_lo(1b)(xi) + if (Instruction.getOpcode() == RISCV::JALR && Begin != End) { + MCInst &PrevInst = *std::prev(End); + if (isRISCVCall(PrevInst, Instruction) && + Instruction.getOperand(0).getReg() == RISCV::X0) + return IndirectBranchType::POSSIBLE_TAIL_CALL; + } + return IndirectBranchType::UNKNOWN; } @@ -396,6 +409,7 @@ class RISCVMCPlusBuilder : public MCPlusBuilder { default: return Expr; case ELF::R_RISCV_GOT_HI20: + case ELF::R_RISCV_TLS_GOT_HI20: // The GOT is reused so no need to create GOT relocations case ELF::R_RISCV_PCREL_HI20: return RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_PCREL_HI, Ctx); @@ -457,8 +471,9 @@ namespace bolt { MCPlusBuilder *createRISCVMCPlusBuilder(const MCInstrAnalysis *Analysis, const MCInstrInfo *Info, - const MCRegisterInfo *RegInfo) { - return new RISCVMCPlusBuilder(Analysis, Info, RegInfo); + const MCRegisterInfo *RegInfo, + const MCSubtargetInfo *STI) { + return new RISCVMCPlusBuilder(Analysis, Info, RegInfo, STI); } } // namespace bolt diff --git a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp index 99b08a91d9696..ce8a4d6914854 100644 --- a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp +++ b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp @@ -87,9 +87,7 @@ static InstructionListType createIncMemory(const MCSymbol *Target, class X86MCPlusBuilder : public MCPlusBuilder { public: - X86MCPlusBuilder(const MCInstrAnalysis *Analysis, const MCInstrInfo *Info, - const MCRegisterInfo *RegInfo) - : MCPlusBuilder(Analysis, Info, RegInfo) {} + using MCPlusBuilder::MCPlusBuilder; std::unique_ptr createTargetSymbolizer(BinaryFunction &Function, @@ -3579,8 +3577,9 @@ namespace bolt { MCPlusBuilder *createX86MCPlusBuilder(const MCInstrAnalysis *Analysis, const MCInstrInfo *Info, - const MCRegisterInfo *RegInfo) { - return new X86MCPlusBuilder(Analysis, Info, RegInfo); + const MCRegisterInfo *RegInfo, + const MCSubtargetInfo *STI) { + return new X86MCPlusBuilder(Analysis, Info, RegInfo, STI); } } // namespace bolt diff --git a/bolt/test/AArch64/Inputs/long-jmp-offset-boundary.ld b/bolt/test/AArch64/Inputs/long-jmp-offset-boundary.ld new file mode 100644 index 0000000000000..94a170ec29850 --- /dev/null +++ b/bolt/test/AArch64/Inputs/long-jmp-offset-boundary.ld @@ -0,0 +1,11 @@ +SECTIONS { + . = 0; + . = ALIGN(0x400000); + .text : { + *(foo_section) + . += 0x7BFFFFC; + *(main_section) + ASSERT(foo == 0x400000, "Error: foo address is not 0x400000."); + ASSERT(_start == 0x8000000, "Error: _start address is not 0x8000000."); + } +} diff --git a/bolt/test/AArch64/long-jmp-offset-boundary.s b/bolt/test/AArch64/long-jmp-offset-boundary.s new file mode 100644 index 0000000000000..1aeffd629f6f3 --- /dev/null +++ b/bolt/test/AArch64/long-jmp-offset-boundary.s @@ -0,0 +1,31 @@ +# This test checks long call negative offset boundary(0x8000000) for aarch64. + +# REQUIRES: system-linux + +# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \ +# RUN: %s -o %t.o +# RUN: %clang %cflags %t.o -o %t.exe -nostartfiles -fuse-ld=lld -Wl,-q \ +# RUN: -Wl,--script=%p/Inputs/long-jmp-offset-boundary.ld +# RUN: llvm-bolt %t.exe -o %t.bolt.exe -skip-funcs="foo.*" +# RUN: llvm-objdump -d -j .text --print-imm-hex %t.bolt.exe | FileCheck %s + +# The default alignment of the new program header table and the new text is +# HugePageSize(2MB). +# CHECK: [[#%x,ADDR:]]: [[#]] bl +# CHECK-SAME: 0x[[#ADDR-0x8000000]] + + .text + .section foo_section,"ax",@progbits + .globl foo + .type foo,@function +foo: + ret + .size foo, .-foo + + .section main_section,"ax",@progbits + .globl _start + .type _start,@function +_start: + bl foo + ret + .size _start, .-_start diff --git a/bolt/test/RISCV/Inputs/tls-le-gnu-ld.yaml b/bolt/test/RISCV/Inputs/tls-le-gnu-ld.yaml new file mode 100644 index 0000000000000..feec407ffdfda --- /dev/null +++ b/bolt/test/RISCV/Inputs/tls-le-gnu-ld.yaml @@ -0,0 +1,92 @@ +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_RISCV + Entry: 0x100B0 +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_X, PF_R ] + FirstSec: .text + LastSec: .text + VAddr: 0x10000 + Align: 0x1000 + Offset: 0x0 + - Type: PT_TLS + Flags: [ PF_R ] + FirstSec: .tbss + LastSec: .tbss + VAddr: 0x110C0 + Align: 0x8 + Offset: 0xc0 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x100B0 + AddressAlign: 0x4 + Content: '13000000832202002320520067800000' + - Name: .tbss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ] + Address: 0x110C0 + AddressAlign: 0x8 + Size: 0x8 + - Name: .rela.text + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .text + Relocations: + - Offset: 0x100B4 + Type: R_RISCV_NONE + - Offset: 0x100B4 + Type: R_RISCV_RELAX + - Offset: 0x100B4 + Type: R_RISCV_NONE + - Offset: 0x100B4 + Type: R_RISCV_RELAX + - Offset: 0x100B4 + Symbol: i + Type: 0x31 + - Offset: 0x100B4 + Type: R_RISCV_RELAX + - Offset: 0x100B8 + Symbol: i + Type: 0x32 + - Offset: 0x100B8 + Type: R_RISCV_RELAX + - Type: SectionHeaderTable + Sections: + - Name: .text + - Name: .rela.text + - Name: .tbss + - Name: .symtab + - Name: .strtab + - Name: .shstrtab +Symbols: + - Name: .text + Type: STT_SECTION + Section: .text + Value: 0x100B0 + - Name: .tbss + Type: STT_SECTION + Section: .tbss + Value: 0x110C0 + - Name: '__global_pointer$' + Index: SHN_ABS + Binding: STB_GLOBAL + Value: 0x118C0 + - Name: i + Type: STT_TLS + Section: .tbss + Binding: STB_GLOBAL + Size: 0x8 + - Name: _start + Section: .text + Binding: STB_GLOBAL + Value: 0x100B0 + Size: 0x10 +... diff --git a/bolt/test/RISCV/call-annotations.s b/bolt/test/RISCV/call-annotations.s index e2c5a1040faee..bc539bb0ec779 100644 --- a/bolt/test/RISCV/call-annotations.s +++ b/bolt/test/RISCV/call-annotations.s @@ -4,7 +4,7 @@ // RUN: llvm-mc -triple riscv64 -filetype obj -o %t.o %s // RUN: ld.lld --emit-relocs -o %t %t.o // RUN: llvm-bolt --enable-bat --print-cfg --print-fix-riscv-calls \ -// RUN: --print-only=_start -o /dev/null %t | FileCheck %s +// RUN: -o /dev/null %t | FileCheck %s .text .global f @@ -19,11 +19,24 @@ f: // CHECK-NEXT: jal ra, f # Offset: 8 // CHECK-NEXT: jal zero, f # TAILCALL # Offset: 12 +// CHECK-LABEL: Binary Function "long_tail" after building cfg { +// CHECK: auipc t1, f +// CHECK-NEXT: jalr zero, -24(t1) # TAILCALL # Offset: 8 + +// CHECK-LABEL: Binary Function "compressed_tail" after building cfg { +// CHECK: jr a0 # TAILCALL # Offset: 0 + // CHECK-LABEL: Binary Function "_start" after fix-riscv-calls { // CHECK: call f # Offset: 0 // CHECK-NEXT: call f # Offset: 8 // CHECK-NEXT: tail f # TAILCALL # Offset: 12 +// CHECK-LABEL: Binary Function "long_tail" after fix-riscv-calls { +// CHECK: tail f # TAILCALL # Offset: 4 + +// CHECK-LABEL: Binary Function "compressed_tail" after fix-riscv-calls { +// CHECK: jr a0 # TAILCALL # Offset: 0 + .globl _start .p2align 1 _start: @@ -31,3 +44,21 @@ _start: jal f jal zero, f .size _start, .-_start + + .globl long_tail + .p2align 1 +long_tail: + // NOTE: BOLT assumes indirect calls in single-BB functions are tail calls + // so artificially introduce a second BB to force RISC-V-specific analysis + // to get triggered. + beq a0, a1, 1f +1: + tail f + .size long_tail, .-long_tail + + .globl compressed_tail + .p2align 1 + .option rvc +compressed_tail: + c.jr a0 + .size compressed_tail, .-compressed_tail diff --git a/bolt/test/RISCV/reloc-abs.s b/bolt/test/RISCV/reloc-abs.s index 3e4b8b1395e1f..5b728f092b3c9 100644 --- a/bolt/test/RISCV/reloc-abs.s +++ b/bolt/test/RISCV/reloc-abs.s @@ -17,8 +17,7 @@ _start: .option push .option norelax 1: -// CHECK: .Ltmp0 -// CHECK: auipc gp, %pcrel_hi(__global_pointer$) +// CHECK: auipc gp, %pcrel_hi(__global_pointer$) # Label: .Ltmp0 // CHECK-NEXT: addi gp, gp, %pcrel_lo(.Ltmp0) auipc gp, %pcrel_hi(__global_pointer$) addi gp, gp, %pcrel_lo(1b) diff --git a/bolt/test/RISCV/reloc-bb-split.s b/bolt/test/RISCV/reloc-bb-split.s new file mode 100644 index 0000000000000..5995562cf130b --- /dev/null +++ b/bolt/test/RISCV/reloc-bb-split.s @@ -0,0 +1,42 @@ +// RUN: %clang %cflags -o %t %s +// RUN: llvm-bolt --print-cfg --print-only=_start -o /dev/null %t \ +// RUN: | FileCheck %s + + .data + .globl d + .p2align 3 +d: + .dword 0 + + .text + .globl _start + .p2align 1 +// CHECK-LABEL: Binary Function "_start" after building cfg { +_start: +/// The local label is used for %pcrel_lo as well as a jump target so a new +/// basic block should start there. +// CHECK-LABEL: {{^}}.LBB00 +// CHECK: nop +// CHECK-LABEL: {{^}}.Ltmp0 +// CHECK: auipc t0, %pcrel_hi(d) # Label: .Ltmp1 +// CHECK-NEXT: ld t0, %pcrel_lo(.Ltmp1)(t0) +// CHECK-NEXT: j .Ltmp0 + nop +1: + auipc t0, %pcrel_hi(d) + ld t0, %pcrel_lo(1b)(t0) + j 1b + +/// The local label is used only for %pcrel_lo so no new basic block should +/// start there. +// CHECK-LABEL: {{^}}.LFT0 +// CHECK: nop +// CHECK-NEXT: auipc t0, %pcrel_hi(d) # Label: .Ltmp2 +// CHECK-NEXT: ld t0, %pcrel_lo(.Ltmp2)(t0) +// CHECK-NEXT: ret + nop +1: + auipc t0, %pcrel_hi(d) + ld t0, %pcrel_lo(1b)(t0) + ret + .size _start, .-_start diff --git a/bolt/test/RISCV/reloc-got.s b/bolt/test/RISCV/reloc-got.s index b6cd61be723bf..dcf9d0ea3ffbf 100644 --- a/bolt/test/RISCV/reloc-got.s +++ b/bolt/test/RISCV/reloc-got.s @@ -14,8 +14,7 @@ d: // CHECK: Binary Function "_start" after building cfg { _start: nop // Here to not make the _start and .Ltmp0 symbols coincide -// CHECK: .Ltmp0 -// CHECK: auipc t0, %pcrel_hi(__BOLT_got_zero+{{[0-9]+}}) +// CHECK: auipc t0, %pcrel_hi(__BOLT_got_zero+{{[0-9]+}}) # Label: .Ltmp0 // CHECK-NEXT: ld t0, %pcrel_lo(.Ltmp0)(t0) 1: auipc t0, %got_pcrel_hi(d) diff --git a/bolt/test/RISCV/reloc-pcrel.s b/bolt/test/RISCV/reloc-pcrel.s index 36b132727291e..3ad3015a0a57f 100644 --- a/bolt/test/RISCV/reloc-pcrel.s +++ b/bolt/test/RISCV/reloc-pcrel.s @@ -14,12 +14,10 @@ d: // CHECK: Binary Function "_start" after building cfg { _start: nop // Here to not make the _start and .Ltmp0 symbols coincide -// CHECK: .Ltmp0 -// CHECK: auipc t0, %pcrel_hi(d) +// CHECK: auipc t0, %pcrel_hi(d) # Label: .Ltmp0 // CHECK-NEXT: ld t0, %pcrel_lo(.Ltmp0)(t0) ld t0, d -// CHECK: .Ltmp1 -// CHECK: auipc t1, %pcrel_hi(d) +// CHECK-NEXT: auipc t1, %pcrel_hi(d) # Label: .Ltmp1 // CHECK-NEXT: sd t0, %pcrel_lo(.Ltmp1)(t1) sd t0, d, t1 ret diff --git a/bolt/test/RISCV/reloc-tls.s b/bolt/test/RISCV/reloc-tls.s new file mode 100644 index 0000000000000..44195818277f5 --- /dev/null +++ b/bolt/test/RISCV/reloc-tls.s @@ -0,0 +1,44 @@ +// RUN: llvm-mc -triple riscv64 -filetype obj -o %t.o %s +// RUN: ld.lld --emit-relocs -o %t %t.o +// RUN: llvm-bolt --print-cfg --print-only=tls_le,tls_ie -o /dev/null %t \ +// RUN: | FileCheck %s + +// CHECK-LABEL: Binary Function "tls_le{{.*}}" after building cfg { +// CHECK: lui a5, 0 +// CHECK-NEXT: add a5, a5, tp +// CHECK-NEXT: lw t0, 0(a5) +// CHECK-NEXT: sw t0, 0(a5) + +// CHECK-LABEL: Binary Function "tls_ie" after building cfg { +// CHECK-LABEL: .LBB01 +// CHECK: auipc a0, %pcrel_hi(__BOLT_got_zero+{{[0-9]+}}) +// CHECK-NEXT: ld a0, %pcrel_lo(.Ltmp0)(a0) + .text + .globl tls_le, _start + .p2align 2 +tls_le: +_start: + nop + lui a5, %tprel_hi(i) + add a5, a5, tp, %tprel_add(i) + lw t0, %tprel_lo(i)(a5) + sw t0, %tprel_lo(i)(a5) + ret + .size _start, .-_start + + .globl tls_ie + .p2align 2 +tls_ie: + nop + la.tls.ie a0, i + ret + .size tls_ie, .-tls_ie + + .section .tbss,"awT",@nobits + .type i,@object + .globl i + .p2align 3 +i: + .quad 0 + .size i, .-i + diff --git a/bolt/test/RISCV/tls-le-gnu-ld.test b/bolt/test/RISCV/tls-le-gnu-ld.test new file mode 100644 index 0000000000000..c3ff08b30ee60 --- /dev/null +++ b/bolt/test/RISCV/tls-le-gnu-ld.test @@ -0,0 +1,11 @@ +// This test checks that the binaries produces with GNU ld TLS le relaxation are +// properly processed by BOLT. GNU ld currently emits two non-standard +// relocations (R_RISCV_TPREL_I and R_RISCV_TPREL_S) in this case. + +// RUN: yaml2obj %p/Inputs/tls-le-gnu-ld.yaml &> %t.exe +// RUN: llvm-bolt %t.exe -o %t.bolt.exe --print-cfg --print-only=_start \ +// RUN: | FileCheck %s + +// CHECK: Binary Function "_start" after building cfg { +// CHECK: lw t0, 0(tp) +// CHECK-NEXT: sw t0, 0(tp) diff --git a/bolt/test/checkvma-large-section.test b/bolt/test/checkvma-large-section.test new file mode 100644 index 0000000000000..36a915951115e --- /dev/null +++ b/bolt/test/checkvma-large-section.test @@ -0,0 +1,35 @@ +# This test reproduces the issue with a section which ends at >4G address +REQUIRES: asserts +RUN: split-file %s %t +RUN: yaml2obj %t/yaml -o %t.exe --max-size=0 +RUN: llvm-bolt %t.exe -o /dev/null --allow-stripped +#--- yaml +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +ProgramHeaders: + - Type: PT_LOAD + FirstSec: .a + LastSec: .a + Align: 0x1000 + - Type: PT_LOAD + Flags: [ PF_R, PF_W ] + FirstSec: .large_sec + LastSec: .large_sec + VAddr: 0x4a0279a8 + - Type: PT_GNU_RELRO + Flags: [ PF_R ] +Sections: + - Name: .a + Type: SHT_PROGBITS + Content: 00 + AddressAlign: 0x1 + - Name: .large_sec + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x4a0279a8 + Size: 0xdf8bb1a0 +... diff --git a/bolt/unittests/Core/MCPlusBuilder.cpp b/bolt/unittests/Core/MCPlusBuilder.cpp index 6519ff6934d1f..b851c756e7960 100644 --- a/bolt/unittests/Core/MCPlusBuilder.cpp +++ b/bolt/unittests/Core/MCPlusBuilder.cpp @@ -52,8 +52,9 @@ struct MCPlusBuilderTester : public testing::TestWithParam { BC = cantFail(BinaryContext::createBinaryContext( ObjFile.get(), true, DWARFContext::create(*ObjFile.get()))); ASSERT_FALSE(!BC); - BC->initializeTarget(std::unique_ptr(createMCPlusBuilder( - GetParam(), BC->MIA.get(), BC->MII.get(), BC->MRI.get()))); + BC->initializeTarget(std::unique_ptr( + createMCPlusBuilder(GetParam(), BC->MIA.get(), BC->MII.get(), + BC->MRI.get(), BC->STI.get()))); } void testRegAliases(Triple::ArchType Arch, uint64_t Register, diff --git a/clang-tools-extra/clang-tidy/ClangTidyCheck.h b/clang-tools-extra/clang-tidy/ClangTidyCheck.h index 39b9f9fa865b7..656a2f008f6e0 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyCheck.h +++ b/clang-tools-extra/clang-tidy/ClangTidyCheck.h @@ -184,8 +184,8 @@ class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback { /// integral type ``T``. /// /// Reads the option with the check-local name \p LocalName from the - /// ``CheckOptions``. If the corresponding key is not present, return - /// ``std::nullopt``. + /// ``CheckOptions``. If the corresponding key is not present, + /// return ``std::nullopt``. /// /// If the corresponding key can't be parsed as a ``T``, emit a /// diagnostic and return ``std::nullopt``. @@ -201,6 +201,31 @@ class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback { return std::nullopt; } + /// Read a named option from the ``Context`` and parse it as an + /// integral type ``T``. + /// + /// Reads the option with the check-local name \p LocalName from the + /// ``CheckOptions``. If the corresponding key is `none`, `null`, + /// `-1` or empty, return ``std::nullopt``. If the corresponding + /// key is not present, return \p Default. + /// + /// If the corresponding key can't be parsed as a ``T``, emit a + /// diagnostic and return \p Default. + template + std::enable_if_t, std::optional> + get(StringRef LocalName, std::optional Default) const { + if (std::optional Value = get(LocalName)) { + if (Value == "" || Value == "none" || Value == "null" || + (std::is_unsigned_v && Value == "-1")) + return std::nullopt; + T Result{}; + if (!StringRef(*Value).getAsInteger(10, Result)) + return Result; + diagnoseBadIntegerOption(NamePrefix + LocalName, *Value); + } + return Default; + } + /// Read a named option from the ``Context`` and parse it as an /// integral type ``T``. /// @@ -245,6 +270,39 @@ class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback { return std::nullopt; } + /// Read a named option from the ``Context`` and parse it as an + /// integral type ``T``. + /// + /// Reads the option with the check-local name \p LocalName from local or + /// global ``CheckOptions``. Gets local option first. If local is not + /// present, falls back to get global option. If global option is not + /// present either, return \p Default. If the value value was found + /// and equals ``none``, ``null``, ``-1`` or empty, return ``std::nullopt``. + /// + /// If the corresponding key can't be parsed as a ``T``, emit a + /// diagnostic and return \p Default. + template + std::enable_if_t, std::optional> + getLocalOrGlobal(StringRef LocalName, std::optional Default) const { + std::optional ValueOr = get(LocalName); + bool IsGlobal = false; + if (!ValueOr) { + IsGlobal = true; + ValueOr = getLocalOrGlobal(LocalName); + if (!ValueOr) + return Default; + } + T Result{}; + if (ValueOr == "" || ValueOr == "none" || ValueOr == "null" || + (std::is_unsigned_v && ValueOr == "-1")) + return std::nullopt; + if (!StringRef(*ValueOr).getAsInteger(10, Result)) + return Result; + diagnoseBadIntegerOption( + IsGlobal ? Twine(LocalName) : NamePrefix + LocalName, *ValueOr); + return Default; + } + /// Read a named option from the ``Context`` and parse it as an /// integral type ``T``. /// @@ -286,8 +344,8 @@ class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback { /// enum type ``T``. /// /// Reads the option with the check-local name \p LocalName from the - /// ``CheckOptions``. If the corresponding key is not present, return - /// \p Default. + /// ``CheckOptions``. If the corresponding key is not present, + /// return \p Default. /// /// If the corresponding key can't be parsed as a ``T``, emit a /// diagnostic and return \p Default. @@ -356,6 +414,19 @@ class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback { storeInt(Options, LocalName, Value); } + /// Stores an option with the check-local name \p LocalName with + /// integer value \p Value to \p Options. If the value is empty + /// stores `` + template + std::enable_if_t> + store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, + std::optional Value) const { + if (Value) + storeInt(Options, LocalName, *Value); + else + store(Options, LocalName, "none"); + } + /// Stores an option with the check-local name \p LocalName as the string /// representation of the Enum \p Value to \p Options. /// diff --git a/clang-tools-extra/clang-tidy/llvmlibc/CalleeNamespaceCheck.cpp b/clang-tools-extra/clang-tidy/llvmlibc/CalleeNamespaceCheck.cpp index 98ae857b589fd..af977bff70f7c 100644 --- a/clang-tools-extra/clang-tidy/llvmlibc/CalleeNamespaceCheck.cpp +++ b/clang-tools-extra/clang-tidy/llvmlibc/CalleeNamespaceCheck.cpp @@ -7,9 +7,11 @@ //===----------------------------------------------------------------------===// #include "CalleeNamespaceCheck.h" +#include "NamespaceConstants.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "llvm/ADT/StringSet.h" using namespace clang::ast_matchers; @@ -45,9 +47,11 @@ void CalleeNamespaceCheck::check(const MatchFinder::MatchResult &Result) { if (FuncDecl->getBuiltinID() != 0) return; - // If the outermost namespace of the function is __llvm_libc, we're good. + // If the outermost namespace of the function is a macro that starts with + // __llvm_libc, we're good. const auto *NS = dyn_cast(getOutermostNamespace(FuncDecl)); - if (NS && NS->getName() == "__llvm_libc") + if (NS && Result.SourceManager->isMacroBodyExpansion(NS->getLocation()) && + NS->getName().starts_with(RequiredNamespaceStart)) return; const DeclarationName &Name = FuncDecl->getDeclName(); @@ -55,9 +59,10 @@ void CalleeNamespaceCheck::check(const MatchFinder::MatchResult &Result) { IgnoredFunctions.contains(Name.getAsIdentifierInfo()->getName())) return; - diag(UsageSiteExpr->getBeginLoc(), "%0 must resolve to a function declared " - "within the '__llvm_libc' namespace") - << FuncDecl; + diag(UsageSiteExpr->getBeginLoc(), + "%0 must resolve to a function declared " + "within the namespace defined by the '%1' macro") + << FuncDecl << RequiredNamespaceMacroName; diag(FuncDecl->getLocation(), "resolves to this declaration", clang::DiagnosticIDs::Note); diff --git a/clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp b/clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp index bbc60217cdb1d..ae9819ed97502 100644 --- a/clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp +++ b/clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "ImplementationInNamespaceCheck.h" +#include "NamespaceConstants.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" @@ -14,9 +15,6 @@ using namespace clang::ast_matchers; namespace clang::tidy::llvm_libc { -const static StringRef RequiredNamespaceStart = "__llvm_libc"; -const static StringRef RequiredNamespaceMacroName = "LIBC_NAMESPACE"; - void ImplementationInNamespaceCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( translationUnitDecl( diff --git a/clang-tools-extra/clang-tidy/llvmlibc/NamespaceConstants.h b/clang-tools-extra/clang-tidy/llvmlibc/NamespaceConstants.h new file mode 100644 index 0000000000000..7d4120085b866 --- /dev/null +++ b/clang-tools-extra/clang-tidy/llvmlibc/NamespaceConstants.h @@ -0,0 +1,16 @@ +//===--- NamespaceConstants.h -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" + +namespace clang::tidy::llvm_libc { + +const static llvm::StringRef RequiredNamespaceStart = "__llvm_libc"; +const static llvm::StringRef RequiredNamespaceMacroName = "LIBC_NAMESPACE"; + +} // namespace clang::tidy::llvm_libc diff --git a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp index fed19bdcc2914..e336ba1ee1fa7 100644 --- a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp @@ -30,6 +30,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Tooling/Core/Replacement.h" #include "clang/Tooling/Inclusions/HeaderIncludes.h" +#include "clang/Tooling/Inclusions/StandardLibrary.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" @@ -97,9 +98,12 @@ bool IncludeCleanerCheck::shouldIgnore(const include_cleaner::Header &H) { return llvm::any_of(IgnoreHeadersRegex, [&H](const llvm::Regex &R) { switch (H.kind()) { case include_cleaner::Header::Standard: + // We don't trim angle brackets around standard library headers + // deliberately, so that they are only matched as , otherwise + // having just `.*/vector` might yield false positives. return R.match(H.standard().name()); case include_cleaner::Header::Verbatim: - return R.match(H.verbatim()); + return R.match(H.verbatim().trim("<>\"")); case include_cleaner::Header::Physical: return R.match(H.physical().getFileEntry().tryGetRealPathName()); } @@ -179,12 +183,14 @@ void IncludeCleanerCheck::check(const MatchFinder::MatchResult &Result) { if (getCurrentMainFile().endswith(PHeader)) continue; } - - if (llvm::none_of( - IgnoreHeadersRegex, - [Resolved = (*I.Resolved).getFileEntry().tryGetRealPathName()]( - const llvm::Regex &R) { return R.match(Resolved); })) - Unused.push_back(&I); + auto StdHeader = tooling::stdlib::Header::named( + I.quote(), PP->getLangOpts().CPlusPlus ? tooling::stdlib::Lang::CXX + : tooling::stdlib::Lang::C); + if (StdHeader && shouldIgnore(*StdHeader)) + continue; + if (shouldIgnore(*I.Resolved)) + continue; + Unused.push_back(&I); } llvm::StringRef Code = SM->getBufferData(SM->getMainFileID()); diff --git a/clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.cpp b/clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.cpp index 407de610d13a7..d7796666d0db2 100644 --- a/clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.cpp @@ -9,6 +9,7 @@ #include "ReturnBracedInitListCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Lex/Lexer.h" #include "clang/Tooling/FixIt.h" @@ -17,11 +18,27 @@ using namespace clang::ast_matchers; namespace clang::tidy::modernize { void ReturnBracedInitListCheck::registerMatchers(MatchFinder *Finder) { - // Skip list initialization and constructors with an initializer list. + auto SemanticallyDifferentContainer = allOf( + hasDeclaration( + // Container(size_type count, const T &value, + // const Allocator &alloc = Allocator()); + cxxConstructorDecl(parameterCountIs(3), + hasParameter(0, hasType(qualType(hasCanonicalType( + isInteger())))))), + hasType(cxxRecordDecl(hasAnyName("::std::basic_string", "::std::vector", + "::std::deque", "::std::forward_list", + "::std::list")))); + auto ConstructExpr = cxxConstructExpr( - unless(anyOf(hasDeclaration(cxxConstructorDecl(isExplicit())), - isListInitialization(), hasDescendant(initListExpr())))) + unless(anyOf( + // Skip explicit constructor. + hasDeclaration(cxxConstructorDecl(isExplicit())), + // Skip list initialization and constructors with an initializer + // list. + isListInitialization(), hasDescendant(initListExpr()), + // Skip container `vector(size_type, const T&, ...)`. + SemanticallyDifferentContainer))) .bind("ctor"); Finder->addMatcher( diff --git a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp index 554abcd900e32..b85dde5644d31 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp @@ -67,11 +67,9 @@ AST_MATCHER_P(CallExpr, hasLastArgument, // function had parameters defined (this is useful to check if there is only one // variadic argument). AST_MATCHER(CXXMemberCallExpr, hasSameNumArgsAsDeclNumParams) { - if (Node.getMethodDecl()->isFunctionTemplateSpecialization()) - return Node.getNumArgs() == Node.getMethodDecl() - ->getPrimaryTemplate() - ->getTemplatedDecl() - ->getNumParams(); + if (const FunctionTemplateDecl *Primary = + Node.getMethodDecl()->getPrimaryTemplate()) + return Node.getNumArgs() == Primary->getTemplatedDecl()->getNumParams(); return Node.getNumArgs() == Node.getMethodDecl()->getNumParams(); } diff --git a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp index 22dc9e21cab9d..e6293ed48bfdd 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp @@ -61,7 +61,8 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { // before the typedef will be the nested one (PR#50990). Therefore, we also // keep track of the parent declaration, so that we can look up the last // TagDecl that is a sibling of the typedef in the AST. - LastTagDeclRanges[ParentDecl] = MatchedTagDecl->getSourceRange(); + if (MatchedTagDecl->isThisDeclarationADefinition()) + LastTagDeclRanges[ParentDecl] = MatchedTagDecl->getSourceRange(); return; } diff --git a/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.cpp b/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.cpp index 3c803959caf80..3313bcb39b7f3 100644 --- a/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.cpp @@ -126,12 +126,16 @@ class FunctionASTVisitor : public RecursiveASTVisitor { FunctionSizeCheck::FunctionSizeCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), - LineThreshold(Options.get("LineThreshold", -1U)), - StatementThreshold(Options.get("StatementThreshold", 800U)), - BranchThreshold(Options.get("BranchThreshold", -1U)), - ParameterThreshold(Options.get("ParameterThreshold", -1U)), - NestingThreshold(Options.get("NestingThreshold", -1U)), - VariableThreshold(Options.get("VariableThreshold", -1U)) {} + LineThreshold(Options.get("LineThreshold", DefaultLineThreshold)), + StatementThreshold( + Options.get("StatementThreshold", DefaultStatementThreshold)), + BranchThreshold(Options.get("BranchThreshold", DefaultBranchThreshold)), + ParameterThreshold( + Options.get("ParameterThreshold", DefaultParameterThreshold)), + NestingThreshold( + Options.get("NestingThreshold", DefaultNestingThreshold)), + VariableThreshold( + Options.get("VariableThreshold", DefaultVariableThreshold)) {} void FunctionSizeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "LineThreshold", LineThreshold); @@ -155,7 +159,7 @@ void FunctionSizeCheck::check(const MatchFinder::MatchResult &Result) { const auto *Func = Result.Nodes.getNodeAs("func"); FunctionASTVisitor Visitor; - Visitor.Info.NestingThreshold = NestingThreshold; + Visitor.Info.NestingThreshold = NestingThreshold.value_or(-1); Visitor.TraverseDecl(const_cast(Func)); auto &FI = Visitor.Info; @@ -173,49 +177,51 @@ void FunctionSizeCheck::check(const MatchFinder::MatchResult &Result) { unsigned ActualNumberParameters = Func->getNumParams(); - if (FI.Lines > LineThreshold || FI.Statements > StatementThreshold || - FI.Branches > BranchThreshold || - ActualNumberParameters > ParameterThreshold || - !FI.NestingThresholders.empty() || FI.Variables > VariableThreshold) { + if ((LineThreshold && FI.Lines > LineThreshold) || + (StatementThreshold && FI.Statements > StatementThreshold) || + (BranchThreshold && FI.Branches > BranchThreshold) || + (ParameterThreshold && ActualNumberParameters > ParameterThreshold) || + !FI.NestingThresholders.empty() || + (VariableThreshold && FI.Variables > VariableThreshold)) { diag(Func->getLocation(), "function %0 exceeds recommended size/complexity thresholds") << Func; } - if (FI.Lines > LineThreshold) { + if (LineThreshold && FI.Lines > LineThreshold) { diag(Func->getLocation(), "%0 lines including whitespace and comments (threshold %1)", DiagnosticIDs::Note) - << FI.Lines << LineThreshold; + << FI.Lines << LineThreshold.value(); } - if (FI.Statements > StatementThreshold) { + if (StatementThreshold && FI.Statements > StatementThreshold) { diag(Func->getLocation(), "%0 statements (threshold %1)", DiagnosticIDs::Note) - << FI.Statements << StatementThreshold; + << FI.Statements << StatementThreshold.value(); } - if (FI.Branches > BranchThreshold) { + if (BranchThreshold && FI.Branches > BranchThreshold) { diag(Func->getLocation(), "%0 branches (threshold %1)", DiagnosticIDs::Note) - << FI.Branches << BranchThreshold; + << FI.Branches << BranchThreshold.value(); } - if (ActualNumberParameters > ParameterThreshold) { + if (ParameterThreshold && ActualNumberParameters > ParameterThreshold) { diag(Func->getLocation(), "%0 parameters (threshold %1)", DiagnosticIDs::Note) - << ActualNumberParameters << ParameterThreshold; + << ActualNumberParameters << ParameterThreshold.value(); } for (const auto &CSPos : FI.NestingThresholders) { diag(CSPos, "nesting level %0 starts here (threshold %1)", DiagnosticIDs::Note) - << NestingThreshold + 1 << NestingThreshold; + << NestingThreshold.value() + 1 << NestingThreshold.value(); } - if (FI.Variables > VariableThreshold) { + if (VariableThreshold && FI.Variables > VariableThreshold) { diag(Func->getLocation(), "%0 variables (threshold %1)", DiagnosticIDs::Note) - << FI.Variables << VariableThreshold; + << FI.Variables << VariableThreshold.value(); } } diff --git a/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.h b/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.h index 5f3fb9a35dd54..106c69ff07393 100644 --- a/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.h +++ b/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.h @@ -41,12 +41,23 @@ class FunctionSizeCheck : public ClangTidyCheck { void check(const ast_matchers::MatchFinder::MatchResult &Result) override; private: - const unsigned LineThreshold; - const unsigned StatementThreshold; - const unsigned BranchThreshold; - const unsigned ParameterThreshold; - const unsigned NestingThreshold; - const unsigned VariableThreshold; + const std::optional LineThreshold; + const std::optional StatementThreshold; + const std::optional BranchThreshold; + const std::optional ParameterThreshold; + const std::optional NestingThreshold; + const std::optional VariableThreshold; + + static constexpr std::optional DefaultLineThreshold = std::nullopt; + static constexpr std::optional DefaultStatementThreshold = 800U; + static constexpr std::optional DefaultBranchThreshold = + std::nullopt; + static constexpr std::optional DefaultParameterThreshold = + std::nullopt; + static constexpr std::optional DefaultNestingThreshold = + std::nullopt; + static constexpr std::optional DefaultVariableThreshold = + std::nullopt; }; } // namespace clang::tidy::readability diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp index 4dd4a95f880ac..1dde049051785 100644 --- a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp +++ b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp @@ -142,13 +142,22 @@ ExceptionSpecAnalyzer::analyzeFunctionEST(const FunctionDecl *FuncDecl, return State::NotThrowing; case CT_Dependent: { const Expr *NoexceptExpr = FuncProto->getNoexceptExpr(); + if (!NoexceptExpr) + return State::NotThrowing; + + // We can't resolve value dependence so just return unknown + if (NoexceptExpr->isValueDependent()) + return State::Unknown; + + // Try to evaluate the expression to a boolean value bool Result = false; - return (NoexceptExpr && !NoexceptExpr->isValueDependent() && - NoexceptExpr->EvaluateAsBooleanCondition( - Result, FuncDecl->getASTContext(), true) && - Result) - ? State::NotThrowing - : State::Throwing; + if (NoexceptExpr->EvaluateAsBooleanCondition( + Result, FuncDecl->getASTContext(), true)) + return Result ? State::NotThrowing : State::Throwing; + + // The noexcept expression is not value dependent but we can't evaluate it + // as a boolean condition so we have no idea if its throwing or not + return State::Unknown; } default: return State::Throwing; diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp index 45c01634e2e38..7649e37e1f966 100644 --- a/clang-tools-extra/clangd/SemanticHighlighting.cpp +++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp @@ -715,13 +715,6 @@ class CollectExtraHighlightings return true; } - bool VisitClassScopeFunctionSpecializationDecl( - ClassScopeFunctionSpecializationDecl *D) { - if (auto *Args = D->getTemplateArgsAsWritten()) - H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc()); - return true; - } - bool VisitDeclRefExpr(DeclRefExpr *E) { H.addAngleBracketTokens(E->getLAngleLoc(), E->getRAngleLoc()); return true; @@ -752,8 +745,6 @@ class CollectExtraHighlightings } if (auto *Args = D->getTemplateSpecializationArgsAsWritten()) H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc()); - if (auto *I = D->getDependentSpecializationInfo()) - H.addAngleBracketTokens(I->getLAngleLoc(), I->getRAngleLoc()); return true; } diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 8fc28c0903418..03e5dc6f164af 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -241,6 +241,11 @@ Changes in existing checks ` check to provide fixes for ``inline`` namespaces in the same format as :program:`clang-format`. +- Improved :doc:`llvmlibc-callee-namespace + ` to support + customizable namespace. This matches the change made to implementation in + namespace. + - Improved :doc:`llvmlibc-implementation-in-namespace ` to support customizable namespace. This further allows for testing the libc when the @@ -249,14 +254,12 @@ Changes in existing checks - Improved :doc:`misc-const-correctness ` check to avoid false positive when using pointer to member function. - -- Improved :doc:`misc-include-cleaner - ` check by adding option - `DeduplicateFindings` to output one finding per symbol occurrence. - Improved :doc:`misc-include-cleaner - ` check to avoid fixes insert - same include header multiple times. + ` check by adding option + `DeduplicateFindings` to output one finding per symbol occurrence, avoid + inserting the same header multiple times, fix a bug where `IgnoreHeaders` + option won't work with verbatim/std headers. - Improved :doc:`misc-redundant-expression ` check to ignore @@ -266,6 +269,11 @@ Changes in existing checks ` to support for-loops with iterators initialized by free functions like ``begin``, ``end``, or ``size``. +- Improved :doc:`modernize-return-braced-init-list + ` check to ignore + false-positives when constructing the container with ``count`` copies of + elements with value ``value``. + - Improved :doc:`modernize-use-equals-delete ` check to ignore false-positives when special member function is actually used or implicit. @@ -279,16 +287,21 @@ Changes in existing checks fixes for reordering arguments. - Improved :doc:`modernize-use-using - ` check to fix function pointer - ``typedef`` correctly. + ` check to fix function pointer and + forward declared ``typedef`` correctly. - Improved :doc:`performance-faster-string-find ` check to properly escape single quotes. +- Improved :doc:`performance-noexcept-move-constructor + ` to better handle + conditional noexcept expressions, eliminating false-positives. + - Improved :doc:`performance-noexcept-swap ` check to enforce a stricter - match with the swap function signature, eliminating false-positives. + match with the swap function signature and better handling of condition + noexcept expressions, eliminating false-positives. - Improved :doc:`readability-braces-around-statements ` check to @@ -299,6 +312,10 @@ Changes in existing checks detect comparison between string and empty string literals and support ``length()`` method as an alternative to ``size()``. +- Improved :doc:`readability-function-size + ` check configuration to use + `none` rather than `-1` to disable some parameters. + - Improved :doc:`readability-identifier-naming ` check to issue accurate warnings when a type's forward declaration precedes its definition. diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvmlibc/callee-namespace.rst b/clang-tools-extra/docs/clang-tidy/checks/llvmlibc/callee-namespace.rst index c072dd069e747..ba742b5e1cab5 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/llvmlibc/callee-namespace.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/llvmlibc/callee-namespace.rst @@ -3,14 +3,18 @@ llvmlibc-callee-namespace ==================================== -Checks all calls resolve to functions within ``__llvm_libc`` namespace. +Checks all calls resolve to functions within correct namespace. .. code-block:: c++ - namespace __llvm_libc { + // Implementation inside the LIBC_NAMESPACE namespace. + // Correct if: + // - LIBC_NAMESPACE is a macro + // - LIBC_NAMESPACE expansion starts with `__llvm_libc` + namespace LIBC_NAMESPACE { // Allow calls with the fully qualified name. - __llvm_libc::strlen("hello"); + LIBC_NAMESPACE::strlen("hello"); // Allow calls to compiler provided functions. (void)__builtin_abs(-1); @@ -21,4 +25,4 @@ Checks all calls resolve to functions within ``__llvm_libc`` namespace. // Disallow calling into functions in the global namespace. ::strlen("!"); - } // namespace __llvm_libc + } // namespace LIBC_NAMESPACE diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/function-size.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/function-size.rst index 3360fbd5f1e63..133bd3e9c8cbe 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/function-size.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/function-size.rst @@ -12,7 +12,7 @@ Options .. option:: LineThreshold - Flag functions exceeding this number of lines. The default is `-1` (ignore + Flag functions exceeding this number of lines. The default is `none` (ignore the number of lines). .. option:: StatementThreshold @@ -24,22 +24,22 @@ Options .. option:: BranchThreshold Flag functions exceeding this number of control statements. The default is - `-1` (ignore the number of branches). + `none` (ignore the number of branches). .. option:: ParameterThreshold Flag functions that exceed a specified number of parameters. The default - is `-1` (ignore the number of parameters). + is `none` (ignore the number of parameters). .. option:: NestingThreshold Flag compound statements which create next nesting level after `NestingThreshold`. This may differ significantly from the expected value - for macro-heavy code. The default is `-1` (ignore the nesting level). + for macro-heavy code. The default is `none` (ignore the nesting level). .. option:: VariableThreshold Flag functions exceeding this number of variables declared in the body. - The default is `-1` (ignore the number of variables). + The default is `none` (ignore the number of variables). Please note that function parameters and variables declared in lambdas, GNU Statement Expressions, and nested class inline functions are not counted. diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/callee-namespace.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/callee-namespace.cpp index f18ab2b89e786..c867b92d5881c 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/callee-namespace.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/callee-namespace.cpp @@ -1,6 +1,16 @@ // RUN: %check_clang_tidy %s llvmlibc-callee-namespace %t +#define OTHER_MACRO_NAMESPACE custom_namespace +namespace OTHER_MACRO_NAMESPACE { + void wrong_name_macro_func() {} +} + namespace __llvm_libc { + void right_name_no_macro_func() {} +} + +#define LIBC_NAMESPACE __llvm_libc_xyz +namespace LIBC_NAMESPACE { namespace nested { void nested_func() {} } // namespace nested @@ -22,12 +32,12 @@ struct global_struct { int operator()() const { return 0; } }; -namespace __llvm_libc { +namespace LIBC_NAMESPACE { void Test() { // Allow calls with the fully qualified name. - __llvm_libc::libc_api_func(); - __llvm_libc::nested::nested_func(); - void (*qualifiedPtr)(void) = __llvm_libc::libc_api_func; + LIBC_NAMESPACE::libc_api_func(); + LIBC_NAMESPACE::nested::nested_func(); + void (*qualifiedPtr)(void) = LIBC_NAMESPACE::libc_api_func; qualifiedPtr(); // Should not trigger on compiler provided function calls. @@ -36,22 +46,22 @@ void Test() { // Bare calls are allowed as long as they resolve to the correct namespace. libc_api_func(); nested::nested_func(); - void (*barePtr)(void) = __llvm_libc::libc_api_func; + void (*barePtr)(void) = LIBC_NAMESPACE::libc_api_func; barePtr(); // Allow calling entities defined in the namespace. - __llvm_libc::libc_api_struct{}(); + LIBC_NAMESPACE::libc_api_struct{}(); // Disallow calling into global namespace for implemented entrypoints. ::libc_api_func(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'libc_api_func' must resolve to a function declared within the '__llvm_libc' namespace - // CHECK-MESSAGES: :15:6: note: resolves to this declaration + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'libc_api_func' must resolve to a function declared within the namespace defined by the 'LIBC_NAMESPACE' macro + // CHECK-MESSAGES: :25:6: note: resolves to this declaration // Disallow indirect references to functions in global namespace. void (*badPtr)(void) = ::libc_api_func; badPtr(); - // CHECK-MESSAGES: :[[@LINE-2]]:26: warning: 'libc_api_func' must resolve to a function declared within the '__llvm_libc' namespace - // CHECK-MESSAGES: :15:6: note: resolves to this declaration + // CHECK-MESSAGES: :[[@LINE-2]]:26: warning: 'libc_api_func' must resolve to a function declared within the namespace defined by the 'LIBC_NAMESPACE' macro + // CHECK-MESSAGES: :25:6: note: resolves to this declaration // Allow calling into global namespace for specific functions. ::malloc(); @@ -59,8 +69,18 @@ void Test() { // Disallow calling on entities that are not in the namespace, but make sure // no crashes happen. global_struct{}(); - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'operator()' must resolve to a function declared within the '__llvm_libc' namespace - // CHECK-MESSAGES: :22:7: note: resolves to this declaration + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'operator()' must resolve to a function declared within the namespace defined by the 'LIBC_NAMESPACE' macro + // CHECK-MESSAGES: :32:7: note: resolves to this declaration + + OTHER_MACRO_NAMESPACE::wrong_name_macro_func(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'wrong_name_macro_func' must resolve to a function declared within the namespace defined by the 'LIBC_NAMESPACE' macro + // CHECK-MESSAGES: :3:31: note: expanded from macro 'OTHER_MACRO_NAMESPACE' + // CHECK-MESSAGES: :5:8: note: resolves to this declaration + + __llvm_libc::right_name_no_macro_func(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'right_name_no_macro_func' must resolve to a function declared within the namespace defined by the 'LIBC_NAMESPACE' macro + // CHECK-MESSAGES: :9:8: note: resolves to this declaration + } } // namespace __llvm_libc diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/return-braced-init-list.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/return-braced-init-list.cpp index 4db1d49da2ea8..02e95e15499dc 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/return-braced-init-list.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/return-braced-init-list.cpp @@ -30,12 +30,16 @@ class initializer_list { }; template +struct allocator {}; + +template > class vector { public: - vector(T) {} - vector(std::initializer_list) {} + vector(T); + vector(size_t, T, const Allocator &alloc = Allocator()); + vector(std::initializer_list); }; -} +} // namespace std class Bar {}; @@ -98,12 +102,26 @@ Foo f6() { return Foo(b6, 1); } -std::vector f7() { +std::vector vectorWithOneParameter() { int i7 = 1; return std::vector(i7); // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type } +std::vector vectorIntWithTwoParameter() { + return std::vector(1, 2); +} + +std::vector vectorDoubleWithTwoParameter() { + return std::vector(1, 2.1); +} +struct A {}; +std::vector vectorRecordWithTwoParameter() { + A a{}; + return std::vector(1, a); +} + + Bar f8() { return {}; } diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp index f7db0af6434ac..422abee11a719 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp @@ -321,3 +321,7 @@ typedef bool (*ISSUE_65055_2)(int); // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use 'using' instead of 'typedef' // CHECK-FIXES: {{^}}using ISSUE_65055_1 = void (*)(int);{{$}} // CHECK-FIXES: {{^}}using ISSUE_65055_2 = bool (*)(int);{{$}} + +typedef class ISSUE_67529_1 *ISSUE_67529; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' +// CHECK-FIXES: using ISSUE_67529 = class ISSUE_67529_1 *; diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp index 60596c2876c0a..347a1e3220061 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp @@ -1,5 +1,14 @@ // RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t -- -- -fexceptions +namespace std +{ + template + struct is_nothrow_move_constructible + { + static constexpr bool value = __is_nothrow_constructible(T, __add_rvalue_reference(T)); + }; +} // namespace std + struct Empty {}; @@ -379,3 +388,12 @@ struct OK31 { OK31(OK31 &&) noexcept(TrueT::value) = default; OK31& operator=(OK31 &&) noexcept(TrueT::value) = default; }; + +namespace gh68101 +{ + template + class Container { + public: + Container(Container&&) noexcept(std::is_nothrow_move_constructible::value); + }; +} // namespace gh68101 diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-swap.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-swap.cpp index 392b5d17d456e..dfc71a2bb9ab3 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-swap.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-swap.cpp @@ -1,5 +1,14 @@ // RUN: %check_clang_tidy %s performance-noexcept-swap %t -- -- -fexceptions +namespace std +{ + template + struct is_nothrow_move_constructible + { + static constexpr bool value = __is_nothrow_constructible(T, __add_rvalue_reference(T)); + }; +} // namespace std + void throwing_function() noexcept(false); void noexcept_function() noexcept; @@ -54,9 +63,6 @@ struct D { // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap] }; -template -void swap(D &, D &) noexcept(D::kFalse); -// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap] void swap(D &, D &) noexcept(D::kFalse); // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap] @@ -151,9 +157,8 @@ struct OK16 { void swap(OK16 &) noexcept(kTrue); }; -// FIXME: This gives a warning, but it should be OK. -//template -//void swap(OK16 &, OK16 &) noexcept(OK16::kTrue); +template +void swap(OK16 &, OK16 &) noexcept(OK16::kTrue); template void swap(OK16 &, OK16 &) noexcept(OK16::kTrue); @@ -217,4 +222,13 @@ namespace PR64303 { friend void swap(Test&, Test&); // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: swap functions should be marked noexcept [performance-noexcept-swap] }; -} +} // namespace PR64303 + +namespace gh68101 +{ + template + class Container { + public: + void swap(Container&) noexcept(std::is_nothrow_move_constructible::value); + }; +} // namespace gh68101 diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/function-size.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/function-size.cpp index b6a79465d981c..45b2604b43d03 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/function-size.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/function-size.cpp @@ -8,6 +8,16 @@ // RUN: readability-function-size.VariableThreshold: 1 \ // RUN: }}' + +// RUN: %check_clang_tidy -check-suffixes=OPTIONAL %s readability-function-size %t -- \ +// RUN: -config='{CheckOptions: { \ +// RUN: readability-function-size.StatementThreshold: "-1", \ +// RUN: readability-function-size.BranchThreshold: "5", \ +// RUN: readability-function-size.ParameterThreshold: "none", \ +// RUN: readability-function-size.NestingThreshold: "", \ +// RUN: readability-function-size.VariableThreshold: "" \ +// RUN: }}' + // Bad formatting is intentional, don't run clang-format over the whole file! void foo1() { @@ -103,9 +113,11 @@ void baz0() { // 1 // check that nested if's are not reported. this was broken initially void nesting_if() { // 1 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'nesting_if' exceeds recommended size/complexity - // CHECK-MESSAGES: :[[@LINE-2]]:6: note: 23 lines including whitespace and comments (threshold 0) + // CHECK-MESSAGES: :[[@LINE-2]]:6: note: 25 lines including whitespace and comments (threshold 0) // CHECK-MESSAGES: :[[@LINE-3]]:6: note: 18 statements (threshold 0) // CHECK-MESSAGES: :[[@LINE-4]]:6: note: 6 branches (threshold 0) + // CHECK-MESSAGES-OPTIONAL: :[[@LINE-5]]:6: warning: function 'nesting_if' exceeds recommended size/complexity + // CHECK-MESSAGES-OPTIONAL: :[[@LINE-6]]:6: note: 6 branches (threshold 5) if (true) { // 2 int j; } else if (true) { // 2 @@ -123,7 +135,7 @@ void nesting_if() { // 1 } else if (true) { // 2 int j; } - // CHECK-MESSAGES: :[[@LINE-22]]:6: note: 6 variables (threshold 1) + // CHECK-MESSAGES: :[[@LINE-24]]:6: note: 6 variables (threshold 1) } // however this should warn diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/config-files.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/config-files.cpp index cc2dbc464e2d7..ab4f3becb7a9f 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/config-files.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/config-files.cpp @@ -55,5 +55,12 @@ // CHECK-CHILD6: Checks: {{.*-llvm-qualified-auto'? *$}} // CHECK-CHILD6-NOT: modernize-use-using.IgnoreMacros +// RUN: clang-tidy -dump-config \ +// RUN: --config='{CheckOptions: {readability-function-size.LineThreshold: ""}, \ +// RUN: Checks: readability-function-size}' \ +// RUN: %S/Inputs/config-files/4/44/- -- | FileCheck %s -check-prefix=CHECK-CHILD7 +// CHECK-CHILD7: readability-function-size.LineThreshold: none + + // Validate that check options are printed in alphabetical order: // RUN: clang-tidy --checks="-*,readability-identifier-naming" --dump-config %S/Inputs/config-files/- -- | grep "readability-identifier-naming\." | sort --check diff --git a/clang-tools-extra/unittests/clang-tidy/IncludeCleanerTest.cpp b/clang-tools-extra/unittests/clang-tidy/IncludeCleanerTest.cpp index 0c29b469b617b..8da1051a860a8 100644 --- a/clang-tools-extra/unittests/clang-tidy/IncludeCleanerTest.cpp +++ b/clang-tools-extra/unittests/clang-tidy/IncludeCleanerTest.cpp @@ -59,18 +59,20 @@ TEST(IncludeCleanerCheckTest, SuppressUnusedIncludes) { #include "foo/qux.h" #include "baz/qux/qux.h" #include +#include )"; const char *PostCode = R"( #include "bar.h" #include "foo/qux.h" #include +#include )"; std::vector Errors; ClangTidyOptions Opts; Opts.CheckOptions["IgnoreHeaders"] = llvm::StringRef{llvm::formatv( - "bar.h;{0};{1};vector", + "bar.h;{0};{1};vector;;", llvm::Regex::escape(appendPathFileSystemIndependent({"foo", "qux.h"})), llvm::Regex::escape(appendPathFileSystemIndependent({"baz", "qux"})))}; EXPECT_EQ( @@ -79,6 +81,7 @@ TEST(IncludeCleanerCheckTest, SuppressUnusedIncludes) { PreCode, &Errors, "file.cpp", std::nullopt, Opts, {{"bar.h", "#pragma once"}, {"vector", "#pragma once"}, + {"list", "#pragma once"}, {appendPathFileSystemIndependent({"foo", "qux.h"}), "#pragma once"}, {appendPathFileSystemIndependent({"baz", "qux", "qux.h"}), "#pragma once"}})); @@ -163,11 +166,13 @@ TEST(IncludeCleanerCheckTest, SuppressMissingIncludes) { int BarResult = bar(); int BazResult = baz(); int QuxResult = qux(); +int PrivResult = test(); +std::vector x; )"; ClangTidyOptions Opts; Opts.CheckOptions["IgnoreHeaders"] = llvm::StringRef{ - "baz.h;" + + "public.h;;baz.h;" + llvm::Regex::escape(appendPathFileSystemIndependent({"foo", "qux.h"}))}; std::vector Errors; EXPECT_EQ(PreCode, runCheckOnCode( @@ -175,18 +180,23 @@ int QuxResult = qux(); {{"bar.h", R"(#pragma once #include "baz.h" #include "foo/qux.h" + #include "private.h" int bar(); + namespace std { struct vector {}; } )"}, {"baz.h", R"(#pragma once int baz(); )"}, + {"private.h", R"(#pragma once + // IWYU pragma: private, include "public.h" + int test(); + )"}, {appendPathFileSystemIndependent({"foo", "qux.h"}), R"(#pragma once int qux(); )"}})); } - TEST(IncludeCleanerCheckTest, MultipleTimeMissingInclude) { const char *PreCode = R"( #include "bar.h" diff --git a/clang/cmake/caches/CrossWinToARMLinux.cmake b/clang/cmake/caches/CrossWinToARMLinux.cmake index fd341b182fd65..2a0953af53fad 100644 --- a/clang/cmake/caches/CrossWinToARMLinux.cmake +++ b/clang/cmake/caches/CrossWinToARMLinux.cmake @@ -151,6 +151,10 @@ set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS find_package(Python3 COMPONENTS Interpreter) +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_TEST_PARAMS_default "${RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_TEST_PARAMS}") +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_TEST_PARAMS_default "${RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_TEST_PARAMS}") +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_TEST_PARAMS_default "${RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_TEST_PARAMS}") + # Remote test configuration. if(DEFINED REMOTE_TEST_HOST) # Allow override with the custom values. @@ -162,11 +166,15 @@ if(DEFINED REMOTE_TEST_HOST) "\\\"${Python3_EXECUTABLE}\\\" \\\"${LLVM_PROJECT_DIR}/llvm/utils/remote-exec.py\\\" --host=${REMOTE_TEST_USER}@${REMOTE_TEST_HOST}" CACHE STRING "") - set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_TEST_PARAMS "${RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_TEST_PARAMS} 'executor=${DEFAULT_TEST_EXECUTOR}'" CACHE STRING "") - set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_TEST_PARAMS "${RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_TEST_PARAMS} 'executor=${DEFAULT_TEST_EXECUTOR}'" CACHE STRING "") - set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_TEST_PARAMS "${RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_TEST_PARAMS} 'executor=${DEFAULT_TEST_EXECUTOR}'" CACHE STRING "") + list(APPEND RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_TEST_PARAMS_default "executor=${DEFAULT_TEST_EXECUTOR}") + list(APPEND RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_TEST_PARAMS_default "executor=${DEFAULT_TEST_EXECUTOR}") + list(APPEND RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_TEST_PARAMS_default "executor=${DEFAULT_TEST_EXECUTOR}") endif() +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_TEST_PARAMS "${RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_TEST_PARAMS_default}" CACHE INTERNAL "") +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_TEST_PARAMS "${RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_TEST_PARAMS_default}" CACHE INTERNAL "") +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_TEST_PARAMS "${RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_TEST_PARAMS_default}" CACHE INTERNAL "") + set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "") set(LLVM_TOOLCHAIN_TOOLS llvm-ar diff --git a/clang/docs/AddressSanitizer.rst b/clang/docs/AddressSanitizer.rst index 37f34cb0cc993..e1997153f2037 100644 --- a/clang/docs/AddressSanitizer.rst +++ b/clang/docs/AddressSanitizer.rst @@ -26,7 +26,13 @@ Typical slowdown introduced by AddressSanitizer is **2x**. How to build ============ -Build LLVM/Clang with `CMake `_. +Build LLVM/Clang with `CMake ` and enable +the ``compiler-rt`` runtime. An example CMake configuration that will allow +for the use/testing of AddressSanitizer: + +.. code-block:: console + + $ cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang" -DLLVM_ENABLE_RUNTIMES="compiler-rt" /llvm Usage ===== diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 5ebb8c82b3049..c5c72c68ee9b8 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -5730,7 +5730,7 @@ Examples ======== A style similar to the `Linux Kernel style -`_: +`_: .. code-block:: yaml diff --git a/clang/docs/ClangOffloadBundler.rst b/clang/docs/ClangOffloadBundler.rst index d08bf4b97781f..1e21d3e7264d5 100644 --- a/clang/docs/ClangOffloadBundler.rst +++ b/clang/docs/ClangOffloadBundler.rst @@ -309,3 +309,30 @@ target by comparing bundle ID's. Two bundle ID's are considered compatible if: * Their offload kind are the same * Their target triple are the same * Their GPUArch are the same + +Compression and Decompression +============================= + +``clang-offload-bundler`` provides features to compress and decompress the full +bundle, leveraging inherent redundancies within the bundle entries. Use the +`-compress` command-line option to enable this compression capability. + +The compressed offload bundle begins with a header followed by the compressed binary data: + +- **Magic Number (4 bytes)**: + This is a unique identifier to distinguish compressed offload bundles. The value is the string 'CCOB' (Compressed Clang Offload Bundle). + +- **Version Number (16-bit unsigned int)**: + This denotes the version of the compressed offload bundle format. The current version is `1`. + +- **Compression Method (16-bit unsigned int)**: + This field indicates the compression method used. The value corresponds to either `zlib` or `zstd`, represented as a 16-bit unsigned integer cast from the LLVM compression enumeration. + +- **Uncompressed Binary Size (32-bit unsigned int)**: + This is the size (in bytes) of the binary data before it was compressed. + +- **Hash (64-bit unsigned int)**: + This is a 64-bit truncated MD5 hash of the uncompressed binary data. It serves for verification and caching purposes. + +- **Compressed Data**: + The actual compressed binary data follows the header. Its size can be inferred from the total size of the file minus the header size. diff --git a/clang/docs/CommandGuide/clang.rst b/clang/docs/CommandGuide/clang.rst index 139c8f25137d3..e1c872cdc5539 100644 --- a/clang/docs/CommandGuide/clang.rst +++ b/clang/docs/CommandGuide/clang.rst @@ -684,6 +684,21 @@ Preprocessor Options Do not search clang's builtin directory for include files. +.. option:: -fkeep-system-includes + + Usable only with :option:`-E`. Do not copy the preprocessed content of + "system" headers to the output; instead, preserve the #include directive. + This can greatly reduce the volume of text produced by :option:`-E` which + can be helpful when trying to produce a "small" reproduceable test case. + + This option does not guarantee reproduceability, however. If the including + source defines preprocessor symbols that influence the behavior of system + headers (for example, ``_XOPEN_SOURCE``) the operation of :option:`-E` will + remove that definition and thus can change the semantics of the included + header. Also, using a different version of the system headers (especially a + different version of the STL) may result in different behavior. Always verify + the preprocessed file by compiling it separately. + ENVIRONMENT ----------- diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 65bd5c8300ea3..9c320bc8b35d2 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -45,6 +45,24 @@ C/C++ Language Potentially Breaking Changes -xc++-header``) is now ``.pch`` instead of ``.gch``. - ``-include a.h`` probing ``a.h.gch`` is deprecated. Change the extension name to ``.pch`` or use ``-include-pch a.h.gch``. +- Fixed a bug that caused ``__has_cpp_attribute`` and ``__has_c_attribute`` + return incorrect values for some C++-11-style attributes. Below is a complete + list of behavior changes. + + .. csv-table:: + :header: Test, Old value, New value + + ``__has_cpp_attribute(unused)``, 201603, 0 + ``__has_cpp_attribute(gnu::unused)``, 201603, 1 + ``__has_c_attribute(unused)``, 202106, 0 + ``__has_cpp_attribute(clang::fallthrough)``, 201603, 1 + ``__has_cpp_attribute(gnu::fallthrough)``, 201603, 1 + ``__has_c_attribute(gnu::fallthrough)``, 201910, 1 + ``__has_cpp_attribute(warn_unused_result)``, 201907, 0 + ``__has_cpp_attribute(clang::warn_unused_result)``, 201907, 1 + ``__has_cpp_attribute(gnu::warn_unused_result)``, 201907, 1 + ``__has_c_attribute(warn_unused_result)``, 202003, 0 + ``__has_c_attribute(gnu::warn_unused_result)``, 202003, 1 C++ Specific Potentially Breaking Changes ----------------------------------------- @@ -71,6 +89,13 @@ C++ Specific Potentially Breaking Changes (`#49884 `_), and (`#61273 `_) +- The `ClassScopeFunctionSpecializationDecl` AST node has been removed. + Dependent class scope explicit function template specializations now use + `DependentFunctionTemplateSpecializationInfo` to store candidate primary + templates and explicit template arguments. This should not impact users of + Clang as a compiler, but it may break assumptions in Clang-based tools + iterating over the AST. + ABI Changes in This Version --------------------------- - Following the SystemV ABI for x86-64, ``__int128`` arguments will no longer @@ -140,6 +165,7 @@ C23 Feature Support previous placeholder value. Clang continues to accept ``-std=c2x`` and ``-std=gnu2x`` as aliases for C23 and GNU C23, respectively. - Clang now supports `requires c23` for module maps. +- Clang now supports ``N3007 Type inference for object definitions``. Non-comprehensive list of changes in this release ------------------------------------------------- @@ -147,6 +173,18 @@ Non-comprehensive list of changes in this release New Compiler Flags ------------------ +* ``-fverify-intermediate-code`` and its complement ``-fno-verify-intermediate-code``. + Enables or disables verification of the generated LLVM IR. + Users can pass this to turn on extra verification to catch certain types of + compiler bugs at the cost of extra compile time. + Since enabling the verifier adds a non-trivial cost of a few percent impact on + build times, it's disabled by default, unless your LLVM distribution itself is + compiled with runtime checks enabled. +* ``-fkeep-system-includes`` modifies the behavior of the ``-E`` option, + preserving ``#include`` directives for "system" headers instead of copying + the preprocessed text to the output. This can greatly reduce the size of the + preprocessed output, which can be helpful when trying to reduce a test case. + Deprecated Compiler Flags ------------------------- @@ -155,6 +193,9 @@ Modified Compiler Flags * ``-Woverriding-t-option`` is renamed to ``-Woverriding-option``. * ``-Winterrupt-service-routine`` is renamed to ``-Wexcessive-regsave`` as a generalization +* ``-frewrite-includes`` now guards the original #include directives with + ``__CLANG_REWRITTEN_INCLUDES``, and ``__CLANG_REWRITTEN_SYSTEM_INCLUDES`` as + appropriate. Removed Compiler Flags ------------------------- @@ -257,6 +298,8 @@ Improvements to Clang's diagnostics source:1:24: note: expression evaluates to ''\n' (0x0A, 10) == U'🌍' (0x1F30D, 127757)' 1 | static_assert("A\n"[1] == U'🌍'); | ~~~~~~~~~^~~~~~~~ +- Clang now always diagnoses when using non-standard layout types in ``offsetof`` . + (`#64619: `_) Bug Fixes in This Version ------------------------- @@ -327,6 +370,13 @@ Bug Fixes in This Version (`#64462 `_) - Fixes a regression where the ``UserDefinedLiteral`` was not properly preserved while evaluating consteval functions. (`#63898 `_). +- Fix a crash when evaluating value-dependent structured binding + variables at compile time. + Fixes (`#67690 `_) +- Fixes a ``clang-17`` regression where ``LLVM_UNREACHABLE_OPTIMIZE=OFF`` + cannot be used with ``Release`` mode builds. (`#68237 `_). +- Fix crash in evaluating ``constexpr`` value for invalid template function. + Fixes (`#68542 `_) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -419,6 +469,9 @@ Bug Fixes to C++ Support - Fix crash caused by a spaceship operator returning a comparision category by reference. Fixes: (`#64162 `_) +- Fix a crash when calling a consteval function in an expression used as + the size of an array. + (`#65520 `_) - Clang no longer tries to capture non-odr-used variables that appear in the enclosing expression of a lambda expression with a noexcept specifier. @@ -435,6 +488,11 @@ Bug Fixes to C++ Support we now produce a diagnostic. Fixes: (`#65522 `_) +- Fixed a bug where clang incorrectly considered implicitly generated deduction + guides from a non-templated constructor and a templated constructor as ambiguous, + rather than prefer the non-templated constructor as specified in + [standard.group]p3. + Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed an import failure of recursive friend class template. @@ -594,11 +652,11 @@ Static Analyzer - A few crashes have been found and fixed using randomized testing related to the use of ``_BitInt()`` in tidy checks and in clang analysis. See - `#67212 `_, - `#66782 `_, - `#65889 `_, - `#65888 `_, and - `#65887 `_ + `#67212 `_, + `#66782 `_, + `#65889 `_, + `#65888 `_, and + `#65887 `_ .. _release-notes-sanitizers: diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 25bbd72c81f7a..edc2bce6a964d 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -4383,6 +4383,7 @@ Execute ``clang-cl /?`` to see a list of supported options: -fno-sanitize-trap= Disable trapping for specified sanitizers -fno-standalone-debug Limit debug information produced to reduce size of debug binary + -fno-strict-aliasing Disable optimizations based on strict aliasing rules (default) -fobjc-runtime= Specify the target Objective-C runtime kind and version -fprofile-exclude-files= Instrument only functions from files where names don't match all the regexes separated by a semi-colon @@ -4444,6 +4445,7 @@ Execute ``clang-cl /?`` to see a list of supported options: behavior. See user manual for available checks -fsplit-lto-unit Enables splitting of the LTO unit. -fstandalone-debug Emit full debug info for all types used by the program + -fstrict-aliasing Enable optimizations based on strict aliasing rules -fsyntax-only Run the preprocessor, parser and semantic analysis stages -fwhole-program-vtables Enables whole-program vtable optimization. Requires -flto -gcodeview-ghash Emit type record hashes in a .debug$H section @@ -4722,3 +4724,16 @@ The Visual C++ Toolset has a slightly more elaborate mechanism for detection. The registry information is used to help locate the installation as a final fallback. This is only possible for pre-VS2017 installations and is considered deprecated. + +Restrictions and Limitations compared to Clang +---------------------------------------------- + +Strict Aliasing +^^^^^^^^^^^^^^^ + +Strict aliasing (TBAA) is always off by default in clang-cl. Whereas in clang, +strict aliasing is turned on by default for all optimization levels. + +To enable LLVM optimizations based on strict aliasing rules (e.g., optimizations +based on type of expressions in C/C++), user will need to explicitly pass +`-fstrict-aliasing` to clang-cl. diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 1151a756ff377..cc8dab97f8b01 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -426,8 +426,12 @@ class ASTNodeTraverser } void VisitFunctionDecl(const FunctionDecl *D) { - if (const auto *FTSI = D->getTemplateSpecializationInfo()) + if (FunctionTemplateSpecializationInfo *FTSI = + D->getTemplateSpecializationInfo()) dumpTemplateArgumentList(*FTSI->TemplateArguments); + else if (DependentFunctionTemplateSpecializationInfo *DFTSI = + D->getDependentSpecializationInfo()) + dumpASTTemplateArgumentListInfo(DFTSI->TemplateArgumentsAsWritten); if (D->param_begin()) for (const auto *Parameter : D->parameters()) @@ -578,11 +582,6 @@ class ASTNodeTraverser dumpTemplateParameters(D->getTemplateParameters()); } - void VisitClassScopeFunctionSpecializationDecl( - const ClassScopeFunctionSpecializationDecl *D) { - Visit(D->getSpecialization()); - dumpASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten()); - } void VisitVarTemplateDecl(const VarTemplateDecl *D) { dumpTemplateDecl(D); } void VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) { diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 3b1e3abd5faa4..02e30e24c8be4 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -2845,9 +2845,7 @@ class FunctionDecl : public DeclaratorDecl, /// Determine whether this function is a function template /// specialization. - bool isFunctionTemplateSpecialization() const { - return getPrimaryTemplate() != nullptr; - } + bool isFunctionTemplateSpecialization() const; /// If this function is actually a function template specialization, /// retrieve information about this function template specialization. @@ -2930,9 +2928,9 @@ class FunctionDecl : public DeclaratorDecl, /// Specifies that this function declaration is actually a /// dependent function template specialization. - void setDependentTemplateSpecialization(ASTContext &Context, - const UnresolvedSetImpl &Templates, - const TemplateArgumentListInfo &TemplateArgs); + void setDependentTemplateSpecialization( + ASTContext &Context, const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo *TemplateArgs); DependentFunctionTemplateSpecializationInfo * getDependentSpecializationInfo() const; diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 6264f15d6ffb9..54d28227a4ae9 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -583,7 +583,7 @@ class FunctionTemplateSpecializationInfo final /// \code /// template struct A { /// template void f(); - /// template<> void f(); // ClassScopeFunctionSpecializationDecl + /// template<> void f(); /// }; /// \endcode /// @@ -682,82 +682,48 @@ class MemberSpecializationInfo { /// Provides information about a dependent function-template /// specialization declaration. /// -/// Since explicit function template specialization and instantiation -/// declarations can only appear in namespace scope, and you can only -/// specialize a member of a fully-specialized class, the only way to -/// get one of these is in a friend declaration like the following: +/// This is used for function templates explicit specializations declared +/// within class templates: +/// +/// \code +/// template struct A { +/// template void f(); +/// template<> void f(); // DependentFunctionTemplateSpecializationInfo +/// }; +/// \endcode +/// +/// As well as dependent friend declarations naming function template +/// specializations declared within class templates: /// /// \code /// template \ void foo(T); /// template \ class A { -/// friend void foo<>(T); +/// friend void foo<>(T); // DependentFunctionTemplateSpecializationInfo /// }; /// \endcode class DependentFunctionTemplateSpecializationInfo final : private llvm::TrailingObjects { - /// The number of potential template candidates. - unsigned NumTemplates; - - /// The number of template arguments. - unsigned NumArgs; - - /// The locations of the left and right angle brackets. - SourceRange AngleLocs; + friend TrailingObjects; - size_t numTrailingObjects(OverloadToken) const { - return NumArgs; - } - size_t numTrailingObjects(OverloadToken) const { - return NumTemplates; - } + /// The number of candidates for the primary template. + unsigned NumCandidates; DependentFunctionTemplateSpecializationInfo( - const UnresolvedSetImpl &Templates, - const TemplateArgumentListInfo &TemplateArgs); + const UnresolvedSetImpl &Candidates, + const ASTTemplateArgumentListInfo *TemplateArgsWritten); public: - friend TrailingObjects; + /// The template arguments as written in the sources, if provided. + const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten; static DependentFunctionTemplateSpecializationInfo * - Create(ASTContext &Context, const UnresolvedSetImpl &Templates, - const TemplateArgumentListInfo &TemplateArgs); - - /// Returns the number of function templates that this might - /// be a specialization of. - unsigned getNumTemplates() const { return NumTemplates; } + Create(ASTContext &Context, const UnresolvedSetImpl &Candidates, + const TemplateArgumentListInfo *TemplateArgs); - /// Returns the i'th template candidate. - FunctionTemplateDecl *getTemplate(unsigned I) const { - assert(I < getNumTemplates() && "template index out of range"); - return getTrailingObjects()[I]; - } - - /// Returns the explicit template arguments that were given. - const TemplateArgumentLoc *getTemplateArgs() const { - return getTrailingObjects(); - } - - /// Returns the number of explicit template arguments that were given. - unsigned getNumTemplateArgs() const { return NumArgs; } - - llvm::ArrayRef arguments() const { - return llvm::ArrayRef(getTemplateArgs(), getNumTemplateArgs()); - } - - /// Returns the nth template argument. - const TemplateArgumentLoc &getTemplateArg(unsigned I) const { - assert(I < getNumTemplateArgs() && "template arg index out of range"); - return getTemplateArgs()[I]; - } - - SourceLocation getLAngleLoc() const { - return AngleLocs.getBegin(); - } - - SourceLocation getRAngleLoc() const { - return AngleLocs.getEnd(); + /// Returns the candidates for the primary function template. + ArrayRef getCandidates() const { + return {getTrailingObjects(), NumCandidates}; } }; @@ -2613,70 +2579,6 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl { static bool classofKind(Kind K) { return K == TypeAliasTemplate; } }; -/// Declaration of a function specialization at template class scope. -/// -/// For example: -/// \code -/// template -/// class A { -/// template void foo(U a) { } -/// template<> void foo(int a) { } -/// } -/// \endcode -/// -/// "template<> foo(int a)" will be saved in Specialization as a normal -/// CXXMethodDecl. Then during an instantiation of class A, it will be -/// transformed into an actual function specialization. -/// -/// FIXME: This is redundant; we could store the same information directly on -/// the CXXMethodDecl as a DependentFunctionTemplateSpecializationInfo. -class ClassScopeFunctionSpecializationDecl : public Decl { - CXXMethodDecl *Specialization; - const ASTTemplateArgumentListInfo *TemplateArgs; - - ClassScopeFunctionSpecializationDecl( - DeclContext *DC, SourceLocation Loc, CXXMethodDecl *FD, - const ASTTemplateArgumentListInfo *TemplArgs) - : Decl(Decl::ClassScopeFunctionSpecialization, DC, Loc), - Specialization(FD), TemplateArgs(TemplArgs) {} - - ClassScopeFunctionSpecializationDecl(EmptyShell Empty) - : Decl(Decl::ClassScopeFunctionSpecialization, Empty) {} - - virtual void anchor(); - -public: - friend class ASTDeclReader; - friend class ASTDeclWriter; - - CXXMethodDecl *getSpecialization() const { return Specialization; } - bool hasExplicitTemplateArgs() const { return TemplateArgs; } - const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { - return TemplateArgs; - } - - static ClassScopeFunctionSpecializationDecl * - Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, CXXMethodDecl *FD, - bool HasExplicitTemplateArgs, - const TemplateArgumentListInfo &TemplateArgs) { - return new (C, DC) ClassScopeFunctionSpecializationDecl( - DC, Loc, FD, - HasExplicitTemplateArgs - ? ASTTemplateArgumentListInfo::Create(C, TemplateArgs) - : nullptr); - } - - static ClassScopeFunctionSpecializationDecl * - CreateDeserialized(ASTContext &Context, unsigned ID); - - // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { return classofKind(D->getKind()); } - - static bool classofKind(Kind K) { - return K == Decl::ClassScopeFunctionSpecialization; - } -}; - /// Represents a variable template specialization, which refers to /// a variable template with a given set of template arguments. /// diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 31ae3d42e232f..eeeca1998f9fa 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -9220,6 +9220,27 @@ class OMPXAttributeClause } }; +/// This represents 'ompx_bare' clause in the '#pragma omp target teams ...' +/// directive. +/// +/// \code +/// #pragma omp target teams ompx_bare +/// \endcode +/// In this example directive '#pragma omp target teams' has a 'ompx_bare' +/// clause. +class OMPXBareClause : public OMPNoChildClause { +public: + /// Build 'ompx_bare' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + OMPXBareClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPNoChildClause(StartLoc, EndLoc) {} + + /// Build an empty clause. + OMPXBareClause() = default; +}; + } // namespace clang #endif // LLVM_CLANG_AST_OPENMPCLAUSE_H diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index d4146d52893ff..3dd23eb38eeab 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1563,16 +1563,6 @@ DEF_TRAVERSE_DECL(FriendTemplateDecl, { } }) -DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, { - TRY_TO(TraverseDecl(D->getSpecialization())); - - if (D->hasExplicitTemplateArgs()) { - TRY_TO(TraverseTemplateArgumentLocsHelper( - D->getTemplateArgsAsWritten()->getTemplateArgs(), - D->getTemplateArgsAsWritten()->NumTemplateArgs)); - } -}) - DEF_TRAVERSE_DECL(LinkageSpecDecl, {}) DEF_TRAVERSE_DECL(ExportDecl, {}) @@ -2154,6 +2144,13 @@ bool RecursiveASTVisitor::TraverseFunctionHelper(FunctionDecl *D) { TALI->NumTemplateArgs)); } } + } else if (const DependentFunctionTemplateSpecializationInfo *DFSI = + D->getDependentSpecializationInfo()) { + if (const ASTTemplateArgumentListInfo *TALI = + DFSI->TemplateArgumentsAsWritten) { + TRY_TO(TraverseTemplateArgumentLocsHelper(TALI->getTemplateArgs(), + TALI->NumTemplateArgs)); + } } // Visit the function type itself, which can be either @@ -3890,6 +3887,11 @@ bool RecursiveASTVisitor::VisitOMPXAttributeClause( return true; } +template +bool RecursiveASTVisitor::VisitOMPXBareClause(OMPXBareClause *C) { + return true; +} + // FIXME: look at the following tricky-seeming exprs to see if we // need to recurse on anything. These are ones that have methods // returning decls or qualtypes or nestednamespecifier -- though I'm diff --git a/clang/include/clang/Basic/BuiltinsX86.def b/clang/include/clang/Basic/BuiltinsX86.def index 6bbbc4bbdd75c..e4802f8ab1c15 100644 --- a/clang/include/clang/Basic/BuiltinsX86.def +++ b/clang/include/clang/Basic/BuiltinsX86.def @@ -233,8 +233,6 @@ TARGET_BUILTIN(__builtin_ia32_minps, "V4fV4fV4f", "ncV:128:", "sse") TARGET_BUILTIN(__builtin_ia32_maxps, "V4fV4fV4f", "ncV:128:", "sse") TARGET_BUILTIN(__builtin_ia32_minss, "V4fV4fV4f", "ncV:128:", "sse") TARGET_BUILTIN(__builtin_ia32_maxss, "V4fV4fV4f", "ncV:128:", "sse") -TARGET_BUILTIN(__builtin_ia32_cmpps, "V4fV4fV4fIc", "ncV:128:", "sse") -TARGET_BUILTIN(__builtin_ia32_cmpss, "V4fV4fV4fIc", "ncV:128:", "sse") TARGET_BUILTIN(__builtin_ia32_cmpeqpd, "V2dV2dV2d", "ncV:128:", "sse2") TARGET_BUILTIN(__builtin_ia32_cmpltpd, "V2dV2dV2d", "ncV:128:", "sse2") @@ -252,8 +250,6 @@ TARGET_BUILTIN(__builtin_ia32_cmpneqsd, "V2dV2dV2d", "ncV:128:", "sse2") TARGET_BUILTIN(__builtin_ia32_cmpnltsd, "V2dV2dV2d", "ncV:128:", "sse2") TARGET_BUILTIN(__builtin_ia32_cmpnlesd, "V2dV2dV2d", "ncV:128:", "sse2") TARGET_BUILTIN(__builtin_ia32_cmpordsd, "V2dV2dV2d", "ncV:128:", "sse2") -TARGET_BUILTIN(__builtin_ia32_cmpsd, "V2dV2dV2dIc", "ncV:128:", "sse2") -TARGET_BUILTIN(__builtin_ia32_cmppd, "V2dV2dV2dIc", "ncV:128:", "sse2") TARGET_BUILTIN(__builtin_ia32_minpd, "V2dV2dV2d", "ncV:128:", "sse2") TARGET_BUILTIN(__builtin_ia32_maxpd, "V2dV2dV2d", "ncV:128:", "sse2") TARGET_BUILTIN(__builtin_ia32_minsd, "V2dV2dV2d", "ncV:128:", "sse2") @@ -473,8 +469,12 @@ TARGET_BUILTIN(__builtin_ia32_blendvps256, "V8fV8fV8fV8f", "ncV:256:", "avx") TARGET_BUILTIN(__builtin_ia32_shufpd256, "V4dV4dV4dIi", "ncV:256:", "avx") TARGET_BUILTIN(__builtin_ia32_shufps256, "V8fV8fV8fIi", "ncV:256:", "avx") TARGET_BUILTIN(__builtin_ia32_dpps256, "V8fV8fV8fIc", "ncV:256:", "avx") +TARGET_BUILTIN(__builtin_ia32_cmppd, "V2dV2dV2dIc", "ncV:128:", "avx") TARGET_BUILTIN(__builtin_ia32_cmppd256, "V4dV4dV4dIc", "ncV:256:", "avx") +TARGET_BUILTIN(__builtin_ia32_cmpps, "V4fV4fV4fIc", "ncV:128:", "avx") TARGET_BUILTIN(__builtin_ia32_cmpps256, "V8fV8fV8fIc", "ncV:256:", "avx") +TARGET_BUILTIN(__builtin_ia32_cmpsd, "V2dV2dV2dIc", "ncV:128:", "avx") +TARGET_BUILTIN(__builtin_ia32_cmpss, "V4fV4fV4fIc", "ncV:128:", "avx") TARGET_BUILTIN(__builtin_ia32_vextractf128_pd256, "V2dV4dIi", "ncV:256:", "avx") TARGET_BUILTIN(__builtin_ia32_vextractf128_ps256, "V4fV8fIi", "ncV:256:", "avx") TARGET_BUILTIN(__builtin_ia32_vextractf128_si256, "V4iV8iIi", "ncV:256:", "avx") diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index 5e726c1bdf8fa..8b1f415dd5fe2 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -102,7 +102,6 @@ def FriendTemplate : DeclNode; def StaticAssert : DeclNode; def Block : DeclNode, DeclContext; def Captured : DeclNode, DeclContext; -def ClassScopeFunctionSpecialization : DeclNode; def Import : DeclNode; def OMPThreadPrivate : DeclNode; def OMPAllocate : DeclNode; diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 91a95def4f80d..9c00fa50bb955 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -182,8 +182,8 @@ def err_drv_invalid_Xopenmp_target_with_args : Error< "invalid -Xopenmp-target argument: '%0', options requiring arguments are unsupported">; def err_drv_argument_only_allowed_with : Error< "invalid argument '%0' only allowed with '%1'">; -def err_drv_minws_unsupported_input_type : Error< - "'-fminimize-whitespace' invalid for input of type %0">; +def err_drv_opt_unsupported_input_type : Error< + "'%0' invalid for input of type %1">; def err_drv_amdgpu_ieee_without_no_honor_nans : Error< "invalid argument '-mno-amdgpu-ieee' only allowed with relaxed NaN handling">; def err_drv_argument_not_allowed_with : Error< diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 178761bdcf4d5..43a5f000eda6c 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1360,6 +1360,8 @@ def warn_clause_expected_string : Warning< "expected string literal in 'clause %0' - ignoring">, InGroup; def err_omp_unexpected_clause : Error< "unexpected OpenMP clause '%0' in directive '#pragma omp %1'">; +def err_omp_unexpected_clause_extension_only : Error< + "OpenMP clause '%0' is only available as extension, use '-fopenmp-extensions'">; def err_omp_immediate_directive : Error< "'#pragma omp %0' %select{|with '%2' clause }1cannot be an immediate substatement">; def err_omp_expected_identifier_for_critical : Error< @@ -1452,6 +1454,8 @@ def warn_unknown_declare_variant_isa_trait "spelling or consider restricting the context selector with the " "'arch' selector further">, InGroup; +def note_ompx_bare_clause : Note< + "OpenMP extension clause '%0' only allowed with '#pragma omp %1'">; def note_omp_declare_variant_ctx_options : Note<"context %select{set|selector|property}0 options are: %1">; def warn_omp_declare_variant_expected diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e2eaeb885e2ea..c1a6e3831127e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -240,6 +240,10 @@ def ext_imaginary_constant : Extension< "imaginary constants are a GNU extension">, InGroup; def ext_integer_complex : Extension< "complex integer types are a GNU extension">, InGroup; +def ext_c23_auto_non_plain_identifier : Extension< + "type inference of a declaration other than a plain identifier with optional " + "trailing attributes is a Clang extension">, + InGroup>; def err_invalid_saturation_spec : Error<"'_Sat' specifier is only valid on " "'_Fract' or '_Accum', not '%0'">; @@ -2388,7 +2392,8 @@ def err_auto_not_allowed : Error< "|in conversion function type|here|in lambda parameter" "|in type allocated by 'new'|in K&R-style function parameter" "|in template parameter|in friend declaration|in function prototype that is " - "not a function declaration|in requires expression parameter}1">; + "not a function declaration|in requires expression parameter" + "|in array declaration}1">; def err_dependent_deduced_tst : Error< "typename specifier refers to " "%select{class template|function template|variable template|alias template|" @@ -2461,7 +2466,8 @@ def err_implied_std_initializer_list_not_found : Error< def err_malformed_std_initializer_list : Error< "std::initializer_list must be a class template with a single type parameter">; def err_auto_init_list_from_c : Error< - "cannot use __auto_type with initializer list in C">; + "cannot use %select{'auto'||'__auto_type'}0 with " + "%select{initializer list|array}1 in C">; def err_auto_bitfield : Error< "cannot pass bit-field as __auto_type initializer in C">; @@ -5226,11 +5232,11 @@ def err_explicit_specialization_inconsistent_storage_class : Error< "'%select{none|extern|static|__private_extern__|auto|register}0'">; def err_dependent_function_template_spec_no_match : Error< "no candidate function template was found for dependent" - " friend function template specialization">; + " %select{member|friend}0 function template specialization">; def note_dependent_function_template_spec_discard_reason : Note< - "candidate ignored: %select{not a function template" - "|not a member of the enclosing namespace;" - " did you mean to explicitly qualify the specialization?}0">; + "candidate ignored: %select{not a function template|" + "not a member of the enclosing %select{class template|" + "namespace; did you mean to explicitly qualify the specialization?}1}0">; // C++ class template specializations and out-of-line definitions def err_template_spec_needs_header : Error< @@ -6649,8 +6655,8 @@ def err_func_def_incomplete_result : Error< def err_atomic_specifier_bad_type : Error<"_Atomic cannot be applied to " "%select{incomplete |array |function |reference |atomic |qualified " - "|sizeless ||integer }0type " - "%1 %select{|||||||which is not trivially copyable|}0">; + "|sizeless ||integer |}0type " + "%1 %select{|||||||which is not trivially copyable||in C23}0">; def warn_atomic_member_access : Warning< "accessing a member of an atomic structure or union is undefined behavior">, InGroup>, DefaultError; diff --git a/clang/include/clang/Basic/ObjCRuntime.h b/clang/include/clang/Basic/ObjCRuntime.h index 0f714ed3ad603..500b2462f0077 100644 --- a/clang/include/clang/Basic/ObjCRuntime.h +++ b/clang/include/clang/Basic/ObjCRuntime.h @@ -482,8 +482,8 @@ class ObjCRuntime { return llvm::hash_combine(OCR.getKind(), OCR.getVersion()); } - template - friend void addHash(llvm::HashBuilderImpl &HBuilder, + template + friend void addHash(llvm::HashBuilder &HBuilder, const ObjCRuntime &OCR) { HBuilder.add(OCR.getKind(), OCR.getVersion()); } diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index 4659e45c78834..c890242269b33 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -77,8 +77,8 @@ class SanitizerMask { llvm::hash_code hash_value() const; - template - friend void addHash(llvm::HashBuilderImpl &HBuilder, + template + friend void addHash(llvm::HashBuilder &HBuilder, const SanitizerMask &SM) { HBuilder.addRange(&SM.maskLoToHigh[0], &SM.maskLoToHigh[kNumElem]); } @@ -170,6 +170,8 @@ struct SanitizerSet { Mask = Value ? (Mask | K) : (Mask & ~K); } + void set(SanitizerMask K) { Mask = K; } + /// Disable the sanitizers specified in \p K. void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; } diff --git a/clang/include/clang/Basic/SourceLocation.h b/clang/include/clang/Basic/SourceLocation.h index ad0682511f97d..00b1e0fa855b7 100644 --- a/clang/include/clang/Basic/SourceLocation.h +++ b/clang/include/clang/Basic/SourceLocation.h @@ -59,6 +59,7 @@ class FileID { friend class ASTWriter; friend class ASTReader; friend class SourceManager; + friend class SourceManagerTestHelper; static FileID get(int V) { FileID F; diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h index 08a69e08405df..420fda111ad13 100644 --- a/clang/include/clang/Basic/SourceManager.h +++ b/clang/include/clang/Basic/SourceManager.h @@ -500,6 +500,14 @@ class SLocEntry { return Expansion; } + /// Creates an incomplete SLocEntry that is only able to report its offset. + static SLocEntry getOffsetOnly(SourceLocation::UIntTy Offset) { + assert(!(Offset & (1ULL << OffsetBits)) && "Offset is too large"); + SLocEntry E; + E.Offset = Offset; + return E; + } + static SLocEntry get(SourceLocation::UIntTy Offset, const FileInfo &FI) { assert(!(Offset & (1ULL << OffsetBits)) && "Offset is too large"); SLocEntry E; @@ -534,6 +542,12 @@ class ExternalSLocEntrySource { /// entry from being loaded. virtual bool ReadSLocEntry(int ID) = 0; + /// Get the index ID for the loaded SourceLocation offset. + /// + /// \returns Invalid index ID (0) if an error occurred that prevented the + /// SLocEntry from being loaded. + virtual int getSLocEntryID(SourceLocation::UIntTy SLocOffset) = 0; + /// Retrieve the module import location and name for the given ID, if /// in fact it was loaded from a module (rather than, say, a precompiled /// header). @@ -702,6 +716,11 @@ class SourceManager : public RefCountedBase { /// use (-ID - 2). llvm::PagedVector LoadedSLocEntryTable; + /// For each allocation in LoadedSLocEntryTable, we keep the first FileID. + /// We assume exactly one allocation per AST file, and use that to determine + /// whether two FileIDs come from the same AST file. + SmallVector LoadedSLocEntryAllocBegin; + /// The starting offset of the next local SLocEntry. /// /// This is LocalSLocEntryTable.back().Offset + the size of that entry. @@ -724,6 +743,12 @@ class SourceManager : public RefCountedBase { /// Same indexing as LoadedSLocEntryTable. llvm::BitVector SLocEntryLoaded; + /// A bitmap that indicates whether the entries of LoadedSLocEntryTable + /// have already had their offset loaded from the external source. + /// + /// Superset of SLocEntryLoaded. Same indexing as SLocEntryLoaded. + llvm::BitVector SLocEntryOffsetLoaded; + /// An external source for source location entries. ExternalSLocEntrySource *ExternalSLocEntries = nullptr; @@ -1639,6 +1664,11 @@ class SourceManager : public RefCountedBase { isInTheSameTranslationUnit(std::pair &LOffs, std::pair &ROffs) const; + /// Determines whether the two decomposed source location is in the same TU. + bool isInTheSameTranslationUnitImpl( + const std::pair &LOffs, + const std::pair &ROffs) const; + /// Determines the order of 2 source locations in the "source location /// address space". bool isBeforeInSLocAddrSpace(SourceLocation LHS, SourceLocation RHS) const { diff --git a/clang/include/clang/Driver/OffloadBundler.h b/clang/include/clang/Driver/OffloadBundler.h index 28473c53662de..17df31d31071d 100644 --- a/clang/include/clang/Driver/OffloadBundler.h +++ b/clang/include/clang/Driver/OffloadBundler.h @@ -19,6 +19,7 @@ #include "llvm/Support/Error.h" #include "llvm/TargetParser/Triple.h" +#include #include #include @@ -26,11 +27,15 @@ namespace clang { class OffloadBundlerConfig { public: + OffloadBundlerConfig(); + bool AllowNoHost = false; bool AllowMissingBundles = false; bool CheckInputArchive = false; bool PrintExternalCommands = false; bool HipOpenmpCompatible = false; + bool Compress = false; + bool Verbose = false; unsigned BundleAlignment = 1; unsigned HostInputIndex = ~0u; @@ -84,6 +89,38 @@ struct OffloadTargetInfo { std::string str() const; }; +// CompressedOffloadBundle represents the format for the compressed offload +// bundles. +// +// The format is as follows: +// - Magic Number (4 bytes) - A constant "CCOB". +// - Version (2 bytes) +// - Compression Method (2 bytes) - Uses the values from +// llvm::compression::Format. +// - Uncompressed Size (4 bytes). +// - Truncated MD5 Hash (8 bytes). +// - Compressed Data (variable length). + +class CompressedOffloadBundle { +private: + static inline const size_t MagicSize = 4; + static inline const size_t VersionFieldSize = sizeof(uint16_t); + static inline const size_t MethodFieldSize = sizeof(uint16_t); + static inline const size_t SizeFieldSize = sizeof(uint32_t); + static inline const size_t HashFieldSize = 8; + static inline const size_t HeaderSize = MagicSize + VersionFieldSize + + MethodFieldSize + SizeFieldSize + + HashFieldSize; + static inline const llvm::StringRef MagicNumber = "CCOB"; + static inline const uint16_t Version = 1; + +public: + static llvm::Expected> + compress(const llvm::MemoryBuffer &Input, bool Verbose = false); + static llvm::Expected> + decompress(const llvm::MemoryBuffer &Input, bool Verbose = false); +}; + } // namespace clang #endif // LLVM_CLANG_DRIVER_OFFLOADBUNDLER_H diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 61e0729974c24..c272a7f1c398a 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1183,6 +1183,10 @@ def fgpu_inline_threshold_EQ : Joined<["-"], "fgpu-inline-threshold=">, def fgpu_sanitize : Flag<["-"], "fgpu-sanitize">, Group, HelpText<"Enable sanitizer for supported offloading devices">; def fno_gpu_sanitize : Flag<["-"], "fno-gpu-sanitize">, Group; + +def offload_compress : Flag<["--"], "offload-compress">, + HelpText<"Compress offload device binaries (HIP only)">; +def no_offload_compress : Flag<["--"], "no-offload-compress">; } // CUDA options @@ -1905,6 +1909,12 @@ defm safe_buffer_usage_suggestions : BoolFOption<"safe-buffer-usage-suggestions" PosFlag, NegFlag>; +def fverify_intermediate_code : Flag<["-"], "fverify-intermediate-code">, + Group, Visibility<[ClangOption, CLOption, DXCOption]>, + HelpText<"Enable verification of LLVM IR">, Flags<[NoXarchOption]>; +def fno_verify_intermediate_code : Flag<["-"], "fno-verify-intermediate-code">, + Group, Visibility<[ClangOption, CLOption, DXCOption]>, + HelpText<"Disable verification of LLVM IR">, Flags<[NoXarchOption]>; def fdiscard_value_names : Flag<["-"], "fdiscard-value-names">, Group, Visibility<[ClangOption, DXCOption]>, HelpText<"Discard value names in LLVM IR">, Flags<[NoXarchOption]>; @@ -2509,6 +2519,17 @@ defm minimize_whitespace : BoolFOption<"minimize-whitespace", "whitespace such that two files with only formatting changes are " "equal.\n\nOnly valid with -E on C-like inputs and incompatible " "with -traditional-cpp.">, NegFlag>; +defm keep_system_includes : BoolFOption<"keep-system-includes", + PreprocessorOutputOpts<"KeepSystemIncludes">, DefaultFalse, + PosFlag, + NegFlag>; def ffreestanding : Flag<["-"], "ffreestanding">, Group, Visibility<[ClangOption, CC1Option]>, @@ -3131,7 +3152,8 @@ defm diagnostics_show_line_numbers : BoolFOption<"diagnostics-show-line-numbers" def fno_stack_protector : Flag<["-"], "fno-stack-protector">, Group, HelpText<"Disable the use of stack protectors">; def fno_strict_aliasing : Flag<["-"], "fno-strict-aliasing">, Group, - Flags<[NoXarchOption]>, Visibility<[ClangOption, CLOption, DXCOption]>; + Flags<[NoXarchOption]>, Visibility<[ClangOption, CLOption, DXCOption]>, + HelpText<"Disable optimizations based on strict aliasing rules">; def fstruct_path_tbaa : Flag<["-"], "fstruct-path-tbaa">, Group; def fno_struct_path_tbaa : Flag<["-"], "fno-struct-path-tbaa">, Group; def fno_strict_enums : Flag<["-"], "fno-strict-enums">, Group; @@ -3574,7 +3596,8 @@ def fno_debug_macro : Flag<["-"], "fno-debug-macro">, Group, Visibility<[ClangOption, CLOption, DXCOption]>, HelpText<"Do not emit macro debug information">; def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group, - Flags<[NoXarchOption]>, Visibility<[ClangOption, CLOption, DXCOption]>; + Flags<[NoXarchOption]>, Visibility<[ClangOption, CLOption, DXCOption]>, + HelpText<"Enable optimizations based on strict aliasing rules">; def fstrict_enums : Flag<["-"], "fstrict-enums">, Group, Visibility<[ClangOption, CC1Option]>, HelpText<"Enable optimizations based on the strict definition of an enum's " @@ -4283,7 +4306,7 @@ def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group, MarshallingInfoString, [{"default"}]>; def mlarge_data_threshold_EQ : Joined<["-"], "mlarge-data-threshold=">, Group, Visibility<[ClangOption, CC1Option]>, - MarshallingInfoInt>; + MarshallingInfoInt, "65535">; def mtls_size_EQ : Joined<["-"], "mtls-size=">, Group, Flags<[NoXarchOption]>, Visibility<[ClangOption, CC1Option]>, HelpText<"Specify bit size of immediate TLS offsets (AArch64 ELF only): " diff --git a/clang/include/clang/Frontend/PreprocessorOutputOptions.h b/clang/include/clang/Frontend/PreprocessorOutputOptions.h index d542032431b14..db2ec9f2ae206 100644 --- a/clang/include/clang/Frontend/PreprocessorOutputOptions.h +++ b/clang/include/clang/Frontend/PreprocessorOutputOptions.h @@ -26,6 +26,7 @@ class PreprocessorOutputOptions { unsigned RewriteImports : 1; ///< Include contents of transitively-imported modules. unsigned MinimizeWhitespace : 1; ///< Ignore whitespace from input. unsigned DirectivesOnly : 1; ///< Process directives but do not expand macros. + unsigned KeepSystemIncludes : 1; ///< Do not expand system headers. public: PreprocessorOutputOptions() { @@ -40,6 +41,7 @@ class PreprocessorOutputOptions { RewriteImports = 0; MinimizeWhitespace = 0; DirectivesOnly = 0; + KeepSystemIncludes = 0; } }; diff --git a/clang/include/clang/Lex/HeaderSearchOptions.h b/clang/include/clang/Lex/HeaderSearchOptions.h index 126659f3ac002..c7d95006bb779 100644 --- a/clang/include/clang/Lex/HeaderSearchOptions.h +++ b/clang/include/clang/Lex/HeaderSearchOptions.h @@ -267,8 +267,8 @@ inline llvm::hash_code hash_value(const HeaderSearchOptions::Entry &E) { return llvm::hash_combine(E.Path, E.Group, E.IsFramework, E.IgnoreSysRoot); } -template -inline void addHash(llvm::HashBuilderImpl &HBuilder, +template +inline void addHash(llvm::HashBuilder &HBuilder, const HeaderSearchOptions::Entry &E) { HBuilder.add(E.Path, E.Group, E.IsFramework, E.IgnoreSysRoot); } @@ -278,8 +278,8 @@ hash_value(const HeaderSearchOptions::SystemHeaderPrefix &SHP) { return llvm::hash_combine(SHP.Prefix, SHP.IsSystemHeader); } -template -inline void addHash(llvm::HashBuilderImpl &HBuilder, +template +inline void addHash(llvm::HashBuilder &HBuilder, const HeaderSearchOptions::SystemHeaderPrefix &SHP) { HBuilder.add(SHP.Prefix, SHP.IsSystemHeader); } diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index e88164f196c1f..18d88407ae12c 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -1722,6 +1722,9 @@ class Preprocessor { /// Lex the next token for this preprocessor. void Lex(Token &Result); + /// Lex all tokens for this preprocessor until (and excluding) end of file. + void LexTokensUntilEOF(std::vector *Tokens = nullptr); + /// Lex a token, forming a header-name token if possible. bool LexHeaderName(Token &Result, bool AllowMacroExpansion = true); @@ -2697,7 +2700,7 @@ class Preprocessor { /// \c false if the module appears to be usable. static bool checkModuleIsAvailable(const LangOptions &LangOpts, const TargetInfo &TargetInfo, - DiagnosticsEngine &Diags, Module *M); + const Module &M, DiagnosticsEngine &Diags); // Module inclusion testing. /// Find the module that owns the source or header file that diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 0e969f341bbe1..79ac622fd03e2 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1766,6 +1766,7 @@ class Parser : public CodeCompletionHandler { ExprResult ParseConstantExpressionInExprEvalContext( TypeCastState isTypeCast = NotTypeCast); ExprResult ParseConstantExpression(); + ExprResult ParseArrayBoundExpression(); ExprResult ParseCaseExpression(SourceLocation CaseLoc); ExprResult ParseConstraintExpression(); ExprResult diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index bb05c45391b54..2ebd21090ae4e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1062,20 +1062,6 @@ class Sema final { } }; - /// Whether the AST is currently being rebuilt to correct immediate - /// invocations. Immediate invocation candidates and references to consteval - /// functions aren't tracked when this is set. - bool RebuildingImmediateInvocation = false; - - /// Used to change context to isConstantEvaluated without pushing a heavy - /// ExpressionEvaluationContextRecord object. - bool isConstantEvaluatedOverride; - - bool isConstantEvaluated() const { - return ExprEvalContexts.back().isConstantEvaluated() || - isConstantEvaluatedOverride; - } - /// RAII object to handle the state changes required to synthesize /// a function body. class SynthesizedFunctionScope { @@ -1361,6 +1347,11 @@ class Sema final { bool IsCurrentlyCheckingDefaultArgumentOrInitializer = false; + // We are in a constant context, but we also allow + // non constant expressions, for example for array bounds (which may be + // VLAs). + bool InConditionallyConstantEvaluateContext = false; + // When evaluating immediate functions in the initializer of a default // argument or default member initializer, this is the declaration whose // default initializer is being evaluated and the location of the call @@ -8458,9 +8449,9 @@ class Sema final { SourceLocation PrevPtOfInstantiation, bool &SuppressNew); - bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, - const TemplateArgumentListInfo &ExplicitTemplateArgs, - LookupResult &Previous); + bool CheckDependentFunctionTemplateSpecialization( + FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs, + LookupResult &Previous); bool CheckFunctionTemplateSpecialization( FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs, @@ -9876,30 +9867,44 @@ class Sema final { /// diagnostics that will be suppressed. std::optional isSFINAEContext() const; - /// Determines whether we are currently in a context that - /// is not evaluated as per C++ [expr] p5. - bool isUnevaluatedContext() const { + /// Whether the AST is currently being rebuilt to correct immediate + /// invocations. Immediate invocation candidates and references to consteval + /// functions aren't tracked when this is set. + bool RebuildingImmediateInvocation = false; + + /// Used to change context to isConstantEvaluated without pushing a heavy + /// ExpressionEvaluationContextRecord object. + bool isConstantEvaluatedOverride = false; + + const ExpressionEvaluationContextRecord ¤tEvaluationContext() const { assert(!ExprEvalContexts.empty() && "Must be in an expression evaluation context"); - return ExprEvalContexts.back().isUnevaluated(); - } + return ExprEvalContexts.back(); + }; bool isConstantEvaluatedContext() const { - assert(!ExprEvalContexts.empty() && - "Must be in an expression evaluation context"); - return ExprEvalContexts.back().isConstantEvaluated(); + return currentEvaluationContext().isConstantEvaluated() || + isConstantEvaluatedOverride; + } + + bool isAlwaysConstantEvaluatedContext() const { + const ExpressionEvaluationContextRecord &Ctx = currentEvaluationContext(); + return (Ctx.isConstantEvaluated() || isConstantEvaluatedOverride) && + !Ctx.InConditionallyConstantEvaluateContext; + } + + /// Determines whether we are currently in a context that + /// is not evaluated as per C++ [expr] p5. + bool isUnevaluatedContext() const { + return currentEvaluationContext().isUnevaluated(); } bool isImmediateFunctionContext() const { - assert(!ExprEvalContexts.empty() && - "Must be in an expression evaluation context"); - return ExprEvalContexts.back().isImmediateFunctionContext(); + return currentEvaluationContext().isImmediateFunctionContext(); } bool isCheckingDefaultArgumentOrInitializer() const { - assert(!ExprEvalContexts.empty() && - "Must be in an expression evaluation context"); - const ExpressionEvaluationContextRecord &Ctx = ExprEvalContexts.back(); + const ExpressionEvaluationContextRecord &Ctx = currentEvaluationContext(); return (Ctx.Context == ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed) || Ctx.IsCurrentlyCheckingDefaultArgumentOrInitializer; @@ -12479,6 +12484,10 @@ class Sema final { SourceLocation LParenLoc, SourceLocation EndLoc); + /// Called on a well-formed 'ompx_bare' clause. + OMPClause *ActOnOpenMPXBareClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// The kind of conversion being performed. enum CheckedConversionKind { /// An implicit conversion. diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 1de2cc6917b42..28d603bf11595 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -630,8 +630,6 @@ enum class TemplateSubstitutionKind : char { // A few supplemental visitor functions. Decl *VisitCXXMethodDecl(CXXMethodDecl *D, TemplateParameterList *TemplateParams, - std::optional - ClassScopeSpecializationArgs = std::nullopt, RewriteKind RK = RewriteKind::None); Decl *VisitFunctionDecl(FunctionDecl *D, TemplateParameterList *TemplateParams, diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 9e115f2a5cce3..5c32fbc079c9a 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -51,7 +51,7 @@ const unsigned VERSION_MAJOR = 29; /// for the previous version could still support reading the new /// version by ignoring new kinds of subblocks), this number /// should be increased. -const unsigned VERSION_MINOR = 0; +const unsigned VERSION_MINOR = 1; /// An ID number that refers to an identifier in an AST file. /// @@ -524,13 +524,7 @@ enum ASTRecordTypes { /// of source-location information. SOURCE_LOCATION_OFFSETS = 14, - /// Record code for the set of source location entries - /// that need to be preloaded by the AST reader. - /// - /// This set contains the source location entry for the - /// predefines buffer and for any file entries that need to be - /// preloaded. - SOURCE_LOCATION_PRELOADS = 15, + // ID 15 used to be for source location entry preloads. /// Record code for the set of ext_vector type names. EXT_VECTOR_DECLS = 16, @@ -1481,10 +1475,6 @@ enum DeclCode { /// template template parameter pack. DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK, - /// A ClassScopeFunctionSpecializationDecl record a class scope - /// function specialization. (Microsoft extension). - DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION, - /// An ImportDecl recording a module import. DECL_IMPORT, diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 3468b06769560..531ad94f0906a 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -2154,6 +2154,12 @@ class ASTReader /// Read the source location entry with index ID. bool ReadSLocEntry(int ID) override; + /// Get the index ID for the loaded SourceLocation offset. + int getSLocEntryID(SourceLocation::UIntTy SLocOffset) override; + /// Try to read the offset of the SLocEntry at the given index in the given + /// module file. + llvm::Expected readSLocOffset(ModuleFile *F, + unsigned Index); /// Retrieve the module import location and module name for the /// given source manager entry ID. diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h index ca85163e0f21c..d643e54e3d923 100644 --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -155,6 +155,8 @@ class ASTRecordReader /// Reads a TemplateArgumentLoc, advancing Idx. TemplateArgumentLoc readTemplateArgumentLoc(); + void readTemplateArgumentListInfo(TemplateArgumentListInfo &Result); + const ASTTemplateArgumentListInfo* readASTTemplateArgumentListInfo(); diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index f2c7c03ff0936..98445d40ebd82 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -613,7 +613,6 @@ class ASTWriter : public ASTDeserializationListener, /// the module but currently is merely a random 32-bit number. ASTFileSignature WriteAST(Sema &SemaRef, StringRef OutputFile, Module *WritingModule, StringRef isysroot, - bool hasErrors = false, bool ShouldCacheASTInMemory = false); /// Emit a token. diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h index 0af5cae6aebc3..48be8676cc26a 100644 --- a/clang/include/clang/Serialization/ModuleFile.h +++ b/clang/include/clang/Serialization/ModuleFile.h @@ -292,9 +292,6 @@ class ModuleFile { /// AST file. const uint32_t *SLocEntryOffsets = nullptr; - /// SLocEntries that we're going to preload. - SmallVector PreloadSLocEntries; - /// Remapping table for source locations in this module. ContinuousRangeMap SLocRemap; diff --git a/clang/include/clang/Serialization/ModuleFileExtension.h b/clang/include/clang/Serialization/ModuleFileExtension.h index 2168ce2ce607c..d7d456c8b5db8 100644 --- a/clang/include/clang/Serialization/ModuleFileExtension.h +++ b/clang/include/clang/Serialization/ModuleFileExtension.h @@ -86,8 +86,7 @@ class ModuleFileExtension /// The default implementation of this function simply does nothing, so the /// presence/absence of this extension does not distinguish module files. using ExtensionHashBuilder = - llvm::HashBuilderImpl; + llvm::HashBuilder; virtual void hashExtension(ExtensionHashBuilder &HBuilder) const; /// Create a new module file extension writer, which will be diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index b7240e64388f3..72e70427161bb 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -3342,27 +3342,25 @@ Error ASTNodeImporter::ImportTemplateInformation( case FunctionDecl::TK_DependentFunctionTemplateSpecialization: { auto *FromInfo = FromFD->getDependentSpecializationInfo(); - UnresolvedSet<8> TemplDecls; - unsigned NumTemplates = FromInfo->getNumTemplates(); - for (unsigned I = 0; I < NumTemplates; I++) { - if (Expected ToFTDOrErr = - import(FromInfo->getTemplate(I))) - TemplDecls.addDecl(*ToFTDOrErr); + UnresolvedSet<8> Candidates; + for (FunctionTemplateDecl *FTD : FromInfo->getCandidates()) { + if (Expected ToFTDOrErr = import(FTD)) + Candidates.addDecl(*ToFTDOrErr); else return ToFTDOrErr.takeError(); } // Import TemplateArgumentListInfo. TemplateArgumentListInfo ToTAInfo; - if (Error Err = ImportTemplateArgumentListInfo( - FromInfo->getLAngleLoc(), FromInfo->getRAngleLoc(), - llvm::ArrayRef(FromInfo->getTemplateArgs(), - FromInfo->getNumTemplateArgs()), - ToTAInfo)) - return Err; + const auto *FromTAArgsAsWritten = FromInfo->TemplateArgumentsAsWritten; + if (FromTAArgsAsWritten) + if (Error Err = + ImportTemplateArgumentListInfo(*FromTAArgsAsWritten, ToTAInfo)) + return Err; - ToFD->setDependentTemplateSpecialization(Importer.getToContext(), - TemplDecls, ToTAInfo); + ToFD->setDependentTemplateSpecialization( + Importer.getToContext(), Candidates, + FromTAArgsAsWritten ? &ToTAInfo : nullptr); return Error::success(); } } @@ -6242,6 +6240,9 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { // FIXME Check for ODR error if the two definitions have // different initializers? return Importer.MapImported(D, FoundDef); + if (FoundTemplate->getDeclContext()->isRecord() && + D->getDeclContext()->isRecord()) + return Importer.MapImported(D, FoundTemplate); FoundByLookup = FoundTemplate; break; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index b88df1edf845a..480639606d225 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3975,6 +3975,12 @@ void FunctionDecl::setDescribedFunctionTemplate( TemplateOrSpecialization = Template; } +bool FunctionDecl::isFunctionTemplateSpecialization() const { + return TemplateOrSpecialization.is() || + TemplateOrSpecialization + .is(); +} + void FunctionDecl::setInstantiatedFromDecl(FunctionDecl *FD) { assert(TemplateOrSpecialization.isNull() && "Function is already a specialization"); @@ -4109,6 +4115,11 @@ FunctionDecl::getTemplateSpecializationArgsAsWritten() const { .dyn_cast()) { return Info->TemplateArgumentsAsWritten; } + if (DependentFunctionTemplateSpecializationInfo *Info = + TemplateOrSpecialization + .dyn_cast()) { + return Info->TemplateArgumentsAsWritten; + } return nullptr; } @@ -4137,10 +4148,9 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C, Template->addSpecialization(Info, InsertPos); } -void -FunctionDecl::setDependentTemplateSpecialization(ASTContext &Context, - const UnresolvedSetImpl &Templates, - const TemplateArgumentListInfo &TemplateArgs) { +void FunctionDecl::setDependentTemplateSpecialization( + ASTContext &Context, const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo *TemplateArgs) { assert(TemplateOrSpecialization.isNull()); DependentFunctionTemplateSpecializationInfo *Info = DependentFunctionTemplateSpecializationInfo::Create(Context, Templates, @@ -4156,28 +4166,26 @@ FunctionDecl::getDependentSpecializationInfo() const { DependentFunctionTemplateSpecializationInfo * DependentFunctionTemplateSpecializationInfo::Create( - ASTContext &Context, const UnresolvedSetImpl &Ts, - const TemplateArgumentListInfo &TArgs) { - void *Buffer = Context.Allocate( - totalSizeToAlloc( - TArgs.size(), Ts.size())); - return new (Buffer) DependentFunctionTemplateSpecializationInfo(Ts, TArgs); + ASTContext &Context, const UnresolvedSetImpl &Candidates, + const TemplateArgumentListInfo *TArgs) { + const auto *TArgsWritten = + TArgs ? ASTTemplateArgumentListInfo::Create(Context, *TArgs) : nullptr; + return new (Context.Allocate( + totalSizeToAlloc(Candidates.size()))) + DependentFunctionTemplateSpecializationInfo(Candidates, TArgsWritten); } DependentFunctionTemplateSpecializationInfo:: -DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts, - const TemplateArgumentListInfo &TArgs) - : AngleLocs(TArgs.getLAngleLoc(), TArgs.getRAngleLoc()) { - NumTemplates = Ts.size(); - NumArgs = TArgs.size(); - - FunctionTemplateDecl **TsArray = getTrailingObjects(); - for (unsigned I = 0, E = Ts.size(); I != E; ++I) - TsArray[I] = cast(Ts[I]->getUnderlyingDecl()); - - TemplateArgumentLoc *ArgsArray = getTrailingObjects(); - for (unsigned I = 0, E = TArgs.size(); I != E; ++I) - new (&ArgsArray[I]) TemplateArgumentLoc(TArgs[I]); + DependentFunctionTemplateSpecializationInfo( + const UnresolvedSetImpl &Candidates, + const ASTTemplateArgumentListInfo *TemplateArgsWritten) + : NumCandidates(Candidates.size()), + TemplateArgumentsAsWritten(TemplateArgsWritten) { + std::transform(Candidates.begin(), Candidates.end(), + getTrailingObjects(), + [](NamedDecl *ND) { + return cast(ND->getUnderlyingDecl()); + }); } TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { @@ -4192,6 +4200,13 @@ TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { TemplateOrSpecialization.dyn_cast()) return MSInfo->getTemplateSpecializationKind(); + // A dependent function template specialization is an explicit specialization, + // except when it's a friend declaration. + if (TemplateOrSpecialization + .is() && + getFriendObjectKind() == FOK_None) + return TSK_ExplicitSpecialization; + return TSK_Undeclared; } @@ -4206,6 +4221,11 @@ FunctionDecl::getTemplateSpecializationKindForInstantiation() const { // template<> void f() {} // }; // + // Within the templated CXXRecordDecl, A::f is a dependent function + // template specialization; both getTemplateSpecializationKind() and + // getTemplateSpecializationKindForInstantiation() will return + // TSK_ExplicitSpecialization. + // // For A::f(): // * getTemplateSpecializationKind() will return TSK_ExplicitSpecialization // * getTemplateSpecializationKindForInstantiation() will return @@ -4226,6 +4246,11 @@ FunctionDecl::getTemplateSpecializationKindForInstantiation() const { TemplateOrSpecialization.dyn_cast()) return MSInfo->getTemplateSpecializationKind(); + if (TemplateOrSpecialization + .is() && + getFriendObjectKind() == FOK_None) + return TSK_ExplicitSpecialization; + return TSK_Undeclared; } diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 834beef49a444..3804f1a5b49d3 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -862,7 +862,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case BuiltinTemplate: case ClassTemplateSpecialization: case ClassTemplatePartialSpecialization: - case ClassScopeFunctionSpecialization: case VarTemplateSpecialization: case VarTemplatePartialSpecialization: case ObjCImplementation: @@ -1003,9 +1002,7 @@ bool Decl::AccessDeclContextCheck() const { isa(this) || // FIXME: a ClassTemplateSpecialization or CXXRecordDecl can have // AS_none as access specifier. - isa(this) || - isa(this) || - isa(this)) + isa(this) || isa(this)) return true; assert(Access != AS_none && diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 42bab4ed51b72..a92b788366434 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1484,7 +1484,8 @@ void CXXRecordDecl::setCaptures(ASTContext &Context, if (Captures[I].isExplicit()) ++Data.NumExplicitCaptures; - *ToCapture++ = Captures[I]; + new (ToCapture) LambdaCapture(Captures[I]); + ToCapture++; } if (!lambdaIsDefaultConstructibleAndAssignable()) diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index e934a81d086e3..e1eef2dbd9c3d 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -931,8 +931,8 @@ void ObjCMethodDecl::setParamsAndSelLocs(ASTContext &C, unsigned Size = sizeof(ParmVarDecl *) * NumParams + sizeof(SourceLocation) * SelLocs.size(); ParamsAndSelLocs = C.Allocate(Size); - std::copy(Params.begin(), Params.end(), getParams()); - std::copy(SelLocs.begin(), SelLocs.end(), getStoredSelLocs()); + std::uninitialized_copy(Params.begin(), Params.end(), getParams()); + std::uninitialized_copy(SelLocs.begin(), SelLocs.end(), getStoredSelLocs()); } void ObjCMethodDecl::getSelectorLocs( diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 5e2742b4949f2..be385ca115254 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -1195,19 +1195,6 @@ TypeAliasTemplateDecl::newCommon(ASTContext &C) const { return CommonPtr; } -//===----------------------------------------------------------------------===// -// ClassScopeFunctionSpecializationDecl Implementation -//===----------------------------------------------------------------------===// - -void ClassScopeFunctionSpecializationDecl::anchor() {} - -ClassScopeFunctionSpecializationDecl * -ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C, - unsigned ID) { - return new (C, ID) ClassScopeFunctionSpecializationDecl( - nullptr, SourceLocation(), nullptr, nullptr); -} - //===----------------------------------------------------------------------===// // VarTemplateDecl Implementation //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index a142ea7c47a47..5a33e918db8e8 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -3357,6 +3357,9 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, return false; } + if (E->isValueDependent()) + return false; + // Dig out the initializer, and use the declaration which it's attached to. // FIXME: We should eventually check whether the variable has a reachable // initializing declaration. @@ -8367,7 +8370,13 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { if (auto *FD = Info.CurrentCall->LambdaCaptureFields.lookup(VD)) { // Start with 'Result' referring to the complete closure object... - Result = *Info.CurrentCall->This; + if (auto *MD = cast(Info.CurrentCall->Callee); + MD->isExplicitObjectMemberFunction()) { + APValue *RefValue = + Info.getParamSlot(Info.CurrentCall->Arguments, MD->getParamDecl(0)); + Result.setFrom(Info.Ctx, *RefValue); + } else + Result = *Info.CurrentCall->This; // ... then update it to refer to the field of the closure object // that represents the capture. if (!HandleLValueMember(Info, E, Result, FD)) diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp index ea4e48cb42627..a634ee288f57c 100644 --- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp +++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp @@ -64,8 +64,8 @@ ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) { this->LambdaCaptures[Cap.first] = { Offset, Cap.second->getType()->isReferenceType()}; } - // FIXME: LambdaThisCapture - (void)LTC; + if (LTC) + this->LambdaThisCapture = R->getField(LTC)->Offset; } } diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.h b/clang/lib/AST/Interp/ByteCodeEmitter.h index d184484a9197f..5520f8c300610 100644 --- a/clang/lib/AST/Interp/ByteCodeEmitter.h +++ b/clang/lib/AST/Interp/ByteCodeEmitter.h @@ -67,7 +67,8 @@ class ByteCodeEmitter { llvm::DenseMap Params; /// Lambda captures. llvm::DenseMap LambdaCaptures; - unsigned LambdaThisCapture; + /// Offset of the This parameter in a lambda record. + unsigned LambdaThisCapture = 0; /// Local descriptors. llvm::SmallVector, 2> Descriptors; diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index f4ab30a5c8e72..02b35583636bf 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -2305,6 +2305,10 @@ template bool ByteCodeExprGen::VisitCXXThisExpr(const CXXThisExpr *E) { if (DiscardResult) return true; + + if (this->LambdaThisCapture > 0) + return this->emitGetThisFieldPtr(this->LambdaThisCapture, E); + return this->emitThis(E); } @@ -2536,12 +2540,16 @@ bool ByteCodeExprGen::VisitDeclRefExpr(const DeclRefExpr *E) { // This happens in C. if (!Ctx.getLangOpts().CPlusPlus) { if (const auto *VD = dyn_cast(D); - VD && VD->hasGlobalStorage() && VD->getAnyInitializer()) { + VD && VD->hasGlobalStorage() && VD->getAnyInitializer() && + VD->getType().isConstQualified()) { if (!this->visitVarDecl(VD)) return false; // Retry. return this->VisitDeclRefExpr(E); } + + if (std::optional I = P.getOrCreateDummy(D)) + return this->emitGetPtrGlobal(*I, E); } return this->emitInvalidDeclRef(E, E); diff --git a/clang/lib/AST/Interp/EvalEmitter.h b/clang/lib/AST/Interp/EvalEmitter.h index c63e46bbf347b..1128e0fb09f0d 100644 --- a/clang/lib/AST/Interp/EvalEmitter.h +++ b/clang/lib/AST/Interp/EvalEmitter.h @@ -73,7 +73,8 @@ class EvalEmitter : public SourceMapper { llvm::DenseMap Params; /// Lambda captures. llvm::DenseMap LambdaCaptures; - unsigned LambdaThisCapture; + /// Offset of the This parameter in a lambda record. + unsigned LambdaThisCapture = 0; /// Local descriptors. llvm::SmallVector, 2> Descriptors; diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 8e85159596318..a4d6844ebe617 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -139,7 +139,7 @@ bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (!Ptr.isExtern()) return true; - if (!S.checkingPotentialConstantExpression()) { + if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) { const auto *VD = Ptr.getDeclDesc()->asValueDecl(); const SourceInfo &Loc = S.Current->getSource(OpPC); S.FFDiag(Loc, diag::note_constexpr_ltor_non_constexpr, 1) << VD; diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp index 63901d90703dc..65e170881e313 100644 --- a/clang/lib/AST/Interp/Program.cpp +++ b/clang/lib/AST/Interp/Program.cpp @@ -138,17 +138,16 @@ std::optional Program::getOrCreateGlobal(const ValueDecl *VD, return std::nullopt; } -std::optional Program::getOrCreateDummy(const ParmVarDecl *PD) { - +std::optional Program::getOrCreateDummy(const ValueDecl *PD) { // Dedup blocks since they are immutable and pointers cannot be compared. if (auto It = DummyParams.find(PD); It != DummyParams.end()) return It->second; - auto &ASTCtx = Ctx.getASTContext(); // Create a pointer to an incomplete array of the specified elements. - QualType ElemTy = PD->getType()->castAs()->getPointeeType(); - QualType Ty = ASTCtx.getIncompleteArrayType(ElemTy, ArrayType::Normal, 0); + QualType ElemTy = PD->getType(); + QualType Ty = + Ctx.getASTContext().getIncompleteArrayType(ElemTy, ArrayType::Normal, 0); if (auto Idx = createGlobal(PD, Ty, /*isStatic=*/true, /*isExtern=*/true)) { DummyParams[PD] = *Idx; diff --git a/clang/lib/AST/Interp/Program.h b/clang/lib/AST/Interp/Program.h index d880a738e733e..d843fa06538f5 100644 --- a/clang/lib/AST/Interp/Program.h +++ b/clang/lib/AST/Interp/Program.h @@ -82,8 +82,8 @@ class Program final { std::optional getOrCreateGlobal(const ValueDecl *VD, const Expr *Init = nullptr); - /// Returns or creates a dummy value for parameters. - std::optional getOrCreateDummy(const ParmVarDecl *PD); + /// Returns or creates a dummy value for unknown declarations. + std::optional getOrCreateDummy(const ValueDecl *PD); /// Creates a global and returns its index. std::optional createGlobal(const ValueDecl *VD, const Expr *E); @@ -208,7 +208,7 @@ class Program final { llvm::DenseMap Records; /// Dummy parameter to generate pointers from. - llvm::DenseMap DummyParams; + llvm::DenseMap DummyParams; /// Creates a new descriptor. template diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 5eab315793b41..7f9b5eb52e367 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -658,6 +658,10 @@ void ODRHash::AddFunctionDecl(const FunctionDecl *Function, if (F->isFunctionTemplateSpecialization()) { if (!isa(DC)) return; if (DC->getLexicalParent()->isFileContext()) return; + // Skip class scope explicit function template specializations, + // as they have not yet been instantiated. + if (F->getDependentSpecializationInfo()) + return; // Inline method specializations are the only supported // specialization for now. } diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index f5ad75028a641..b95b4fce180e7 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -170,6 +170,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { case OMPC_affinity: case OMPC_when: case OMPC_bind: + case OMPC_ompx_bare: break; default: break; @@ -2546,6 +2547,10 @@ void OMPClausePrinter::VisitOMPXAttributeClause(OMPXAttributeClause *Node) { OS << ")"; } +void OMPClausePrinter::VisitOMPXBareClause(OMPXBareClause *Node) { + OS << "ompx_bare"; +} + void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx, VariantMatchInfo &VMI) const { for (const OMPTraitSet &Set : Sets) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 763d3d6126980..22b6855b0fff2 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -930,6 +930,7 @@ void OMPClauseProfiler::VisitOMPDoacrossClause(const OMPDoacrossClause *C) { } void OMPClauseProfiler::VisitOMPXAttributeClause(const OMPXAttributeClause *C) { } +void OMPClauseProfiler::VisitOMPXBareClause(const OMPXBareClause *C) {} } // namespace void diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp index 47915958750d1..8aef1d6f46089 100644 --- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp +++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp @@ -150,6 +150,7 @@ class HTMLLogger : public Logger { const CFGBlock *Block; unsigned Iter; bool PostVisit; + bool Converged; }; StreamFactory Streams; @@ -159,8 +160,8 @@ class HTMLLogger : public Logger { const ControlFlowContext *CFG; // Timeline of iterations of CFG block visitation. std::vector Iters; - // Number of times each CFG block has been seen. - llvm::DenseMap> BlockIters; + // Indexes in `Iters` of the iterations for each block. + llvm::DenseMap> BlockIters; // The messages logged in the current context but not yet written. std::string ContextLogs; // The number of elements we have visited within the current CFG block. @@ -207,6 +208,7 @@ class HTMLLogger : public Logger { JOS->attribute("block", blockID(E.Block->getBlockID())); JOS->attribute("iter", E.Iter); JOS->attribute("post_visit", E.PostVisit); + JOS->attribute("converged", E.Converged); }); } }); @@ -222,10 +224,10 @@ class HTMLLogger : public Logger { } void enterBlock(const CFGBlock &B, bool PostVisit) override { - llvm::SmallVector &BIter = BlockIters[&B]; + llvm::SmallVector &BIter = BlockIters[&B]; unsigned IterNum = BIter.size() + 1; - BIter.push_back({&B, IterNum, PostVisit}); - Iters.push_back({&B, IterNum, PostVisit}); + BIter.push_back(Iters.size()); + Iters.push_back({&B, IterNum, PostVisit, /*Converged=*/false}); ElementIndex = 0; } void enterElement(const CFGElement &E) override { @@ -290,7 +292,7 @@ class HTMLLogger : public Logger { } }); } - void blockConverged() override { logText("Block converged"); } + void blockConverged() override { Iters.back().Converged = true; } void logText(llvm::StringRef S) override { ContextLogs.append(S.begin(), S.end()); @@ -301,13 +303,15 @@ class HTMLLogger : public Logger { // Write the CFG block details. // Currently this is just the list of elements in execution order. // FIXME: an AST dump would be a useful view, too. - void writeBlock(const CFGBlock &B, llvm::ArrayRef ItersForB) { + void writeBlock(const CFGBlock &B, llvm::ArrayRef ItersForB) { JOS->attributeObject(blockID(B.getBlockID()), [&] { JOS->attributeArray("iters", [&] { - for (const auto &Iter : ItersForB) { + for (size_t IterIdx : ItersForB) { + const Iteration &Iter = Iters[IterIdx]; JOS->object([&] { JOS->attribute("iter", Iter.Iter); JOS->attribute("post_visit", Iter.PostVisit); + JOS->attribute("converged", Iter.Converged); }); } }); diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.html b/clang/lib/Analysis/FlowSensitive/HTMLLogger.html index 6d866d57e1448..ec9d74c71d35d 100644 --- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.html +++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.html @@ -45,6 +45,7 @@ {{entry.block}} + @@ -62,6 +63,7 @@ + diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp index 0fd9c1dca3998..7879a11179b6d 100644 --- a/clang/lib/Basic/Module.cpp +++ b/clang/lib/Basic/Module.cpp @@ -301,7 +301,8 @@ bool Module::directlyUses(const Module *Requested) { // Anyone is allowed to use our builtin stdarg.h and stddef.h and their // accompanying modules. - if (!Requested->Parent && (Requested->Name == "_Builtin_stdarg" || Requested->Name == "_Builtin_stddef")) + if (Requested->getTopLevelModuleName() == "_Builtin_stdarg" || + Requested->getTopLevelModuleName() == "_Builtin_stddef") return true; if (NoUndeclaredIncludes) diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp index 7312f0514e72f..4ce89267e03f4 100644 --- a/clang/lib/Basic/SourceManager.cpp +++ b/clang/lib/Basic/SourceManager.cpp @@ -337,6 +337,7 @@ void SourceManager::clearIDTables() { LocalSLocEntryTable.clear(); LoadedSLocEntryTable.clear(); SLocEntryLoaded.clear(); + SLocEntryOffsetLoaded.clear(); LastLineNoFileIDQuery = FileID(); LastLineNoContentCache = nullptr; LastFileIDLookup = FileID(); @@ -459,9 +460,11 @@ SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries, } LoadedSLocEntryTable.resize(LoadedSLocEntryTable.size() + NumSLocEntries); SLocEntryLoaded.resize(LoadedSLocEntryTable.size()); + SLocEntryOffsetLoaded.resize(LoadedSLocEntryTable.size()); CurrentLoadedOffset -= TotalSize; - int ID = LoadedSLocEntryTable.size(); - return std::make_pair(-ID - 1, CurrentLoadedOffset); + int BaseID = -int(LoadedSLocEntryTable.size()) - 1; + LoadedSLocEntryAllocBegin.push_back(FileID::get(BaseID)); + return std::make_pair(BaseID, CurrentLoadedOffset); } /// As part of recovering from missing or changed content, produce a @@ -596,7 +599,7 @@ FileID SourceManager::createFileIDImpl(ContentCache &File, StringRef Filename, assert(!SLocEntryLoaded[Index] && "FileID already loaded"); LoadedSLocEntryTable[Index] = SLocEntry::get( LoadedOffset, FileInfo::get(IncludePos, File, FileCharacter, Filename)); - SLocEntryLoaded[Index] = true; + SLocEntryLoaded[Index] = SLocEntryOffsetLoaded[Index] = true; return FileID::get(LoadedID); } unsigned FileSize = File.getSize(); @@ -656,7 +659,7 @@ SourceManager::createExpansionLocImpl(const ExpansionInfo &Info, assert(Index < LoadedSLocEntryTable.size() && "FileID out of range"); assert(!SLocEntryLoaded[Index] && "FileID already loaded"); LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset, Info); - SLocEntryLoaded[Index] = true; + SLocEntryLoaded[Index] = SLocEntryOffsetLoaded[Index] = true; return SourceLocation::getMacroLoc(LoadedOffset); } LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset, Info)); @@ -857,69 +860,7 @@ FileID SourceManager::getFileIDLoaded(SourceLocation::UIntTy SLocOffset) const { return FileID(); } - // Essentially the same as the local case, but the loaded array is sorted - // in the other direction (decreasing order). - // GreaterIndex is the one where the offset is greater, which is actually a - // lower index! - unsigned GreaterIndex = 0; - unsigned LessIndex = LoadedSLocEntryTable.size(); - if (LastFileIDLookup.ID < 0) { - // Prune the search space. - int LastID = LastFileIDLookup.ID; - if (getLoadedSLocEntryByID(LastID).getOffset() > SLocOffset) - GreaterIndex = - (-LastID - 2) + 1; // Exclude LastID, else we would have hit the cache - else - LessIndex = -LastID - 2; - } - - // First do a linear scan from the last lookup position, if possible. - unsigned NumProbes; - bool Invalid = false; - for (NumProbes = 0; NumProbes < 8; ++NumProbes, ++GreaterIndex) { - // Make sure the entry is loaded! - const SrcMgr::SLocEntry &E = getLoadedSLocEntry(GreaterIndex, &Invalid); - if (Invalid) - return FileID(); // invalid entry. - if (E.getOffset() <= SLocOffset) { - FileID Res = FileID::get(-int(GreaterIndex) - 2); - LastFileIDLookup = Res; - NumLinearScans += NumProbes + 1; - return Res; - } - } - - // Linear scan failed. Do the binary search. - NumProbes = 0; - while (true) { - ++NumProbes; - unsigned MiddleIndex = (LessIndex - GreaterIndex) / 2 + GreaterIndex; - const SrcMgr::SLocEntry &E = getLoadedSLocEntry(MiddleIndex, &Invalid); - if (Invalid) - return FileID(); // invalid entry. - - if (E.getOffset() > SLocOffset) { - if (GreaterIndex == MiddleIndex) { - assert(0 && "binary search missed the entry"); - return FileID(); - } - GreaterIndex = MiddleIndex; - continue; - } - - if (isOffsetInFileID(FileID::get(-int(MiddleIndex) - 2), SLocOffset)) { - FileID Res = FileID::get(-int(MiddleIndex) - 2); - LastFileIDLookup = Res; - NumBinaryProbes += NumProbes; - return Res; - } - - if (LessIndex == MiddleIndex) { - assert(0 && "binary search missed the entry"); - return FileID(); - } - LessIndex = MiddleIndex; - } + return FileID::get(ExternalSLocEntries->getSLocEntryID(SLocOffset)); } SourceLocation SourceManager:: @@ -1964,14 +1905,39 @@ SourceManager::getDecomposedIncludedLoc(FileID FID) const { return DecompLoc; } +bool SourceManager::isInTheSameTranslationUnitImpl( + const std::pair &LOffs, + const std::pair &ROffs) const { + // If one is local while the other is loaded. + if (isLoadedFileID(LOffs.first) != isLoadedFileID(ROffs.first)) + return false; + + if (isLoadedFileID(LOffs.first) && isLoadedFileID(ROffs.first)) { + auto FindSLocEntryAlloc = [this](FileID FID) { + // Loaded FileIDs are negative, we store the lowest FileID from each + // allocation, later allocations have lower FileIDs. + return llvm::lower_bound(LoadedSLocEntryAllocBegin, FID, + std::greater{}); + }; + + // If both are loaded from different AST files. + if (FindSLocEntryAlloc(LOffs.first) != FindSLocEntryAlloc(ROffs.first)) + return false; + } + + return true; +} + /// Given a decomposed source location, move it up the include/expansion stack -/// to the parent source location. If this is possible, return the decomposed -/// version of the parent in Loc and return false. If Loc is the top-level -/// entry, return true and don't modify it. -static bool MoveUpIncludeHierarchy(std::pair &Loc, - const SourceManager &SM) { +/// to the parent source location within the same translation unit. If this is +/// possible, return the decomposed version of the parent in Loc and return +/// false. If Loc is a top-level entry, return true and don't modify it. +static bool +MoveUpTranslationUnitIncludeHierarchy(std::pair &Loc, + const SourceManager &SM) { std::pair UpperLoc = SM.getDecomposedIncludedLoc(Loc.first); - if (UpperLoc.first.isInvalid()) + if (UpperLoc.first.isInvalid() || + !SM.isInTheSameTranslationUnitImpl(UpperLoc, Loc)) return true; // We reached the top. Loc = UpperLoc; @@ -2027,45 +1993,18 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, std::pair InSameTU = isInTheSameTranslationUnit(LOffs, ROffs); if (InSameTU.first) return InSameTU.second; - - // If we arrived here, the location is either in a built-ins buffer or - // associated with global inline asm. PR5662 and PR22576 are examples. - - StringRef LB = getBufferOrFake(LOffs.first).getBufferIdentifier(); - StringRef RB = getBufferOrFake(ROffs.first).getBufferIdentifier(); - bool LIsBuiltins = LB == ""; - bool RIsBuiltins = RB == ""; - // Sort built-in before non-built-in. - if (LIsBuiltins || RIsBuiltins) { - if (LIsBuiltins != RIsBuiltins) - return LIsBuiltins; - // Both are in built-in buffers, but from different files. We just claim that - // lower IDs come first. - return LOffs.first < ROffs.first; - } - bool LIsAsm = LB == ""; - bool RIsAsm = RB == ""; - // Sort assembler after built-ins, but before the rest. - if (LIsAsm || RIsAsm) { - if (LIsAsm != RIsAsm) - return RIsAsm; - assert(LOffs.first == ROffs.first); - return false; - } - bool LIsScratch = LB == ""; - bool RIsScratch = RB == ""; - // Sort scratch after inline asm, but before the rest. - if (LIsScratch || RIsScratch) { - if (LIsScratch != RIsScratch) - return LIsScratch; - return LOffs.second < ROffs.second; - } - llvm_unreachable("Unsortable locations found"); + // TODO: This should be unreachable, but some clients are calling this + // function before making sure LHS and RHS are in the same TU. + return LOffs.first < ROffs.first; } std::pair SourceManager::isInTheSameTranslationUnit( std::pair &LOffs, std::pair &ROffs) const { + // If the source locations are not in the same TU, return early. + if (!isInTheSameTranslationUnitImpl(LOffs, ROffs)) + return std::make_pair(false, false); + // If the source locations are in the same file, just compare offsets. if (LOffs.first == ROffs.first) return std::make_pair(true, LOffs.second < ROffs.second); @@ -2088,53 +2027,88 @@ std::pair SourceManager::isInTheSameTranslationUnit( // A location within a FileID on the path up from LOffs to the main file. struct Entry { - unsigned Offset; - FileID ParentFID; // Used for breaking ties. + std::pair DecomposedLoc; // FileID redundant, but clearer. + FileID ChildFID; // Used for breaking ties. Invalid for the initial loc. }; llvm::SmallDenseMap LChain; - FileID Parent; + FileID LChild; do { - LChain.try_emplace(LOffs.first, Entry{LOffs.second, Parent}); + LChain.try_emplace(LOffs.first, Entry{LOffs, LChild}); // We catch the case where LOffs is in a file included by ROffs and // quit early. The other way round unfortunately remains suboptimal. if (LOffs.first == ROffs.first) break; - Parent = LOffs.first; - } while (!MoveUpIncludeHierarchy(LOffs, *this)); + LChild = LOffs.first; + } while (!MoveUpTranslationUnitIncludeHierarchy(LOffs, *this)); - Parent = FileID(); + FileID RChild; do { - auto I = LChain.find(ROffs.first); - if (I != LChain.end()) { + auto LIt = LChain.find(ROffs.first); + if (LIt != LChain.end()) { // Compare the locations within the common file and cache them. - LOffs.first = I->first; - LOffs.second = I->second.Offset; - // The relative order of LParent and RParent is a tiebreaker when + LOffs = LIt->second.DecomposedLoc; + LChild = LIt->second.ChildFID; + // The relative order of LChild and RChild is a tiebreaker when // - locs expand to the same location (occurs in macro arg expansion) // - one loc is a parent of the other (we consider the parent as "first") - // For the parent to be first, the invalid file ID must compare smaller. + // For the parent entry to be first, its invalid child file ID must + // compare smaller to the valid child file ID of the other entry. // However loaded FileIDs are <0, so we perform *unsigned* comparison! // This changes the relative order of local vs loaded FileIDs, but it // doesn't matter as these are never mixed in macro expansion. - unsigned LParent = I->second.ParentFID.ID; - unsigned RParent = Parent.ID; + unsigned LChildID = LChild.ID; + unsigned RChildID = RChild.ID; assert(((LOffs.second != ROffs.second) || - (LParent == 0 || RParent == 0) || - isInSameSLocAddrSpace(getComposedLoc(I->second.ParentFID, 0), - getComposedLoc(Parent, 0), nullptr)) && + (LChildID == 0 || RChildID == 0) || + isInSameSLocAddrSpace(getComposedLoc(LChild, 0), + getComposedLoc(RChild, 0), nullptr)) && "Mixed local/loaded FileIDs with same include location?"); IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, ROffs.second, - LParent < RParent); + LChildID < RChildID); return std::make_pair( true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second)); } - Parent = ROffs.first; - } while (!MoveUpIncludeHierarchy(ROffs, *this)); + RChild = ROffs.first; + } while (!MoveUpTranslationUnitIncludeHierarchy(ROffs, *this)); + + // If we found no match, the location is either in a built-ins buffer or + // associated with global inline asm. PR5662 and PR22576 are examples. + + StringRef LB = getBufferOrFake(LOffs.first).getBufferIdentifier(); + StringRef RB = getBufferOrFake(ROffs.first).getBufferIdentifier(); + + bool LIsBuiltins = LB == ""; + bool RIsBuiltins = RB == ""; + // Sort built-in before non-built-in. + if (LIsBuiltins || RIsBuiltins) { + if (LIsBuiltins != RIsBuiltins) + return std::make_pair(true, LIsBuiltins); + // Both are in built-in buffers, but from different files. We just claim + // that lower IDs come first. + return std::make_pair(true, LOffs.first < ROffs.first); + } - // If we found no match, we're not in the same TU. - // We don't cache this, but it is rare. - return std::make_pair(false, false); + bool LIsAsm = LB == ""; + bool RIsAsm = RB == ""; + // Sort assembler after built-ins, but before the rest. + if (LIsAsm || RIsAsm) { + if (LIsAsm != RIsAsm) + return std::make_pair(true, RIsAsm); + assert(LOffs.first == ROffs.first); + return std::make_pair(true, false); + } + + bool LIsScratch = LB == ""; + bool RIsScratch = RB == ""; + // Sort scratch after inline asm, but before the rest. + if (LIsScratch || RIsScratch) { + if (LIsScratch != RIsScratch) + return std::make_pair(true, LIsScratch); + return std::make_pair(true, LOffs.second < ROffs.second); + } + + llvm_unreachable("Unsortable locations found"); } void SourceManager::PrintStats() const { diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 80822f6566285..8130f90a27674 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -219,6 +219,8 @@ std::unique_ptr AllocateTarget(const llvm::Triple &Triple, return std::make_unique>(Triple, Opts); case llvm::Triple::RTEMS: return std::make_unique>(Triple, Opts); + case llvm::Triple::Haiku: + return std::make_unique>(Triple, Opts); case llvm::Triple::NaCl: return std::make_unique>(Triple, Opts); case llvm::Triple::Win32: diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index 06e99e67c8755..1e809283748b6 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -257,6 +257,7 @@ ARMTargetInfo::ARMTargetInfo(const llvm::Triple &Triple, bool IsFreeBSD = Triple.isOSFreeBSD(); bool IsOpenBSD = Triple.isOSOpenBSD(); bool IsNetBSD = Triple.isOSNetBSD(); + bool IsHaiku = Triple.isOSHaiku(); // FIXME: the isOSBinFormatMachO is a workaround for identifying a Darwin-like // environment where size_t is `unsigned long` rather than `unsigned int` @@ -323,7 +324,7 @@ ARMTargetInfo::ARMTargetInfo(const llvm::Triple &Triple, default: if (IsNetBSD) setABI("apcs-gnu"); - else if (IsFreeBSD || IsOpenBSD) + else if (IsFreeBSD || IsOpenBSD || IsHaiku) setABI("aapcs-linux"); else setABI("aapcs"); diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index e0abc069032e1..4e895cc7310c0 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -804,7 +804,7 @@ ArrayRef PPCTargetInfo::getGCCRegAliases() const { return llvm::ArrayRef(GCCRegAliases); } -// PPC ELFABIv2 DWARF Definitoin "Table 2.26. Mappings of Common Registers". +// PPC ELFABIv2 DWARF Definition "Table 2.26. Mappings of Common Registers". // vs0 ~ vs31 is mapping to 32 - 63, // vs32 ~ vs63 is mapping to 77 - 108. const TargetInfo::AddlRegName GCCAddlRegNames[] = { diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 3f68aa2c953c7..8cb7943df9a78 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -2730,6 +2730,27 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, } } + // Check NonnullAttribute/NullabilityArg and Alignment. + auto EmitArgCheck = [&](TypeCheckKind Kind, Address A, const Expr *Arg, + unsigned ParmNum) { + Value *Val = A.getPointer(); + EmitNonNullArgCheck(RValue::get(Val), Arg->getType(), Arg->getExprLoc(), FD, + ParmNum); + + if (SanOpts.has(SanitizerKind::Alignment)) { + SanitizerSet SkippedChecks; + SkippedChecks.set(SanitizerKind::All); + SkippedChecks.clear(SanitizerKind::Alignment); + SourceLocation Loc = Arg->getExprLoc(); + // Strip an implicit cast. + if (auto *CE = dyn_cast(Arg)) + if (CE->getCastKind() == CK_BitCast) + Arg = CE->getSubExpr(); + EmitTypeCheck(Kind, Loc, Val, Arg->getType(), A.getAlignment(), + SkippedChecks); + } + }; + switch (BuiltinIDIfNoAsmLabel) { default: break; case Builtin::BI__builtin___CFStringMakeConstantString: @@ -3720,10 +3741,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Address Dest = EmitPointerWithAlignment(E->getArg(0)); Address Src = EmitPointerWithAlignment(E->getArg(1)); Value *SizeVal = EmitScalarExpr(E->getArg(2)); - EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(), - E->getArg(0)->getExprLoc(), FD, 0); - EmitNonNullArgCheck(RValue::get(Src.getPointer()), E->getArg(1)->getType(), - E->getArg(1)->getExprLoc(), FD, 1); + EmitArgCheck(TCK_Store, Dest, E->getArg(0), 0); + EmitArgCheck(TCK_Load, Src, E->getArg(1), 1); Builder.CreateMemCpy(Dest, Src, SizeVal, false); if (BuiltinID == Builtin::BImempcpy || BuiltinID == Builtin::BI__builtin_mempcpy) @@ -3738,10 +3757,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Address Src = EmitPointerWithAlignment(E->getArg(1)); uint64_t Size = E->getArg(2)->EvaluateKnownConstInt(getContext()).getZExtValue(); - EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(), - E->getArg(0)->getExprLoc(), FD, 0); - EmitNonNullArgCheck(RValue::get(Src.getPointer()), E->getArg(1)->getType(), - E->getArg(1)->getExprLoc(), FD, 1); + EmitArgCheck(TCK_Store, Dest, E->getArg(0), 0); + EmitArgCheck(TCK_Load, Src, E->getArg(1), 1); Builder.CreateMemCpyInline(Dest, Src, Size); return RValue::get(nullptr); } @@ -3798,10 +3815,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Address Dest = EmitPointerWithAlignment(E->getArg(0)); Address Src = EmitPointerWithAlignment(E->getArg(1)); Value *SizeVal = EmitScalarExpr(E->getArg(2)); - EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(), - E->getArg(0)->getExprLoc(), FD, 0); - EmitNonNullArgCheck(RValue::get(Src.getPointer()), E->getArg(1)->getType(), - E->getArg(1)->getExprLoc(), FD, 1); + EmitArgCheck(TCK_Store, Dest, E->getArg(0), 0); + EmitArgCheck(TCK_Load, Src, E->getArg(1), 1); Builder.CreateMemMove(Dest, Src, SizeVal, false); return RValue::get(Dest.getPointer()); } diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 57a424c6f176c..d18f186ce5b41 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -28,6 +28,7 @@ #include "clang/CodeGen/CGFunctionInfo.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Metadata.h" +#include "llvm/Support/SaveAndRestore.h" #include "llvm/Transforms/Utils/SanitizerStats.h" #include @@ -1291,10 +1292,10 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, assert(BaseCtorContinueBB); } - llvm::Value *const OldThis = CXXThisValue; for (; B != E && (*B)->isBaseInitializer() && (*B)->isBaseVirtual(); B++) { if (!ConstructVBases) continue; + SaveAndRestore ThisRAII(CXXThisValue); if (CGM.getCodeGenOpts().StrictVTablePointers && CGM.getCodeGenOpts().OptimizationLevel > 0 && isInitializerOfDynamicClass(*B)) @@ -1311,7 +1312,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, // Then, non-virtual base initializers. for (; B != E && (*B)->isBaseInitializer(); B++) { assert(!(*B)->isBaseVirtual()); - + SaveAndRestore ThisRAII(CXXThisValue); if (CGM.getCodeGenOpts().StrictVTablePointers && CGM.getCodeGenOpts().OptimizationLevel > 0 && isInitializerOfDynamicClass(*B)) @@ -1319,8 +1320,6 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, EmitBaseInitializer(*this, ClassDecl, *B); } - CXXThisValue = OldThis; - InitializeVTablePointers(ClassDecl); // And finally, initialize class members. diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 99b94588f56f0..4d4c94d008c9d 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -96,7 +96,6 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::FriendTemplate: case Decl::Block: case Decl::Captured: - case Decl::ClassScopeFunctionSpecialization: case Decl::UsingShadow: case Decl::ConstructorUsingShadow: case Decl::ObjCTypeParam: diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index d76ce15b41ac5..93ab064bdf391 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -3723,10 +3723,12 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF, // Explicitly handle GNU void* and function pointer arithmetic extensions. The // GNU void* casts amount to no-ops since our void* type is i8*, but this is // future proof. + llvm::Type *elemTy; if (elementType->isVoidType() || elementType->isFunctionType()) - return CGF.Builder.CreateGEP(CGF.Int8Ty, pointer, index, "add.ptr"); + elemTy = CGF.Int8Ty; + else + elemTy = CGF.ConvertTypeForMem(elementType); - llvm::Type *elemTy = CGF.ConvertTypeForMem(elementType); if (CGF.getLangOpts().isSignedOverflowDefined()) return CGF.Builder.CreateGEP(elemTy, pointer, index, "add.ptr"); diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index 93819ab815add..56de8d39fe856 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -551,10 +551,9 @@ CGOpenMPRuntimeGPU::getExecutionMode() const { return CurrentExecutionMode; } -static CGOpenMPRuntimeGPU::DataSharingMode -getDataSharingMode(CodeGenModule &CGM) { - return CGM.getLangOpts().OpenMPCUDAMode ? CGOpenMPRuntimeGPU::CUDA - : CGOpenMPRuntimeGPU::Generic; +CGOpenMPRuntimeGPU::DataSharingMode +CGOpenMPRuntimeGPU::getDataSharingMode() const { + return CurrentDataSharingMode; } /// Check for inner (nested) SPMD construct, if any @@ -752,6 +751,9 @@ void CGOpenMPRuntimeGPU::emitNonSPMDKernel(const OMPExecutableDirective &D, EntryFunctionState EST; WrapperFunctionsMap.clear(); + [[maybe_unused]] bool IsBareKernel = D.getSingleClause(); + assert(!IsBareKernel && "bare kernel should not be at generic mode"); + // Emit target region as a standalone region. class NVPTXPrePostActionTy : public PrePostActionTy { CGOpenMPRuntimeGPU::EntryFunctionState &EST; @@ -760,15 +762,13 @@ void CGOpenMPRuntimeGPU::emitNonSPMDKernel(const OMPExecutableDirective &D, NVPTXPrePostActionTy(CGOpenMPRuntimeGPU::EntryFunctionState &EST) : EST(EST) {} void Enter(CodeGenFunction &CGF) override { - auto &RT = - static_cast(CGF.CGM.getOpenMPRuntime()); + auto &RT = static_cast(CGF.CGM.getOpenMPRuntime()); RT.emitKernelInit(CGF, EST, /* IsSPMD */ false); // Skip target region initialization. RT.setLocThreadIdInsertPt(CGF, /*AtCurrentPoint=*/true); } void Exit(CodeGenFunction &CGF) override { - auto &RT = - static_cast(CGF.CGM.getOpenMPRuntime()); + auto &RT = static_cast(CGF.CGM.getOpenMPRuntime()); RT.clearLocThreadIdInsertPt(CGF); RT.emitKernelDeinit(CGF, EST, /* IsSPMD */ false); } @@ -807,25 +807,39 @@ void CGOpenMPRuntimeGPU::emitSPMDKernel(const OMPExecutableDirective &D, ExecutionRuntimeModesRAII ModeRAII(CurrentExecutionMode, EM_SPMD); EntryFunctionState EST; + bool IsBareKernel = D.getSingleClause(); + // Emit target region as a standalone region. class NVPTXPrePostActionTy : public PrePostActionTy { CGOpenMPRuntimeGPU &RT; CGOpenMPRuntimeGPU::EntryFunctionState &EST; + bool IsBareKernel; + DataSharingMode Mode; public: NVPTXPrePostActionTy(CGOpenMPRuntimeGPU &RT, - CGOpenMPRuntimeGPU::EntryFunctionState &EST) - : RT(RT), EST(EST) {} + CGOpenMPRuntimeGPU::EntryFunctionState &EST, + bool IsBareKernel) + : RT(RT), EST(EST), IsBareKernel(IsBareKernel), + Mode(RT.CurrentDataSharingMode) {} void Enter(CodeGenFunction &CGF) override { + if (IsBareKernel) { + RT.CurrentDataSharingMode = DataSharingMode::DS_CUDA; + return; + } RT.emitKernelInit(CGF, EST, /* IsSPMD */ true); // Skip target region initialization. RT.setLocThreadIdInsertPt(CGF, /*AtCurrentPoint=*/true); } void Exit(CodeGenFunction &CGF) override { + if (IsBareKernel) { + RT.CurrentDataSharingMode = Mode; + return; + } RT.clearLocThreadIdInsertPt(CGF); RT.emitKernelDeinit(CGF, EST, /* IsSPMD */ true); } - } Action(*this, EST); + } Action(*this, EST, IsBareKernel); CodeGen.setAction(Action); IsInTTDRegion = true; emitTargetOutlinedFunctionHelper(D, ParentName, OutlinedFn, OutlinedFnID, @@ -843,7 +857,8 @@ void CGOpenMPRuntimeGPU::emitTargetOutlinedFunction( assert(!ParentName.empty() && "Invalid target region parent name!"); bool Mode = supportsSPMDExecutionMode(CGM.getContext(), D); - if (Mode) + bool IsBareKernel = D.getSingleClause(); + if (Mode || IsBareKernel) emitSPMDKernel(D, ParentName, OutlinedFn, OutlinedFnID, IsOffloadEntry, CodeGen); else @@ -863,6 +878,9 @@ CGOpenMPRuntimeGPU::CGOpenMPRuntimeGPU(CodeGenModule &CGM) if (!CGM.getLangOpts().OpenMPIsTargetDevice) llvm_unreachable("OpenMP can only handle device code."); + if (CGM.getLangOpts().OpenMPCUDAMode) + CurrentDataSharingMode = CGOpenMPRuntimeGPU::DS_CUDA; + llvm::OpenMPIRBuilder &OMPBuilder = getOMPBuilder(); if (CGM.getLangOpts().NoGPULib || CGM.getLangOpts().OMPHostIRFile.empty()) return; @@ -1030,7 +1048,7 @@ llvm::Function *CGOpenMPRuntimeGPU::emitTeamsOutlinedFunction( void CGOpenMPRuntimeGPU::emitGenericVarsProlog(CodeGenFunction &CGF, SourceLocation Loc, bool WithSPMDCheck) { - if (getDataSharingMode(CGM) != CGOpenMPRuntimeGPU::Generic && + if (getDataSharingMode() != CGOpenMPRuntimeGPU::DS_Generic && getExecutionMode() != CGOpenMPRuntimeGPU::EM_SPMD) return; @@ -1142,7 +1160,7 @@ void CGOpenMPRuntimeGPU::getKmpcFreeShared( void CGOpenMPRuntimeGPU::emitGenericVarsEpilog(CodeGenFunction &CGF, bool WithSPMDCheck) { - if (getDataSharingMode(CGM) != CGOpenMPRuntimeGPU::Generic && + if (getDataSharingMode() != CGOpenMPRuntimeGPU::DS_Generic && getExecutionMode() != CGOpenMPRuntimeGPU::EM_SPMD) return; @@ -1178,11 +1196,18 @@ void CGOpenMPRuntimeGPU::emitTeamsCall(CodeGenFunction &CGF, if (!CGF.HaveInsertPoint()) return; + bool IsBareKernel = D.getSingleClause(); + Address ZeroAddr = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty, /*Name=*/".zero.addr"); CGF.Builder.CreateStore(CGF.Builder.getInt32(/*C*/ 0), ZeroAddr); llvm::SmallVector OutlinedFnArgs; - OutlinedFnArgs.push_back(emitThreadIDAddress(CGF, Loc).getPointer()); + // We don't emit any thread id function call in bare kernel, but because the + // outlined function has a pointer argument, we emit a nullptr here. + if (IsBareKernel) + OutlinedFnArgs.push_back(llvm::ConstantPointerNull::get(CGM.VoidPtrTy)); + else + OutlinedFnArgs.push_back(emitThreadIDAddress(CGF, Loc).getPointer()); OutlinedFnArgs.push_back(ZeroAddr.getPointer()); OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end()); emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs); @@ -3273,7 +3298,7 @@ llvm::Function *CGOpenMPRuntimeGPU::createParallelDataSharingWrapper( void CGOpenMPRuntimeGPU::emitFunctionProlog(CodeGenFunction &CGF, const Decl *D) { - if (getDataSharingMode(CGM) != CGOpenMPRuntimeGPU::Generic) + if (getDataSharingMode() != CGOpenMPRuntimeGPU::DS_Generic) return; assert(D && "Expected function or captured|block decl."); @@ -3382,7 +3407,7 @@ Address CGOpenMPRuntimeGPU::getAddressOfLocalVariable(CodeGenFunction &CGF, VarTy, Align); } - if (getDataSharingMode(CGM) != CGOpenMPRuntimeGPU::Generic) + if (getDataSharingMode() != CGOpenMPRuntimeGPU::DS_Generic) return Address::invalid(); VD = VD->getCanonicalDecl(); diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h index dddfe5a94dccb..86871dfce418f 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h @@ -32,6 +32,18 @@ class CGOpenMPRuntimeGPU : public CGOpenMPRuntime { /// Unknown execution mode (orphaned directive). EM_Unknown, }; + + /// Target codegen is specialized based on two data-sharing modes: CUDA, in + /// which the local variables are actually global threadlocal, and Generic, in + /// which the local variables are placed in global memory if they may escape + /// their declaration context. + enum DataSharingMode { + /// CUDA data sharing mode. + DS_CUDA, + /// Generic data-sharing mode. + DS_Generic, + }; + private: /// Parallel outlined function work for workers to execute. llvm::SmallVector Work; @@ -42,6 +54,8 @@ class CGOpenMPRuntimeGPU : public CGOpenMPRuntime { ExecutionMode getExecutionMode() const; + DataSharingMode getDataSharingMode() const; + /// Get barrier to synchronize all threads in a block. void syncCTAThreads(CodeGenFunction &CGF); @@ -297,17 +311,6 @@ class CGOpenMPRuntimeGPU : public CGOpenMPRuntime { Address getAddressOfLocalVariable(CodeGenFunction &CGF, const VarDecl *VD) override; - /// Target codegen is specialized based on two data-sharing modes: CUDA, in - /// which the local variables are actually global threadlocal, and Generic, in - /// which the local variables are placed in global memory if they may escape - /// their declaration context. - enum DataSharingMode { - /// CUDA data sharing mode. - CUDA, - /// Generic data-sharing mode. - Generic, - }; - /// Cleans up references to the objects in finished function. /// void functionFinished(CodeGenFunction &CGF) override; @@ -343,6 +346,10 @@ class CGOpenMPRuntimeGPU : public CGOpenMPRuntime { /// to emit optimized code. ExecutionMode CurrentExecutionMode = EM_Unknown; + /// Track the data sharing mode when codegening directives within a target + /// region. + DataSharingMode CurrentDataSharingMode = DataSharingMode::DS_Generic; + /// true if currently emitting code for target/teams/distribute region, false /// - otherwise. bool IsInTTDRegion = false; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 2dd7569198769..754377bed7f7e 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1390,9 +1390,24 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, } if (!D) return; + // Set visibility for definitions, and for declarations if requested globally // or set explicitly. LinkageInfo LV = D->getLinkageAndVisibility(); + + // OpenMP declare target variables must be visible to the host so they can + // be registered. We require protected visibility unless the variable has + // the DT_nohost modifier and does not need to be registered. + if (Context.getLangOpts().OpenMP && + Context.getLangOpts().OpenMPIsTargetDevice && isa(D) && + D->hasAttr() && + D->getAttr()->getDevType() != + OMPDeclareTargetDeclAttr::DT_NoHost && + LV.getVisibility() == HiddenVisibility) { + GV->setVisibility(llvm::GlobalValue::ProtectedVisibility); + return; + } + if (GV->hasDLLExportStorageClass() || GV->hasDLLImportStorageClass()) { // Reject incompatible dlllstorage and visibility annotations. if (!LV.isVisibilityExplicit()) @@ -3834,6 +3849,9 @@ bool CodeGenModule::shouldEmitFunction(GlobalDecl GD) { if (CodeGenOpts.OptimizationLevel == 0 && !F->hasAttr()) return false; + if (F->hasAttr()) + return false; + if (F->hasAttr() && !F->hasAttr()) { // Check whether it would be safe to inline this dllimport function. DLLImportFunctionVisitor Visitor; @@ -4790,7 +4808,8 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty, assert(getContext().getTargetAddressSpace(ExpectedAS) == TargetAS); if (DAddrSpace != ExpectedAS) { return getTargetCodeGenInfo().performAddrSpaceCast( - *this, GV, DAddrSpace, ExpectedAS, Ty->getPointerTo(TargetAS)); + *this, GV, DAddrSpace, ExpectedAS, + llvm::PointerType::get(getLLVMContext(), TargetAS)); } return GV; @@ -5002,7 +5021,8 @@ castStringLiteralToDefaultAddressSpace(CodeGenModule &CGM, if (AS != LangAS::Default) Cast = CGM.getTargetCodeGenInfo().performAddrSpaceCast( CGM, GV, AS, LangAS::Default, - GV->getValueType()->getPointerTo( + llvm::PointerType::get( + CGM.getLLVMContext(), CGM.getContext().getTargetAddressSpace(LangAS::Default))); } return Cast; @@ -6377,7 +6397,8 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary( if (AddrSpace != LangAS::Default) CV = getTargetCodeGenInfo().performAddrSpaceCast( *this, GV, AddrSpace, LangAS::Default, - Type->getPointerTo( + llvm::PointerType::get( + getLLVMContext(), getContext().getTargetAddressSpace(LangAS::Default))); // Update the map with the new temporary. If we created a placeholder above, diff --git a/clang/lib/CodeGen/Targets/AMDGPU.cpp b/clang/lib/CodeGen/Targets/AMDGPU.cpp index dc628b7345f59..f6a614b3e4d54 100644 --- a/clang/lib/CodeGen/Targets/AMDGPU.cpp +++ b/clang/lib/CodeGen/Targets/AMDGPU.cpp @@ -308,12 +308,13 @@ static bool requiresAMDGPUProtectedVisibility(const Decl *D, if (GV->getVisibility() != llvm::GlobalValue::HiddenVisibility) return false; - return D->hasAttr() || - (isa(D) && D->hasAttr()) || - (isa(D) && - (D->hasAttr() || D->hasAttr() || - cast(D)->getType()->isCUDADeviceBuiltinSurfaceType() || - cast(D)->getType()->isCUDADeviceBuiltinTextureType())); + return !D->hasAttr() && + (D->hasAttr() || + (isa(D) && D->hasAttr()) || + (isa(D) && + (D->hasAttr() || D->hasAttr() || + cast(D)->getType()->isCUDADeviceBuiltinSurfaceType() || + cast(D)->getType()->isCUDADeviceBuiltinTextureType()))); } void AMDGPUTargetCodeGenInfo::setFunctionDeclAttributes( diff --git a/clang/lib/Driver/OffloadBundler.cpp b/clang/lib/Driver/OffloadBundler.cpp index d11c41605bf39..0ad9de299603b 100644 --- a/clang/lib/Driver/OffloadBundler.cpp +++ b/clang/lib/Driver/OffloadBundler.cpp @@ -21,24 +21,29 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/Binary.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Debug.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/MD5.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" #include "llvm/Support/StringSaver.h" +#include "llvm/Support/Timer.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/Host.h" @@ -48,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +64,10 @@ using namespace llvm; using namespace llvm::object; using namespace clang; +static llvm::TimerGroup + ClangOffloadBundlerTimerGroup("Clang Offload Bundler Timer Group", + "Timer group for clang offload bundler"); + /// Magic string that marks the existence of offloading data. #define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__" @@ -224,20 +234,22 @@ class FileHandler { /// Write the header of the bundled file to \a OS based on the information /// gathered from \a Inputs. - virtual Error WriteHeader(raw_fd_ostream &OS, + virtual Error WriteHeader(raw_ostream &OS, ArrayRef> Inputs) = 0; /// Write the marker that initiates a bundle for the triple \a TargetTriple to /// \a OS. - virtual Error WriteBundleStart(raw_fd_ostream &OS, - StringRef TargetTriple) = 0; + virtual Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) = 0; /// Write the marker that closes a bundle for the triple \a TargetTriple to \a /// OS. - virtual Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) = 0; + virtual Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) = 0; /// Write the bundle from \a Input into \a OS. - virtual Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0; + virtual Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) = 0; + + /// Finalize output file. + virtual Error finalizeOutputFile() { return Error::success(); } /// List bundle IDs in \a Input. virtual Error listBundleIDs(MemoryBuffer &Input) { @@ -311,7 +323,7 @@ static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer, size_t pos) { } /// Write 8-byte integers to a buffer in little-endian format. -static void Write8byteIntegerToBuffer(raw_fd_ostream &OS, uint64_t Val) { +static void Write8byteIntegerToBuffer(raw_ostream &OS, uint64_t Val) { llvm::support::endian::write(OS, Val, llvm::support::little); } @@ -359,8 +371,7 @@ class BinaryFileHandler final : public FileHandler { return Error::success(); // Check if no magic was found. - StringRef Magic(FC.data(), sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1); - if (!Magic.equals(OFFLOAD_BUNDLER_MAGIC_STR)) + if (llvm::identify_magic(FC) != llvm::file_magic::offload_bundle) return Error::success(); // Read number of bundles. @@ -435,7 +446,7 @@ class BinaryFileHandler final : public FileHandler { return Error::success(); } - Error WriteHeader(raw_fd_ostream &OS, + Error WriteHeader(raw_ostream &OS, ArrayRef> Inputs) final { // Compute size of the header. @@ -472,19 +483,27 @@ class BinaryFileHandler final : public FileHandler { return Error::success(); } - Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final { + Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) final { CurWriteBundleTarget = TargetTriple.str(); return Error::success(); } - Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final { + Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) final { return Error::success(); } - Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final { + Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) final { auto BI = BundlesInfo[CurWriteBundleTarget]; - OS.seek(BI.Offset); + + // Pad with 0 to reach specified offset. + size_t CurrentPos = OS.tell(); + size_t PaddingSize = BI.Offset > CurrentPos ? BI.Offset - CurrentPos : 0; + for (size_t I = 0; I < PaddingSize; ++I) + OS.write('\0'); + assert(OS.tell() == BI.Offset); + OS.write(Input.getBufferStart(), Input.getBufferSize()); + return Error::success(); } }; @@ -541,7 +560,7 @@ class ObjectFileHandler final : public FileHandler { return NameOrErr.takeError(); // If it does not start with the reserved suffix, just skip this section. - if (!NameOrErr->startswith(OFFLOAD_BUNDLER_MAGIC_STR)) + if (llvm::identify_magic(*NameOrErr) != llvm::file_magic::offload_bundle) return std::nullopt; // Return the triple that is right after the reserved prefix. @@ -607,7 +626,7 @@ class ObjectFileHandler final : public FileHandler { return Error::success(); } - Error WriteHeader(raw_fd_ostream &OS, + Error WriteHeader(raw_ostream &OS, ArrayRef> Inputs) final { assert(BundlerConfig.HostInputIndex != ~0u && "Host input index not defined."); @@ -617,12 +636,16 @@ class ObjectFileHandler final : public FileHandler { return Error::success(); } - Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final { + Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) final { ++NumberOfProcessedInputs; return Error::success(); } - Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final { + Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) final { + return Error::success(); + } + + Error finalizeOutputFile() final { assert(NumberOfProcessedInputs <= NumberOfInputs && "Processing more inputs that actually exist!"); assert(BundlerConfig.HostInputIndex != ~0u && @@ -640,10 +663,6 @@ class ObjectFileHandler final : public FileHandler { assert(BundlerConfig.ObjcopyPath != "" && "llvm-objcopy path not specified"); - // We write to the output file directly. So, we close it and use the name - // to pass down to llvm-objcopy. - OS.close(); - // Temporary files that need to be removed. TempFileHandlerRAII TempFiles; @@ -684,7 +703,7 @@ class ObjectFileHandler final : public FileHandler { return Error::success(); } - Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final { + Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) final { return Error::success(); } @@ -781,22 +800,22 @@ class TextFileHandler final : public FileHandler { return Error::success(); } - Error WriteHeader(raw_fd_ostream &OS, + Error WriteHeader(raw_ostream &OS, ArrayRef> Inputs) final { return Error::success(); } - Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final { + Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) final { OS << BundleStartString << TargetTriple << "\n"; return Error::success(); } - Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final { + Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) final { OS << BundleEndString << TargetTriple << "\n"; return Error::success(); } - Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final { + Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) final { OS << Input.getBuffer(); return Error::success(); } @@ -881,6 +900,187 @@ CreateFileHandler(MemoryBuffer &FirstInput, "'" + FilesType + "': invalid file type specified"); } +OffloadBundlerConfig::OffloadBundlerConfig() { + auto IgnoreEnvVarOpt = + llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_IGNORE_ENV_VAR"); + if (IgnoreEnvVarOpt.has_value() && IgnoreEnvVarOpt.value() == "1") + return; + + auto VerboseEnvVarOpt = llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_VERBOSE"); + if (VerboseEnvVarOpt.has_value()) + Verbose = VerboseEnvVarOpt.value() == "1"; + + auto CompressEnvVarOpt = + llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_COMPRESS"); + if (CompressEnvVarOpt.has_value()) + Compress = CompressEnvVarOpt.value() == "1"; +} + +llvm::Expected> +CompressedOffloadBundle::compress(const llvm::MemoryBuffer &Input, + bool Verbose) { + llvm::Timer HashTimer("Hash Calculation Timer", "Hash calculation time", + ClangOffloadBundlerTimerGroup); + if (Verbose) + HashTimer.startTimer(); + llvm::MD5 Hash; + llvm::MD5::MD5Result Result; + Hash.update(Input.getBuffer()); + Hash.final(Result); + uint64_t TruncatedHash = Result.low(); + if (Verbose) + HashTimer.stopTimer(); + + SmallVector CompressedBuffer; + auto BufferUint8 = llvm::ArrayRef( + reinterpret_cast(Input.getBuffer().data()), + Input.getBuffer().size()); + + llvm::compression::Format CompressionFormat; + + if (llvm::compression::zstd::isAvailable()) + CompressionFormat = llvm::compression::Format::Zstd; + else if (llvm::compression::zlib::isAvailable()) + CompressionFormat = llvm::compression::Format::Zlib; + else + return createStringError(llvm::inconvertibleErrorCode(), + "Compression not supported"); + + llvm::Timer CompressTimer("Compression Timer", "Compression time", + ClangOffloadBundlerTimerGroup); + if (Verbose) + CompressTimer.startTimer(); + llvm::compression::compress(CompressionFormat, BufferUint8, CompressedBuffer); + if (Verbose) + CompressTimer.stopTimer(); + + uint16_t CompressionMethod = static_cast(CompressionFormat); + uint32_t UncompressedSize = Input.getBuffer().size(); + + SmallVector FinalBuffer; + llvm::raw_svector_ostream OS(FinalBuffer); + OS << MagicNumber; + OS.write(reinterpret_cast(&Version), sizeof(Version)); + OS.write(reinterpret_cast(&CompressionMethod), + sizeof(CompressionMethod)); + OS.write(reinterpret_cast(&UncompressedSize), + sizeof(UncompressedSize)); + OS.write(reinterpret_cast(&TruncatedHash), + sizeof(TruncatedHash)); + OS.write(reinterpret_cast(CompressedBuffer.data()), + CompressedBuffer.size()); + + if (Verbose) { + auto MethodUsed = + CompressionFormat == llvm::compression::Format::Zstd ? "zstd" : "zlib"; + llvm::errs() << "Compressed bundle format version: " << Version << "\n" + << "Compression method used: " << MethodUsed << "\n" + << "Binary size before compression: " << UncompressedSize + << " bytes\n" + << "Binary size after compression: " << CompressedBuffer.size() + << " bytes\n" + << "Truncated MD5 hash: " + << llvm::format_hex(TruncatedHash, 16) << "\n"; + } + + return llvm::MemoryBuffer::getMemBufferCopy( + llvm::StringRef(FinalBuffer.data(), FinalBuffer.size())); +} + +llvm::Expected> +CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input, + bool Verbose) { + + StringRef Blob = Input.getBuffer(); + + if (Blob.size() < HeaderSize) { + return llvm::MemoryBuffer::getMemBufferCopy(Blob); + } + if (llvm::identify_magic(Blob) != + llvm::file_magic::offload_bundle_compressed) { + if (Verbose) + llvm::errs() << "Uncompressed bundle.\n"; + return llvm::MemoryBuffer::getMemBufferCopy(Blob); + } + + uint16_t ThisVersion; + uint16_t CompressionMethod; + uint32_t UncompressedSize; + uint64_t StoredHash; + memcpy(&ThisVersion, Input.getBuffer().data() + MagicNumber.size(), + sizeof(uint16_t)); + memcpy(&CompressionMethod, Blob.data() + MagicSize + VersionFieldSize, + sizeof(uint16_t)); + memcpy(&UncompressedSize, + Blob.data() + MagicSize + VersionFieldSize + MethodFieldSize, + sizeof(uint32_t)); + memcpy(&StoredHash, + Blob.data() + MagicSize + VersionFieldSize + MethodFieldSize + + SizeFieldSize, + sizeof(uint64_t)); + + llvm::compression::Format CompressionFormat; + if (CompressionMethod == + static_cast(llvm::compression::Format::Zlib)) + CompressionFormat = llvm::compression::Format::Zlib; + else if (CompressionMethod == + static_cast(llvm::compression::Format::Zstd)) + CompressionFormat = llvm::compression::Format::Zstd; + else + return createStringError(inconvertibleErrorCode(), + "Unknown compressing method"); + + llvm::Timer DecompressTimer("Decompression Timer", "Decompression time", + ClangOffloadBundlerTimerGroup); + if (Verbose) + DecompressTimer.startTimer(); + + SmallVector DecompressedData; + StringRef CompressedData = Blob.substr(HeaderSize); + if (llvm::Error DecompressionError = llvm::compression::decompress( + CompressionFormat, llvm::arrayRefFromStringRef(CompressedData), + DecompressedData, UncompressedSize)) + return createStringError(inconvertibleErrorCode(), + "Could not decompress embedded file contents: " + + llvm::toString(std::move(DecompressionError))); + + if (Verbose) { + DecompressTimer.stopTimer(); + + // Recalculate MD5 hash + llvm::Timer HashRecalcTimer("Hash Recalculation Timer", + "Hash recalculation time", + ClangOffloadBundlerTimerGroup); + HashRecalcTimer.startTimer(); + llvm::MD5 Hash; + llvm::MD5::MD5Result Result; + Hash.update(llvm::ArrayRef(DecompressedData.data(), + DecompressedData.size())); + Hash.final(Result); + uint64_t RecalculatedHash = Result.low(); + HashRecalcTimer.stopTimer(); + bool HashMatch = (StoredHash == RecalculatedHash); + + llvm::errs() << "Compressed bundle format version: " << ThisVersion << "\n" + << "Decompression method: " + << (CompressionFormat == llvm::compression::Format::Zlib + ? "zlib" + : "zstd") + << "\n" + << "Size before decompression: " << CompressedData.size() + << " bytes\n" + << "Size after decompression: " << UncompressedSize + << " bytes\n" + << "Stored hash: " << llvm::format_hex(StoredHash, 16) << "\n" + << "Recalculated hash: " + << llvm::format_hex(RecalculatedHash, 16) << "\n" + << "Hashes match: " << (HashMatch ? "Yes" : "No") << "\n"; + } + + return llvm::MemoryBuffer::getMemBufferCopy( + llvm::toStringRef(DecompressedData)); +} + // List bundle IDs. Return true if an error was found. Error OffloadBundler::ListBundleIDsInFile( StringRef InputFileName, const OffloadBundlerConfig &BundlerConfig) { @@ -890,28 +1090,35 @@ Error OffloadBundler::ListBundleIDsInFile( if (std::error_code EC = CodeOrErr.getError()) return createFileError(InputFileName, EC); - MemoryBuffer &Input = **CodeOrErr; + // Decompress the input if necessary. + Expected> DecompressedBufferOrErr = + CompressedOffloadBundle::decompress(**CodeOrErr, BundlerConfig.Verbose); + if (!DecompressedBufferOrErr) + return createStringError( + inconvertibleErrorCode(), + "Failed to decompress input: " + + llvm::toString(DecompressedBufferOrErr.takeError())); + + MemoryBuffer &DecompressedInput = **DecompressedBufferOrErr; // Select the right files handler. Expected> FileHandlerOrErr = - CreateFileHandler(Input, BundlerConfig); + CreateFileHandler(DecompressedInput, BundlerConfig); if (!FileHandlerOrErr) return FileHandlerOrErr.takeError(); std::unique_ptr &FH = *FileHandlerOrErr; assert(FH); - return FH->listBundleIDs(Input); + return FH->listBundleIDs(DecompressedInput); } /// Bundle the files. Return true if an error was found. Error OffloadBundler::BundleFiles() { std::error_code EC; - // Create output file. - raw_fd_ostream OutputFile(BundlerConfig.OutputFileNames.front(), EC, - sys::fs::OF_None); - if (EC) - return createFileError(BundlerConfig.OutputFileNames.front(), EC); + // Create a buffer to hold the content before compressing. + SmallVector Buffer; + llvm::raw_svector_ostream BufferStream(Buffer); // Open input files. SmallVector, 8u> InputBuffers; @@ -938,22 +1145,46 @@ Error OffloadBundler::BundleFiles() { assert(FH); // Write header. - if (Error Err = FH->WriteHeader(OutputFile, InputBuffers)) + if (Error Err = FH->WriteHeader(BufferStream, InputBuffers)) return Err; // Write all bundles along with the start/end markers. If an error was found // writing the end of the bundle component, abort the bundle writing. auto Input = InputBuffers.begin(); for (auto &Triple : BundlerConfig.TargetNames) { - if (Error Err = FH->WriteBundleStart(OutputFile, Triple)) + if (Error Err = FH->WriteBundleStart(BufferStream, Triple)) return Err; - if (Error Err = FH->WriteBundle(OutputFile, **Input)) + if (Error Err = FH->WriteBundle(BufferStream, **Input)) return Err; - if (Error Err = FH->WriteBundleEnd(OutputFile, Triple)) + if (Error Err = FH->WriteBundleEnd(BufferStream, Triple)) return Err; ++Input; } - return Error::success(); + + raw_fd_ostream OutputFile(BundlerConfig.OutputFileNames.front(), EC, + sys::fs::OF_None); + if (EC) + return createFileError(BundlerConfig.OutputFileNames.front(), EC); + + SmallVector CompressedBuffer; + if (BundlerConfig.Compress) { + std::unique_ptr BufferMemory = + llvm::MemoryBuffer::getMemBufferCopy( + llvm::StringRef(Buffer.data(), Buffer.size())); + auto CompressionResult = + CompressedOffloadBundle::compress(*BufferMemory, BundlerConfig.Verbose); + if (auto Error = CompressionResult.takeError()) + return Error; + + auto CompressedMemBuffer = std::move(CompressionResult.get()); + CompressedBuffer.assign(CompressedMemBuffer->getBufferStart(), + CompressedMemBuffer->getBufferEnd()); + } else + CompressedBuffer = Buffer; + + OutputFile.write(CompressedBuffer.data(), CompressedBuffer.size()); + + return FH->finalizeOutputFile(); } // Unbundle the files. Return true if an error was found. @@ -964,7 +1195,16 @@ Error OffloadBundler::UnbundleFiles() { if (std::error_code EC = CodeOrErr.getError()) return createFileError(BundlerConfig.InputFileNames.front(), EC); - MemoryBuffer &Input = **CodeOrErr; + // Decompress the input if necessary. + Expected> DecompressedBufferOrErr = + CompressedOffloadBundle::decompress(**CodeOrErr, BundlerConfig.Verbose); + if (!DecompressedBufferOrErr) + return createStringError( + inconvertibleErrorCode(), + "Failed to decompress input: " + + llvm::toString(DecompressedBufferOrErr.takeError())); + + MemoryBuffer &Input = **DecompressedBufferOrErr; // Select the right files handler. Expected> FileHandlerOrErr = @@ -1169,11 +1409,23 @@ Error OffloadBundler::UnbundleArchive() { if (!CodeObjectBufferRefOrErr) return CodeObjectBufferRefOrErr.takeError(); - auto CodeObjectBuffer = + auto TempCodeObjectBuffer = MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr, false); + // Decompress the buffer if necessary. + Expected> DecompressedBufferOrErr = + CompressedOffloadBundle::decompress(*TempCodeObjectBuffer, + BundlerConfig.Verbose); + if (!DecompressedBufferOrErr) + return createStringError( + inconvertibleErrorCode(), + "Failed to decompress code object: " + + llvm::toString(DecompressedBufferOrErr.takeError())); + + MemoryBuffer &CodeObjectBuffer = **DecompressedBufferOrErr; + Expected> FileHandlerOrErr = - CreateFileHandler(*CodeObjectBuffer, BundlerConfig); + CreateFileHandler(CodeObjectBuffer, BundlerConfig); if (!FileHandlerOrErr) return FileHandlerOrErr.takeError(); @@ -1181,11 +1433,11 @@ Error OffloadBundler::UnbundleArchive() { assert(FileHandler && "FileHandle creation failed for file in the archive!"); - if (Error ReadErr = FileHandler->ReadHeader(*CodeObjectBuffer)) + if (Error ReadErr = FileHandler->ReadHeader(CodeObjectBuffer)) return ReadErr; Expected> CurBundleIDOrErr = - FileHandler->ReadBundleStart(*CodeObjectBuffer); + FileHandler->ReadBundleStart(CodeObjectBuffer); if (!CurBundleIDOrErr) return CurBundleIDOrErr.takeError(); @@ -1206,7 +1458,7 @@ Error OffloadBundler::UnbundleArchive() { BundlerConfig)) { std::string BundleData; raw_string_ostream DataStream(BundleData); - if (Error Err = FileHandler->ReadBundle(DataStream, *CodeObjectBuffer)) + if (Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer)) return Err; for (auto &CompatibleTarget : CompatibleTargets) { @@ -1244,11 +1496,11 @@ Error OffloadBundler::UnbundleArchive() { } } - if (Error Err = FileHandler->ReadBundleEnd(*CodeObjectBuffer)) + if (Error Err = FileHandler->ReadBundleEnd(CodeObjectBuffer)) return Err; Expected> NextTripleOrErr = - FileHandler->ReadBundleStart(*CodeObjectBuffer); + FileHandler->ReadBundleStart(CodeObjectBuffer); if (!NextTripleOrErr) return NextTripleOrErr.takeError(); diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp index bb66db5feae8c..8e1cff0b443ee 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -404,6 +404,7 @@ arm::FloatABI arm::getDefaultFloatABI(const llvm::Triple &Triple) { } break; + case llvm::Triple::Haiku: case llvm::Triple::OpenBSD: return FloatABI::SoftFP; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 129adfb9fcc74..bfd6c5c2864ab 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -68,7 +68,9 @@ using namespace llvm::opt; static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { if (Arg *A = Args.getLastArg(clang::driver::options::OPT_C, options::OPT_CC, options::OPT_fminimize_whitespace, - options::OPT_fno_minimize_whitespace)) { + options::OPT_fno_minimize_whitespace, + options::OPT_fkeep_system_includes, + options::OPT_fno_keep_system_includes)) { if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_P) && !Args.hasArg(options::OPT__SLASH_EP) && !D.CCCIsCPP()) { D.Diag(clang::diag::err_drv_argument_only_allowed_with) @@ -5150,9 +5152,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, const bool IsAssertBuild = true; #endif - // Disable the verification pass in -asserts builds. - if (!IsAssertBuild) + // Disable the verification pass in asserts builds unless otherwise specified. + if (Args.hasFlag(options::OPT_fno_verify_intermediate_code, + options::OPT_fverify_intermediate_code, !IsAssertBuild)) { CmdArgs.push_back("-disable-llvm-verifier"); + } // Discard value names in assert builds unless otherwise specified. if (Args.hasFlag(options::OPT_fdiscard_value_names, @@ -6715,11 +6719,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_minimize_whitespace, false)) { types::ID InputType = Inputs[0].getType(); if (!isDerivedFromC(InputType)) - D.Diag(diag::err_drv_minws_unsupported_input_type) - << types::getTypeName(InputType); + D.Diag(diag::err_drv_opt_unsupported_input_type) + << "-fminimize-whitespace" << types::getTypeName(InputType); CmdArgs.push_back("-fminimize-whitespace"); } + // -fno-keep-system-includes is default. + if (Args.hasFlag(options::OPT_fkeep_system_includes, + options::OPT_fno_keep_system_includes, false)) { + types::ID InputType = Inputs[0].getType(); + if (!isDerivedFromC(InputType)) + D.Diag(diag::err_drv_opt_unsupported_input_type) + << "-fkeep-system-includes" << types::getTypeName(InputType); + CmdArgs.push_back("-fkeep-system-includes"); + } + // -fms-extensions=0 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, IsWindowsMSVC)) @@ -8470,6 +8484,11 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, } CmdArgs.push_back(TCArgs.MakeArgString(UB)); } + if (TCArgs.hasFlag(options::OPT_offload_compress, + options::OPT_no_offload_compress, false)) + CmdArgs.push_back("-compress"); + if (TCArgs.hasArg(options::OPT_v)) + CmdArgs.push_back("-verbose"); // All the inputs are encoded as commands. C.addCommand(std::make_unique( JA, *this, ResponseFileSupport::None(), @@ -8553,6 +8572,8 @@ void OffloadBundler::ConstructJobMultipleOutputs( } CmdArgs.push_back("-unbundle"); CmdArgs.push_back("-allow-missing-bundles"); + if (TCArgs.hasArg(options::OPT_v)) + CmdArgs.push_back("-verbose"); // All the inputs are encoded as commands. C.addCommand(std::make_unique( diff --git a/clang/lib/Driver/ToolChains/HIPUtility.cpp b/clang/lib/Driver/ToolChains/HIPUtility.cpp index 8b9d8db90ffab..04efdcba20ea7 100644 --- a/clang/lib/Driver/ToolChains/HIPUtility.cpp +++ b/clang/lib/Driver/ToolChains/HIPUtility.cpp @@ -84,6 +84,12 @@ void HIP::constructHIPFatbinCommand(Compilation &C, const JobAction &JA, Args.MakeArgString(std::string("-output=").append(Output)); BundlerArgs.push_back(BundlerOutputArg); + if (Args.hasFlag(options::OPT_offload_compress, + options::OPT_no_offload_compress, false)) + BundlerArgs.push_back("-compress"); + if (Args.hasArg(options::OPT_v)) + BundlerArgs.push_back("-verbose"); + const char *Bundler = Args.MakeArgString( T.getToolChain().GetProgramPath("clang-offload-bundler")); C.addCommand(std::make_unique( diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 5872e13bda358..d3d829a8ddbdb 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -709,6 +709,8 @@ void toolchains::MinGW::addClangTargetOptions( } } + CC1Args.push_back("-fno-use-init-array"); + for (auto Opt : {options::OPT_mthreads, options::OPT_mwindows, options::OPT_mconsole, options::OPT_mdll}) { if (Arg *A = DriverArgs.getLastArgNoClaim(Opt)) diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 8a34b4d9431b6..7b0ebe2cf621b 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -3914,7 +3914,7 @@ llvm::Expected getStyle(StringRef StyleName, StringRef FileName, FormatStyle FallbackStyle = getNoStyle(); if (!getPredefinedStyle(FallbackStyleName, Style.Language, &FallbackStyle)) - return make_string_error("Invalid fallback style \"" + FallbackStyleName); + return make_string_error("Invalid fallback style: " + FallbackStyleName); llvm::SmallVector, 1> ChildFormatTextToApply; diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 5877b0a612474..527f1d744a580 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -42,6 +42,7 @@ namespace format { TYPE(CaseLabelColon) \ TYPE(CastRParen) \ TYPE(ClassLBrace) \ + TYPE(ClassRBrace) \ /* ternary ?: expression */ \ TYPE(ConditionalExpr) \ /* the condition in an if statement */ \ @@ -67,6 +68,7 @@ namespace format { TYPE(DictLiteral) \ TYPE(ElseLBrace) \ TYPE(EnumLBrace) \ + TYPE(EnumRBrace) \ TYPE(FatArrow) \ TYPE(ForEachMacro) \ TYPE(FunctionAnnotationRParen) \ @@ -125,6 +127,7 @@ namespace format { TYPE(PureVirtualSpecifier) \ TYPE(RangeBasedForLoopColon) \ TYPE(RecordLBrace) \ + TYPE(RecordRBrace) \ TYPE(RegexLiteral) \ TYPE(RequiresClause) \ TYPE(RequiresClauseInARequiresExpression) \ @@ -141,6 +144,7 @@ namespace format { * braces need to be added to split it. Not used for other languages. */ \ TYPE(StringInConcatenation) \ TYPE(StructLBrace) \ + TYPE(StructRBrace) \ TYPE(StructuredBindingLSquare) \ TYPE(TemplateCloser) \ TYPE(TemplateOpener) \ @@ -153,6 +157,7 @@ namespace format { TYPE(TypenameMacro) \ TYPE(UnaryOperator) \ TYPE(UnionLBrace) \ + TYPE(UnionRBrace) \ TYPE(UntouchableMacroFunc) \ /* Like in 'assign x = 0, y = 1;' . */ \ TYPE(VerilogAssignComma) \ diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 6f879006465ec..543c119620bf2 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1414,10 +1414,6 @@ class AnnotatingParser { Tok->setType(TT_TrailingReturnArrow); } break; - case tok::eof: - if (Style.InsertNewlineAtEOF && Tok->NewlinesBefore == 0) - Tok->NewlinesBefore = 1; - break; default: break; } @@ -3244,8 +3240,14 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) { else if (Line.startsWith(TT_ObjCProperty)) Line.Type = LT_ObjCProperty; - Line.First->SpacesRequiredBefore = 1; - Line.First->CanBreakBefore = Line.First->MustBreakBefore; + auto *First = Line.First; + First->SpacesRequiredBefore = 1; + First->CanBreakBefore = First->MustBreakBefore; + + if (First->is(tok::eof) && First->NewlinesBefore == 0 && + Style.InsertNewlineAtEOF) { + First->NewlinesBefore = 1; + } } // This function heuristically determines whether 'Current' starts the name of a diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index dda5fd077e590..3275d7b6a71aa 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -3713,6 +3713,10 @@ bool UnwrappedLineParser::parseEnum() { nextToken(); addUnwrappedLine(); } + if (auto Prev = FormatTok->getPreviousNonComment(); + Prev && Prev->is(tok::r_brace)) { + Prev->setFinalizedType(TT_EnumRBrace); + } return true; // There is no addUnwrappedLine() here so that we fall through to parsing a @@ -3920,21 +3924,23 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { } while (!eof()); } - auto GetBraceType = [](const FormatToken &RecordTok) { + auto GetBraceTypes = + [](const FormatToken &RecordTok) -> std::pair { switch (RecordTok.Tok.getKind()) { case tok::kw_class: - return TT_ClassLBrace; + return {TT_ClassLBrace, TT_ClassRBrace}; case tok::kw_struct: - return TT_StructLBrace; + return {TT_StructLBrace, TT_StructRBrace}; case tok::kw_union: - return TT_UnionLBrace; + return {TT_UnionLBrace, TT_UnionRBrace}; default: // Useful for e.g. interface. - return TT_RecordLBrace; + return {TT_RecordLBrace, TT_RecordRBrace}; } }; if (FormatTok->is(tok::l_brace)) { - FormatTok->setFinalizedType(GetBraceType(InitialToken)); + auto [OpenBraceType, ClosingBraceType] = GetBraceTypes(InitialToken); + FormatTok->setFinalizedType(OpenBraceType); if (ParseAsExpr) { parseChildBlock(); } else { @@ -3944,6 +3950,10 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { unsigned AddLevels = Style.IndentAccessModifiers ? 2u : 1u; parseBlock(/*MustBeDeclaration=*/true, AddLevels, /*MunchSemi=*/false); } + if (auto Prev = FormatTok->getPreviousNonComment(); + Prev && Prev->is(tok::r_brace)) { + Prev->setFinalizedType(ClosingBraceType); + } } // There is no addUnwrappedLine() here so that we fall through to parsing a // structural element afterwards. Thus, in "class A {} n, m;", diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index 9061e07add545..dc81060671c17 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -307,8 +307,9 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, SmallVector ScopeStack; for (unsigned i = Start; i != End; ++i) { + auto &CurrentChange = Changes[i]; if (ScopeStack.size() != 0 && - Changes[i].indentAndNestingLevel() < + CurrentChange.indentAndNestingLevel() < Changes[ScopeStack.back()].indentAndNestingLevel()) { ScopeStack.pop_back(); } @@ -320,18 +321,18 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, Changes[PreviousNonComment].Tok->is(tok::comment)) { --PreviousNonComment; } - if (i != Start && Changes[i].indentAndNestingLevel() > + if (i != Start && CurrentChange.indentAndNestingLevel() > Changes[PreviousNonComment].indentAndNestingLevel()) { ScopeStack.push_back(i); } bool InsideNestedScope = ScopeStack.size() != 0; bool ContinuedStringLiteral = i > Start && - Changes[i].Tok->is(tok::string_literal) && + CurrentChange.Tok->is(tok::string_literal) && Changes[i - 1].Tok->is(tok::string_literal); bool SkipMatchCheck = InsideNestedScope || ContinuedStringLiteral; - if (Changes[i].NewlinesBefore > 0 && !SkipMatchCheck) { + if (CurrentChange.NewlinesBefore > 0 && !SkipMatchCheck) { Shift = 0; FoundMatchOnLine = false; } @@ -339,23 +340,26 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, // If this is the first matching token to be aligned, remember by how many // spaces it has to be shifted, so the rest of the changes on the line are // shifted by the same amount - if (!FoundMatchOnLine && !SkipMatchCheck && Matches(Changes[i])) { + if (!FoundMatchOnLine && !SkipMatchCheck && Matches(CurrentChange)) { FoundMatchOnLine = true; - Shift = Column - (RightJustify ? Changes[i].TokenLength : 0) - - Changes[i].StartOfTokenColumn; - Changes[i].Spaces += Shift; + Shift = Column - (RightJustify ? CurrentChange.TokenLength : 0) - + CurrentChange.StartOfTokenColumn; + CurrentChange.Spaces += Shift; // FIXME: This is a workaround that should be removed when we fix // http://llvm.org/PR53699. An assertion later below verifies this. - if (Changes[i].NewlinesBefore == 0) { - Changes[i].Spaces = - std::max(Changes[i].Spaces, - static_cast(Changes[i].Tok->SpacesRequiredBefore)); + if (CurrentChange.NewlinesBefore == 0) { + CurrentChange.Spaces = + std::max(CurrentChange.Spaces, + static_cast(CurrentChange.Tok->SpacesRequiredBefore)); } } + if (Shift == 0) + continue; + // This is for function parameters that are split across multiple lines, // as mentioned in the ScopeStack comment. - if (InsideNestedScope && Changes[i].NewlinesBefore > 0) { + if (InsideNestedScope && CurrentChange.NewlinesBefore > 0) { unsigned ScopeStart = ScopeStack.back(); auto ShouldShiftBeAdded = [&] { // Function declaration @@ -378,30 +382,30 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, TT_TemplateCloser) && Changes[ScopeStart - 1].Tok->is(tok::l_paren) && Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)) { - if (Changes[i].Tok->MatchingParen && - Changes[i].Tok->MatchingParen->is(TT_LambdaLBrace)) { + if (CurrentChange.Tok->MatchingParen && + CurrentChange.Tok->MatchingParen->is(TT_LambdaLBrace)) { return false; } if (Changes[ScopeStart].NewlinesBefore > 0) return false; - if (Changes[i].Tok->is(tok::l_brace) && - Changes[i].Tok->is(BK_BracedInit)) { + if (CurrentChange.Tok->is(tok::l_brace) && + CurrentChange.Tok->is(BK_BracedInit)) { return true; } return Style.BinPackArguments; } // Ternary operator - if (Changes[i].Tok->is(TT_ConditionalExpr)) + if (CurrentChange.Tok->is(TT_ConditionalExpr)) return true; // Period Initializer .XXX = 1. - if (Changes[i].Tok->is(TT_DesignatedInitializerPeriod)) + if (CurrentChange.Tok->is(TT_DesignatedInitializerPeriod)) return true; // Continued ternary operator - if (Changes[i].Tok->Previous && - Changes[i].Tok->Previous->is(TT_ConditionalExpr)) { + if (CurrentChange.Tok->Previous && + CurrentChange.Tok->Previous->is(TT_ConditionalExpr)) { return true; } @@ -409,8 +413,8 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, if (ScopeStart > Start + 1 && Changes[ScopeStart - 2].Tok->is(tok::identifier) && Changes[ScopeStart - 1].Tok->is(tok::l_brace) && - Changes[i].Tok->is(tok::l_brace) && - Changes[i].Tok->is(BK_BracedInit)) { + CurrentChange.Tok->is(tok::l_brace) && + CurrentChange.Tok->is(BK_BracedInit)) { return true; } @@ -418,7 +422,7 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, if (ScopeStart > Start + 1 && Changes[ScopeStart - 2].Tok->isNot(tok::identifier) && Changes[ScopeStart - 1].Tok->is(tok::l_brace) && - Changes[i].Tok->isNot(tok::r_brace)) { + CurrentChange.Tok->isNot(tok::r_brace)) { for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) { // Lambda. if (OuterScopeStart > Start && @@ -439,26 +443,26 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, }; if (ShouldShiftBeAdded()) - Changes[i].Spaces += Shift; + CurrentChange.Spaces += Shift; } if (ContinuedStringLiteral) - Changes[i].Spaces += Shift; + CurrentChange.Spaces += Shift; // We should not remove required spaces unless we break the line before. - assert(Shift >= 0 || Changes[i].NewlinesBefore > 0 || - Changes[i].Spaces >= + assert(Shift > 0 || Changes[i].NewlinesBefore > 0 || + CurrentChange.Spaces >= static_cast(Changes[i].Tok->SpacesRequiredBefore) || - Changes[i].Tok->is(tok::eof)); + CurrentChange.Tok->is(tok::eof)); - Changes[i].StartOfTokenColumn += Shift; + CurrentChange.StartOfTokenColumn += Shift; if (i + 1 != Changes.size()) Changes[i + 1].PreviousEndOfTokenColumn += Shift; // If PointerAlignment is PAS_Right, keep *s or &s next to the token if ((Style.PointerAlignment == FormatStyle::PAS_Right || Style.ReferenceAlignment == FormatStyle::RAS_Right) && - Changes[i].Spaces != 0) { + CurrentChange.Spaces != 0) { const bool ReferenceNotRightAligned = Style.ReferenceAlignment != FormatStyle::RAS_Right && Style.ReferenceAlignment != FormatStyle::RAS_Pointer; @@ -579,16 +583,17 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, unsigned i = StartAt; for (unsigned e = Changes.size(); i != e; ++i) { - if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) + auto &CurrentChange = Changes[i]; + if (CurrentChange.indentAndNestingLevel() < IndentAndNestingLevel) break; - if (Changes[i].NewlinesBefore != 0) { + if (CurrentChange.NewlinesBefore != 0) { CommasBeforeMatch = 0; EndOfSequence = i; // Whether to break the alignment sequence because of an empty line. bool EmptyLineBreak = - (Changes[i].NewlinesBefore > 1) && !ACS.AcrossEmptyLines; + (CurrentChange.NewlinesBefore > 1) && !ACS.AcrossEmptyLines; // Whether to break the alignment sequence because of a line without a // match. @@ -600,19 +605,19 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, // A new line starts, re-initialize line status tracking bools. // Keep the match state if a string literal is continued on this line. - if (i == 0 || Changes[i].Tok->isNot(tok::string_literal) || + if (i == 0 || CurrentChange.Tok->isNot(tok::string_literal) || Changes[i - 1].Tok->isNot(tok::string_literal)) { FoundMatchOnLine = false; } LineIsComment = true; } - if (Changes[i].Tok->isNot(tok::comment)) + if (CurrentChange.Tok->isNot(tok::comment)) LineIsComment = false; - if (Changes[i].Tok->is(tok::comma)) { + if (CurrentChange.Tok->is(tok::comma)) { ++CommasBeforeMatch; - } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { + } else if (CurrentChange.indentAndNestingLevel() > IndentAndNestingLevel) { // Call AlignTokens recursively, skipping over this scope block. unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS, RightJustify); @@ -620,7 +625,7 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, continue; } - if (!Matches(Changes[i])) + if (!Matches(CurrentChange)) continue; // If there is more than one matching token per line, or if the number of @@ -634,16 +639,16 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, if (StartOfSequence == 0) StartOfSequence = i; - unsigned ChangeWidthLeft = Changes[i].StartOfTokenColumn; + unsigned ChangeWidthLeft = CurrentChange.StartOfTokenColumn; unsigned ChangeWidthAnchor = 0; unsigned ChangeWidthRight = 0; if (RightJustify) if (ACS.PadOperators) - ChangeWidthAnchor = Changes[i].TokenLength; + ChangeWidthAnchor = CurrentChange.TokenLength; else - ChangeWidthLeft += Changes[i].TokenLength; + ChangeWidthLeft += CurrentChange.TokenLength; else - ChangeWidthRight = Changes[i].TokenLength; + ChangeWidthRight = CurrentChange.TokenLength; for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 0; ++j) { ChangeWidthRight += Changes[j].Spaces; // Changes are generally 1:1 with the tokens, but a change could also be diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 016f88a43a56d..85157c3b21b66 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -2341,12 +2341,9 @@ bool ASTUnit::Save(StringRef File) { return false; } -static bool serializeUnit(ASTWriter &Writer, - SmallVectorImpl &Buffer, - Sema &S, - bool hasErrors, - raw_ostream &OS) { - Writer.WriteAST(S, std::string(), nullptr, "", hasErrors); +static bool serializeUnit(ASTWriter &Writer, SmallVectorImpl &Buffer, + Sema &S, raw_ostream &OS) { + Writer.WriteAST(S, std::string(), nullptr, ""); // Write the generated bitstream to "Out". if (!Buffer.empty()) @@ -2356,18 +2353,14 @@ static bool serializeUnit(ASTWriter &Writer, } bool ASTUnit::serialize(raw_ostream &OS) { - // For serialization we are lenient if the errors were only warn-as-error kind. - bool hasErrors = getDiagnostics().hasUncompilableErrorOccurred(); - if (WriterData) - return serializeUnit(WriterData->Writer, WriterData->Buffer, - getSema(), hasErrors, OS); + return serializeUnit(WriterData->Writer, WriterData->Buffer, getSema(), OS); SmallString<128> Buffer; llvm::BitstreamWriter Stream(Buffer); InMemoryModuleCache ModuleCache; ASTWriter Writer(Stream, Buffer, ModuleCache, {}); - return serializeUnit(Writer, Buffer, getSema(), hasErrors, OS); + return serializeUnit(Writer, Buffer, getSema(), OS); } using SLocRemap = ContinuousRangeMap; diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index d18371f21a9d8..d749195585eca 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -2116,7 +2116,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, // Check whether this module is available. if (Preprocessor::checkModuleIsAvailable(getLangOpts(), getTarget(), - getDiagnostics(), Module)) { + *Module, getDiagnostics())) { getDiagnostics().Report(ImportLoc, diag::note_module_import_here) << SourceRange(Path.front().second, Path.back().second); LastModuleImportLoc = ImportLoc; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index f2fe9046a6c1f..bb442495f5835 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -4630,7 +4630,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Invocation, std::string CompilerInvocation::getModuleHash() const { // FIXME: Consider using SHA1 instead of MD5. - llvm::HashBuilder HBuilder; + llvm::HashBuilder HBuilder; // Note: For QoI reasons, the things we use as a hash here should all be // dumped via the -module-info flag. diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 60eac0c6d3530..eb8a96627bb70 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -510,8 +510,8 @@ static Module *prepareToBuildModule(CompilerInstance &CI, } // Check whether we can build this module at all. - if (Preprocessor::checkModuleIsAvailable(CI.getLangOpts(), CI.getTarget(), - CI.getDiagnostics(), M)) + if (Preprocessor::checkModuleIsAvailable(CI.getLangOpts(), CI.getTarget(), *M, + CI.getDiagnostics())) return nullptr; // Inform the preprocessor that includes from within the input buffer should diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 9e1e02e04ca7a..846e5fce6de7b 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -1081,8 +1081,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat(), "F"); DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat(), ""); DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat(), "L"); - if (TI.hasFloat128Type()) - DefineFloatMacros(Builder, "FLT128", &TI.getFloat128Format(), "Q"); // Define a __POINTER_WIDTH__ macro for stdint.h. Builder.defineMacro("__POINTER_WIDTH__", diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp index 1b262d9e6f7cb..7f5f669068230 100644 --- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -32,42 +32,42 @@ using namespace clang; /// PrintMacroDefinition - Print a macro definition in a form that will be /// properly accepted back as a definition. static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, - Preprocessor &PP, raw_ostream &OS) { - OS << "#define " << II.getName(); + Preprocessor &PP, raw_ostream *OS) { + *OS << "#define " << II.getName(); if (MI.isFunctionLike()) { - OS << '('; + *OS << '('; if (!MI.param_empty()) { MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end(); for (; AI+1 != E; ++AI) { - OS << (*AI)->getName(); - OS << ','; + *OS << (*AI)->getName(); + *OS << ','; } // Last argument. if ((*AI)->getName() == "__VA_ARGS__") - OS << "..."; + *OS << "..."; else - OS << (*AI)->getName(); + *OS << (*AI)->getName(); } if (MI.isGNUVarargs()) - OS << "..."; // #define foo(x...) + *OS << "..."; // #define foo(x...) - OS << ')'; + *OS << ')'; } // GCC always emits a space, even if the macro body is empty. However, do not // want to emit two spaces if the first token has a leading space. if (MI.tokens_empty() || !MI.tokens_begin()->hasLeadingSpace()) - OS << ' '; + *OS << ' '; SmallString<128> SpellingBuffer; for (const auto &T : MI.tokens()) { if (T.hasLeadingSpace()) - OS << ' '; + *OS << ' '; - OS << PP.getSpelling(T, SpellingBuffer); + *OS << PP.getSpelling(T, SpellingBuffer); } } @@ -81,7 +81,7 @@ class PrintPPOutputPPCallbacks : public PPCallbacks { SourceManager &SM; TokenConcatenation ConcatInfo; public: - raw_ostream &OS; + raw_ostream *OS; private: unsigned CurLine; @@ -97,20 +97,24 @@ class PrintPPOutputPPCallbacks : public PPCallbacks { bool IsFirstFileEntered; bool MinimizeWhitespace; bool DirectivesOnly; + bool KeepSystemIncludes; + raw_ostream *OrigOS; + std::unique_ptr NullOS; Token PrevTok; Token PrevPrevTok; public: - PrintPPOutputPPCallbacks(Preprocessor &pp, raw_ostream &os, bool lineMarkers, + PrintPPOutputPPCallbacks(Preprocessor &pp, raw_ostream *os, bool lineMarkers, bool defines, bool DumpIncludeDirectives, bool UseLineDirectives, bool MinimizeWhitespace, - bool DirectivesOnly) + bool DirectivesOnly, bool KeepSystemIncludes) : PP(pp), SM(PP.getSourceManager()), ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers), DumpDefines(defines), DumpIncludeDirectives(DumpIncludeDirectives), UseLineDirectives(UseLineDirectives), - MinimizeWhitespace(MinimizeWhitespace), DirectivesOnly(DirectivesOnly) { + MinimizeWhitespace(MinimizeWhitespace), DirectivesOnly(DirectivesOnly), + KeepSystemIncludes(KeepSystemIncludes), OrigOS(os) { CurLine = 0; CurFilename += ""; EmittedTokensOnThisLine = false; @@ -118,6 +122,8 @@ class PrintPPOutputPPCallbacks : public PPCallbacks { FileType = SrcMgr::C_User; Initialized = false; IsFirstFileEntered = false; + if (KeepSystemIncludes) + NullOS = std::make_unique(); PrevTok.startToken(); PrevPrevTok.startToken(); @@ -235,23 +241,23 @@ void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo, // Emit #line directives or GNU line markers depending on what mode we're in. if (UseLineDirectives) { - OS << "#line" << ' ' << LineNo << ' ' << '"'; - OS.write_escaped(CurFilename); - OS << '"'; + *OS << "#line" << ' ' << LineNo << ' ' << '"'; + OS->write_escaped(CurFilename); + *OS << '"'; } else { - OS << '#' << ' ' << LineNo << ' ' << '"'; - OS.write_escaped(CurFilename); - OS << '"'; + *OS << '#' << ' ' << LineNo << ' ' << '"'; + OS->write_escaped(CurFilename); + *OS << '"'; if (ExtraLen) - OS.write(Extra, ExtraLen); + OS->write(Extra, ExtraLen); if (FileType == SrcMgr::C_System) - OS.write(" 3", 2); + OS->write(" 3", 2); else if (FileType == SrcMgr::C_ExternCSystem) - OS.write(" 3 4", 4); + OS->write(" 3 4", 4); } - OS << '\n'; + *OS << '\n'; } /// MoveToLine - Move the output to the source line specified by the location @@ -266,7 +272,7 @@ bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo, bool StartedNewLine = false; if ((RequireStartOfLine && EmittedTokensOnThisLine) || EmittedDirectiveOnThisLine) { - OS << '\n'; + *OS << '\n'; StartedNewLine = true; CurLine += 1; EmittedTokensOnThisLine = false; @@ -283,12 +289,12 @@ bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo, // Printing a single line has priority over printing a #line directive, even // when minimizing whitespace which otherwise would print #line directives // for every single line. - OS << '\n'; + *OS << '\n'; StartedNewLine = true; } else if (!DisableLineMarkers) { if (LineNo - CurLine <= 8) { const char *NewLines = "\n\n\n\n\n\n\n\n"; - OS.write(NewLines, LineNo - CurLine); + OS->write(NewLines, LineNo - CurLine); } else { // Emit a #line or line marker. WriteLineInfo(LineNo, nullptr, 0); @@ -297,7 +303,7 @@ bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo, } else if (EmittedTokensOnThisLine) { // If we are not on the correct line and don't need to be line-correct, // at least ensure we start on a new line. - OS << '\n'; + *OS << '\n'; StartedNewLine = true; } @@ -312,7 +318,7 @@ bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo, void PrintPPOutputPPCallbacks::startNewLineIfNeeded() { if (EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) { - OS << '\n'; + *OS << '\n'; EmittedTokensOnThisLine = false; EmittedDirectiveOnThisLine = false; } @@ -350,6 +356,10 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, CurLine = NewLine; + // In KeepSystemIncludes mode, redirect OS as needed. + if (KeepSystemIncludes && (isSystem(FileType) != isSystem(NewFileType))) + OS = isSystem(FileType) ? OrigOS : NullOS.get(); + CurFilename.clear(); CurFilename += UserLoc.getFilename(); FileType = NewFileType; @@ -394,14 +404,16 @@ void PrintPPOutputPPCallbacks::InclusionDirective( StringRef SearchPath, StringRef RelativePath, const Module *Imported, SrcMgr::CharacteristicKind FileType) { // In -dI mode, dump #include directives prior to dumping their content or - // interpretation. - if (DumpIncludeDirectives) { + // interpretation. Similar for -fkeep-system-includes. + if (DumpIncludeDirectives || (KeepSystemIncludes && isSystem(FileType))) { MoveToLine(HashLoc, /*RequireStartOfLine=*/true); const std::string TokenText = PP.getSpelling(IncludeTok); assert(!TokenText.empty()); - OS << "#" << TokenText << " " - << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"') - << " /* clang -E -dI */"; + *OS << "#" << TokenText << " " + << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"') + << " /* clang -E " + << (DumpIncludeDirectives ? "-dI" : "-fkeep-system-includes") + << " */"; setEmittedDirectiveOnThisLine(); } @@ -412,11 +424,12 @@ void PrintPPOutputPPCallbacks::InclusionDirective( case tok::pp_import: case tok::pp_include_next: MoveToLine(HashLoc, /*RequireStartOfLine=*/true); - OS << "#pragma clang module import " << Imported->getFullModuleName(true) - << " /* clang -E: implicit import for " - << "#" << PP.getSpelling(IncludeTok) << " " - << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"') - << " */"; + *OS << "#pragma clang module import " + << Imported->getFullModuleName(true) + << " /* clang -E: implicit import for " + << "#" << PP.getSpelling(IncludeTok) << " " + << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"') + << " */"; setEmittedDirectiveOnThisLine(); break; @@ -438,14 +451,14 @@ void PrintPPOutputPPCallbacks::InclusionDirective( /// Handle entering the scope of a module during a module compilation. void PrintPPOutputPPCallbacks::BeginModule(const Module *M) { startNewLineIfNeeded(); - OS << "#pragma clang module begin " << M->getFullModuleName(true); + *OS << "#pragma clang module begin " << M->getFullModuleName(true); setEmittedDirectiveOnThisLine(); } /// Handle leaving the scope of a module during a module compilation. void PrintPPOutputPPCallbacks::EndModule(const Module *M) { startNewLineIfNeeded(); - OS << "#pragma clang module end /*" << M->getFullModuleName(true) << "*/"; + *OS << "#pragma clang module end /*" << M->getFullModuleName(true) << "*/"; setEmittedDirectiveOnThisLine(); } @@ -454,8 +467,8 @@ void PrintPPOutputPPCallbacks::EndModule(const Module *M) { void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, StringRef S) { MoveToLine(Loc, /*RequireStartOfLine=*/true); - OS.write("#ident ", strlen("#ident ")); - OS.write(S.begin(), S.size()); + OS->write("#ident ", strlen("#ident ")); + OS->write(S.begin(), S.size()); setEmittedTokensOnThisLine(); } @@ -491,19 +504,19 @@ void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok, return; MoveToLine(MacroNameTok.getLocation(), /*RequireStartOfLine=*/true); - OS << "#undef " << MacroNameTok.getIdentifierInfo()->getName(); + *OS << "#undef " << MacroNameTok.getIdentifierInfo()->getName(); setEmittedDirectiveOnThisLine(); } -static void outputPrintable(raw_ostream &OS, StringRef Str) { +static void outputPrintable(raw_ostream *OS, StringRef Str) { for (unsigned char Char : Str) { if (isPrintable(Char) && Char != '\\' && Char != '"') - OS << (char)Char; + *OS << (char)Char; else // Output anything hard as an octal escape. - OS << '\\' - << (char)('0' + ((Char >> 6) & 7)) - << (char)('0' + ((Char >> 3) & 7)) - << (char)('0' + ((Char >> 0) & 7)); + *OS << '\\' + << (char)('0' + ((Char >> 6) & 7)) + << (char)('0' + ((Char >> 3) & 7)) + << (char)('0' + ((Char >> 0) & 7)); } } @@ -512,25 +525,25 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc, PragmaMessageKind Kind, StringRef Str) { MoveToLine(Loc, /*RequireStartOfLine=*/true); - OS << "#pragma "; + *OS << "#pragma "; if (!Namespace.empty()) - OS << Namespace << ' '; + *OS << Namespace << ' '; switch (Kind) { case PMK_Message: - OS << "message(\""; + *OS << "message(\""; break; case PMK_Warning: - OS << "warning \""; + *OS << "warning \""; break; case PMK_Error: - OS << "error \""; + *OS << "error \""; break; } outputPrintable(OS, Str); - OS << '"'; + *OS << '"'; if (Kind == PMK_Message) - OS << ')'; + *OS << ')'; setEmittedDirectiveOnThisLine(); } @@ -538,8 +551,8 @@ void PrintPPOutputPPCallbacks::PragmaDebug(SourceLocation Loc, StringRef DebugType) { MoveToLine(Loc, /*RequireStartOfLine=*/true); - OS << "#pragma clang __debug "; - OS << DebugType; + *OS << "#pragma clang __debug "; + *OS << DebugType; setEmittedDirectiveOnThisLine(); } @@ -547,14 +560,14 @@ void PrintPPOutputPPCallbacks::PragmaDebug(SourceLocation Loc, void PrintPPOutputPPCallbacks:: PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) { MoveToLine(Loc, /*RequireStartOfLine=*/true); - OS << "#pragma " << Namespace << " diagnostic push"; + *OS << "#pragma " << Namespace << " diagnostic push"; setEmittedDirectiveOnThisLine(); } void PrintPPOutputPPCallbacks:: PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) { MoveToLine(Loc, /*RequireStartOfLine=*/true); - OS << "#pragma " << Namespace << " diagnostic pop"; + *OS << "#pragma " << Namespace << " diagnostic pop"; setEmittedDirectiveOnThisLine(); } @@ -563,25 +576,25 @@ void PrintPPOutputPPCallbacks::PragmaDiagnostic(SourceLocation Loc, diag::Severity Map, StringRef Str) { MoveToLine(Loc, /*RequireStartOfLine=*/true); - OS << "#pragma " << Namespace << " diagnostic "; + *OS << "#pragma " << Namespace << " diagnostic "; switch (Map) { case diag::Severity::Remark: - OS << "remark"; + *OS << "remark"; break; case diag::Severity::Warning: - OS << "warning"; + *OS << "warning"; break; case diag::Severity::Error: - OS << "error"; + *OS << "error"; break; case diag::Severity::Ignored: - OS << "ignored"; + *OS << "ignored"; break; case diag::Severity::Fatal: - OS << "fatal"; + *OS << "fatal"; break; } - OS << " \"" << Str << '"'; + *OS << " \"" << Str << '"'; setEmittedDirectiveOnThisLine(); } @@ -590,69 +603,69 @@ void PrintPPOutputPPCallbacks::PragmaWarning(SourceLocation Loc, ArrayRef Ids) { MoveToLine(Loc, /*RequireStartOfLine=*/true); - OS << "#pragma warning("; + *OS << "#pragma warning("; switch(WarningSpec) { - case PWS_Default: OS << "default"; break; - case PWS_Disable: OS << "disable"; break; - case PWS_Error: OS << "error"; break; - case PWS_Once: OS << "once"; break; - case PWS_Suppress: OS << "suppress"; break; - case PWS_Level1: OS << '1'; break; - case PWS_Level2: OS << '2'; break; - case PWS_Level3: OS << '3'; break; - case PWS_Level4: OS << '4'; break; + case PWS_Default: *OS << "default"; break; + case PWS_Disable: *OS << "disable"; break; + case PWS_Error: *OS << "error"; break; + case PWS_Once: *OS << "once"; break; + case PWS_Suppress: *OS << "suppress"; break; + case PWS_Level1: *OS << '1'; break; + case PWS_Level2: *OS << '2'; break; + case PWS_Level3: *OS << '3'; break; + case PWS_Level4: *OS << '4'; break; } - OS << ':'; + *OS << ':'; for (ArrayRef::iterator I = Ids.begin(), E = Ids.end(); I != E; ++I) - OS << ' ' << *I; - OS << ')'; + *OS << ' ' << *I; + *OS << ')'; setEmittedDirectiveOnThisLine(); } void PrintPPOutputPPCallbacks::PragmaWarningPush(SourceLocation Loc, int Level) { MoveToLine(Loc, /*RequireStartOfLine=*/true); - OS << "#pragma warning(push"; + *OS << "#pragma warning(push"; if (Level >= 0) - OS << ", " << Level; - OS << ')'; + *OS << ", " << Level; + *OS << ')'; setEmittedDirectiveOnThisLine(); } void PrintPPOutputPPCallbacks::PragmaWarningPop(SourceLocation Loc) { MoveToLine(Loc, /*RequireStartOfLine=*/true); - OS << "#pragma warning(pop)"; + *OS << "#pragma warning(pop)"; setEmittedDirectiveOnThisLine(); } void PrintPPOutputPPCallbacks::PragmaExecCharsetPush(SourceLocation Loc, StringRef Str) { MoveToLine(Loc, /*RequireStartOfLine=*/true); - OS << "#pragma character_execution_set(push"; + *OS << "#pragma character_execution_set(push"; if (!Str.empty()) - OS << ", " << Str; - OS << ')'; + *OS << ", " << Str; + *OS << ')'; setEmittedDirectiveOnThisLine(); } void PrintPPOutputPPCallbacks::PragmaExecCharsetPop(SourceLocation Loc) { MoveToLine(Loc, /*RequireStartOfLine=*/true); - OS << "#pragma character_execution_set(pop)"; + *OS << "#pragma character_execution_set(pop)"; setEmittedDirectiveOnThisLine(); } void PrintPPOutputPPCallbacks:: PragmaAssumeNonNullBegin(SourceLocation Loc) { MoveToLine(Loc, /*RequireStartOfLine=*/true); - OS << "#pragma clang assume_nonnull begin"; + *OS << "#pragma clang assume_nonnull begin"; setEmittedDirectiveOnThisLine(); } void PrintPPOutputPPCallbacks:: PragmaAssumeNonNullEnd(SourceLocation Loc) { MoveToLine(Loc, /*RequireStartOfLine=*/true); - OS << "#pragma clang assume_nonnull end"; + *OS << "#pragma clang assume_nonnull end"; setEmittedDirectiveOnThisLine(); } @@ -673,7 +686,7 @@ void PrintPPOutputPPCallbacks::HandleWhitespaceBeforeTok(const Token &Tok, if (MinimizeWhitespace) { // Avoid interpreting hash as a directive under -fpreprocessed. if (Tok.is(tok::hash)) - OS << ' '; + *OS << ' '; } else { // Print out space characters so that the first token on a line is // indented for easy reading. @@ -693,11 +706,11 @@ void PrintPPOutputPPCallbacks::HandleWhitespaceBeforeTok(const Token &Tok, // is not handled as a #define next time through the preprocessor if in // -fpreprocessed mode. if (ColNo <= 1 && Tok.is(tok::hash)) - OS << ' '; + *OS << ' '; // Otherwise, indent the appropriate number of spaces. for (; ColNo > 1; --ColNo) - OS << ' '; + *OS << ' '; } } else { // Insert whitespace between the previous and next token if either @@ -709,7 +722,7 @@ void PrintPPOutputPPCallbacks::HandleWhitespaceBeforeTok(const Token &Tok, if (RequireSpace || (!MinimizeWhitespace && Tok.hasLeadingSpace()) || ((EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) && AvoidConcat(PrevPrevTok, PrevTok, Tok))) - OS << ' '; + *OS << ' '; } PrevPrevTok = PrevTok; @@ -758,7 +771,7 @@ struct UnknownPragmaHandler : public PragmaHandler { // Figure out what line we went to and insert the appropriate number of // newline characters. Callbacks->MoveToLine(PragmaTok.getLocation(), /*RequireStartOfLine=*/true); - Callbacks->OS.write(Prefix, strlen(Prefix)); + Callbacks->OS->write(Prefix, strlen(Prefix)); Callbacks->setEmittedTokensOnThisLine(); if (ShouldExpandTokens) { @@ -779,7 +792,7 @@ struct UnknownPragmaHandler : public PragmaHandler { /*RequireSameLine=*/true); IsFirst = false; std::string TokSpell = PP.getSpelling(PragmaTok); - Callbacks->OS.write(&TokSpell[0], TokSpell.size()); + Callbacks->OS->write(&TokSpell[0], TokSpell.size()); Callbacks->setEmittedTokensOnThisLine(); if (ShouldExpandTokens) @@ -794,8 +807,7 @@ struct UnknownPragmaHandler : public PragmaHandler { static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, - PrintPPOutputPPCallbacks *Callbacks, - raw_ostream &OS) { + PrintPPOutputPPCallbacks *Callbacks) { bool DropComments = PP.getLangOpts().TraditionalCPP && !PP.getCommentRetentionState(); @@ -863,7 +875,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, // components. We don't have a good way to round-trip those. Module *M = reinterpret_cast(Tok.getAnnotationValue()); std::string Name = M->getFullModuleName(); - OS.write(Name.data(), Name.size()); + Callbacks->OS->write(Name.data(), Name.size()); Callbacks->HandleNewlinesInToken(Name.data(), Name.size()); } else if (Tok.isAnnotation()) { // Ignore annotation tokens created by pragmas - the pragmas themselves @@ -871,14 +883,14 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, PP.Lex(Tok); continue; } else if (IdentifierInfo *II = Tok.getIdentifierInfo()) { - OS << II->getName(); + *Callbacks->OS << II->getName(); } else if (Tok.isLiteral() && !Tok.needsCleaning() && Tok.getLiteralData()) { - OS.write(Tok.getLiteralData(), Tok.getLength()); + Callbacks->OS->write(Tok.getLiteralData(), Tok.getLength()); } else if (Tok.getLength() < std::size(Buffer)) { const char *TokPtr = Buffer; unsigned Len = PP.getSpelling(Tok, TokPtr); - OS.write(TokPtr, Len); + Callbacks->OS->write(TokPtr, Len); // Tokens that can contain embedded newlines need to adjust our current // line number. @@ -895,7 +907,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, } } else { std::string S = PP.getSpelling(Tok); - OS.write(S.data(), S.size()); + Callbacks->OS->write(S.data(), S.size()); // Tokens that can contain embedded newlines need to adjust our current // line number. @@ -947,7 +959,7 @@ static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS) { // Ignore computed macros like __LINE__ and friends. if (MI.isBuiltinMacro()) continue; - PrintMacroDefinition(*MacrosByID[i].first, MI, PP, *OS); + PrintMacroDefinition(*MacrosByID[i].first, MI, PP, OS); *OS << '\n'; } } @@ -968,9 +980,9 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, PP.SetCommentRetentionState(Opts.ShowComments, Opts.ShowMacroComments); PrintPPOutputPPCallbacks *Callbacks = new PrintPPOutputPPCallbacks( - PP, *OS, !Opts.ShowLineMarkers, Opts.ShowMacros, + PP, OS, !Opts.ShowLineMarkers, Opts.ShowMacros, Opts.ShowIncludeDirectives, Opts.UseLineDirectives, - Opts.MinimizeWhitespace, Opts.DirectivesOnly); + Opts.MinimizeWhitespace, Opts.DirectivesOnly, Opts.KeepSystemIncludes); // Expand macros in pragmas with -fms-extensions. The assumption is that // the majority of pragmas in such a file will be Microsoft pragmas. @@ -1028,7 +1040,7 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, } while (true); // Read all the preprocessed tokens, printing them out to the stream. - PrintPreprocessedTokens(PP, Tok, Callbacks, *OS); + PrintPreprocessedTokens(PP, Tok, Callbacks); *OS << '\n'; // Remove the handlers we just added to leave the preprocessor in a sane state diff --git a/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp b/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp index d3a3db0139c6d..28f7b0b9edfc5 100644 --- a/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp +++ b/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp @@ -90,8 +90,10 @@ class InclusionRewriter : public PPCallbacks { bool EnsureNewline); void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken, const MemoryBufferRef &FromFile, StringRef EOL, - unsigned &NextToWrite, int &Lines); + unsigned &NextToWrite, int &Lines, + const IncludedFile *Inc = nullptr); const IncludedFile *FindIncludeAtLocation(SourceLocation Loc) const; + StringRef getIncludedFileName(const IncludedFile *Inc) const; const Module *FindModuleAtLocation(SourceLocation Loc) const; const Module *FindEnteredModule(SourceLocation Loc) const; bool IsIfAtLocationTrue(SourceLocation Loc) const; @@ -311,6 +313,17 @@ void InclusionRewriter::OutputContentUpTo(const MemoryBufferRef &FromFile, WriteFrom = WriteTo; } +StringRef +InclusionRewriter::getIncludedFileName(const IncludedFile *Inc) const { + if (Inc) { + auto B = SM.getBufferOrNone(Inc->Id); + assert(B && "Attempting to process invalid inclusion"); + if (B) + return llvm::sys::path::filename(B->getBufferIdentifier()); + } + return StringRef(); +} + /// Print characters from \p FromFile starting at \p NextToWrite up until the /// inclusion directive at \p StartToken, then print out the inclusion /// inclusion directive disabled by a #if directive, updating \p NextToWrite @@ -320,7 +333,8 @@ void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex, const Token &StartToken, const MemoryBufferRef &FromFile, StringRef LocalEOL, - unsigned &NextToWrite, int &Line) { + unsigned &NextToWrite, int &Line, + const IncludedFile *Inc) { OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(StartToken.getLocation()), LocalEOL, Line, false); @@ -332,12 +346,21 @@ void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex, // OutputContentUpTo() would not output anything anyway. return; } - OS << "#if 0 /* expanded by -frewrite-includes */" << MainEOL; + if (Inc) { + OS << "#if defined(__CLANG_REWRITTEN_INCLUDES) "; + if (isSystem(Inc->FileType)) + OS << "|| defined(__CLANG_REWRITTEN_SYSTEM_INCLUDES) "; + OS << "/* " << getIncludedFileName(Inc); + } else { + OS << "#if 0 /*"; + } + OS << " expanded by -frewrite-includes */" << MainEOL; OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(DirectiveToken.getLocation()) + DirectiveToken.getLength(), LocalEOL, Line, true); - OS << "#endif /* expanded by -frewrite-includes */" << MainEOL; + OS << (Inc ? "#else /* " : "#endif /*") << getIncludedFileName(Inc) + << " expanded by -frewrite-includes */" << MainEOL; } /// Find the next identifier in the pragma directive specified by \p RawToken. @@ -400,15 +423,16 @@ void InclusionRewriter::Process(FileID FileId, case tok::pp_include: case tok::pp_include_next: case tok::pp_import: { - CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, NextToWrite, - Line); + SourceLocation Loc = HashToken.getLocation(); + const IncludedFile *Inc = FindIncludeAtLocation(Loc); + CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, + NextToWrite, Line, Inc); if (FileId != PP.getPredefinesFileID()) WriteLineInfo(FileName, Line - 1, FileType, ""); StringRef LineInfoExtra; - SourceLocation Loc = HashToken.getLocation(); if (const Module *Mod = FindModuleAtLocation(Loc)) WriteImplicitModuleImport(Mod); - else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) { + else if (Inc) { const Module *Mod = FindEnteredModule(Loc); if (Mod) OS << "#pragma clang module begin " @@ -420,6 +444,8 @@ void InclusionRewriter::Process(FileID FileId, if (Mod) OS << "#pragma clang module end /*" << Mod->getFullModuleName(true) << "*/\n"; + OS << "#endif /* " << getIncludedFileName(Inc) + << " expanded by -frewrite-includes */" << LocalEOL; // Add line marker to indicate we're returning from an included // file. diff --git a/clang/lib/Headers/avxintrin.h b/clang/lib/Headers/avxintrin.h index 9729786923c2d..b796bb773ec11 100644 --- a/clang/lib/Headers/avxintrin.h +++ b/clang/lib/Headers/avxintrin.h @@ -1569,6 +1569,15 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) ((__m256d)__builtin_ia32_shufpd256((__v4df)(__m256d)(a), \ (__v4df)(__m256d)(b), (int)(mask))) +/* Compare */ +#define _CMP_EQ_OQ 0x00 /* Equal (ordered, non-signaling) */ +#define _CMP_LT_OS 0x01 /* Less-than (ordered, signaling) */ +#define _CMP_LE_OS 0x02 /* Less-than-or-equal (ordered, signaling) */ +#define _CMP_UNORD_Q 0x03 /* Unordered (non-signaling) */ +#define _CMP_NEQ_UQ 0x04 /* Not-equal (unordered, non-signaling) */ +#define _CMP_NLT_US 0x05 /* Not-less-than (unordered, signaling) */ +#define _CMP_NLE_US 0x06 /* Not-less-than-or-equal (unordered, signaling) */ +#define _CMP_ORD_Q 0x07 /* Ordered (non-signaling) */ #define _CMP_EQ_UQ 0x08 /* Equal (unordered, non-signaling) */ #define _CMP_NGE_US 0x09 /* Not-greater-than-or-equal (unordered, signaling) */ #define _CMP_NGT_US 0x0a /* Not-greater-than (unordered, signaling) */ @@ -1594,6 +1603,126 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) #define _CMP_GT_OQ 0x1e /* Greater-than (ordered, non-signaling) */ #define _CMP_TRUE_US 0x1f /* True (unordered, signaling) */ +/// Compares each of the corresponding double-precision values of two +/// 128-bit vectors of [2 x double], using the operation specified by the +/// immediate integer operand. +/// +/// Returns a [2 x double] vector consisting of two doubles corresponding to +/// the two comparison results: zero if the comparison is false, and all 1's +/// if the comparison is true. +/// +/// \headerfile +/// +/// \code +/// __m128d _mm_cmp_pd(__m128d a, __m128d b, const int c); +/// \endcode +/// +/// This intrinsic corresponds to the VCMPPD instruction. +/// +/// \param a +/// A 128-bit vector of [2 x double]. +/// \param b +/// A 128-bit vector of [2 x double]. +/// \param c +/// An immediate integer operand, with bits [4:0] specifying which comparison +/// operation to use: \n +/// 0x00: Equal (ordered, non-signaling) \n +/// 0x01: Less-than (ordered, signaling) \n +/// 0x02: Less-than-or-equal (ordered, signaling) \n +/// 0x03: Unordered (non-signaling) \n +/// 0x04: Not-equal (unordered, non-signaling) \n +/// 0x05: Not-less-than (unordered, signaling) \n +/// 0x06: Not-less-than-or-equal (unordered, signaling) \n +/// 0x07: Ordered (non-signaling) \n +/// 0x08: Equal (unordered, non-signaling) \n +/// 0x09: Not-greater-than-or-equal (unordered, signaling) \n +/// 0x0A: Not-greater-than (unordered, signaling) \n +/// 0x0B: False (ordered, non-signaling) \n +/// 0x0C: Not-equal (ordered, non-signaling) \n +/// 0x0D: Greater-than-or-equal (ordered, signaling) \n +/// 0x0E: Greater-than (ordered, signaling) \n +/// 0x0F: True (unordered, non-signaling) \n +/// 0x10: Equal (ordered, signaling) \n +/// 0x11: Less-than (ordered, non-signaling) \n +/// 0x12: Less-than-or-equal (ordered, non-signaling) \n +/// 0x13: Unordered (signaling) \n +/// 0x14: Not-equal (unordered, signaling) \n +/// 0x15: Not-less-than (unordered, non-signaling) \n +/// 0x16: Not-less-than-or-equal (unordered, non-signaling) \n +/// 0x17: Ordered (signaling) \n +/// 0x18: Equal (unordered, signaling) \n +/// 0x19: Not-greater-than-or-equal (unordered, non-signaling) \n +/// 0x1A: Not-greater-than (unordered, non-signaling) \n +/// 0x1B: False (ordered, signaling) \n +/// 0x1C: Not-equal (ordered, signaling) \n +/// 0x1D: Greater-than-or-equal (ordered, non-signaling) \n +/// 0x1E: Greater-than (ordered, non-signaling) \n +/// 0x1F: True (unordered, signaling) +/// \returns A 128-bit vector of [2 x double] containing the comparison results. +#define _mm_cmp_pd(a, b, c) \ + ((__m128d)__builtin_ia32_cmppd((__v2df)(__m128d)(a), \ + (__v2df)(__m128d)(b), (c))) + +/// Compares each of the corresponding values of two 128-bit vectors of +/// [4 x float], using the operation specified by the immediate integer +/// operand. +/// +/// Returns a [4 x float] vector consisting of four floats corresponding to +/// the four comparison results: zero if the comparison is false, and all 1's +/// if the comparison is true. +/// +/// \headerfile +/// +/// \code +/// __m128 _mm_cmp_ps(__m128 a, __m128 b, const int c); +/// \endcode +/// +/// This intrinsic corresponds to the VCMPPS instruction. +/// +/// \param a +/// A 128-bit vector of [4 x float]. +/// \param b +/// A 128-bit vector of [4 x float]. +/// \param c +/// An immediate integer operand, with bits [4:0] specifying which comparison +/// operation to use: \n +/// 0x00: Equal (ordered, non-signaling) \n +/// 0x01: Less-than (ordered, signaling) \n +/// 0x02: Less-than-or-equal (ordered, signaling) \n +/// 0x03: Unordered (non-signaling) \n +/// 0x04: Not-equal (unordered, non-signaling) \n +/// 0x05: Not-less-than (unordered, signaling) \n +/// 0x06: Not-less-than-or-equal (unordered, signaling) \n +/// 0x07: Ordered (non-signaling) \n +/// 0x08: Equal (unordered, non-signaling) \n +/// 0x09: Not-greater-than-or-equal (unordered, signaling) \n +/// 0x0A: Not-greater-than (unordered, signaling) \n +/// 0x0B: False (ordered, non-signaling) \n +/// 0x0C: Not-equal (ordered, non-signaling) \n +/// 0x0D: Greater-than-or-equal (ordered, signaling) \n +/// 0x0E: Greater-than (ordered, signaling) \n +/// 0x0F: True (unordered, non-signaling) \n +/// 0x10: Equal (ordered, signaling) \n +/// 0x11: Less-than (ordered, non-signaling) \n +/// 0x12: Less-than-or-equal (ordered, non-signaling) \n +/// 0x13: Unordered (signaling) \n +/// 0x14: Not-equal (unordered, signaling) \n +/// 0x15: Not-less-than (unordered, non-signaling) \n +/// 0x16: Not-less-than-or-equal (unordered, non-signaling) \n +/// 0x17: Ordered (signaling) \n +/// 0x18: Equal (unordered, signaling) \n +/// 0x19: Not-greater-than-or-equal (unordered, non-signaling) \n +/// 0x1A: Not-greater-than (unordered, non-signaling) \n +/// 0x1B: False (ordered, signaling) \n +/// 0x1C: Not-equal (ordered, signaling) \n +/// 0x1D: Greater-than-or-equal (ordered, non-signaling) \n +/// 0x1E: Greater-than (ordered, non-signaling) \n +/// 0x1F: True (unordered, signaling) +/// \returns A 128-bit vector of [4 x float] containing the comparison results. +#define _mm_cmp_ps(a, b, c) \ + ((__m128)__builtin_ia32_cmpps((__v4sf)(__m128)(a), \ + (__v4sf)(__m128)(b), (c))) + /// Compares each of the corresponding double-precision values of two /// 256-bit vectors of [4 x double], using the operation specified by the /// immediate integer operand. @@ -1714,6 +1843,124 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) ((__m256)__builtin_ia32_cmpps256((__v8sf)(__m256)(a), \ (__v8sf)(__m256)(b), (c))) +/// Compares each of the corresponding scalar double-precision values of +/// two 128-bit vectors of [2 x double], using the operation specified by the +/// immediate integer operand. +/// +/// If the result is true, all 64 bits of the destination vector are set; +/// otherwise they are cleared. +/// +/// \headerfile +/// +/// \code +/// __m128d _mm_cmp_sd(__m128d a, __m128d b, const int c); +/// \endcode +/// +/// This intrinsic corresponds to the VCMPSD instruction. +/// +/// \param a +/// A 128-bit vector of [2 x double]. +/// \param b +/// A 128-bit vector of [2 x double]. +/// \param c +/// An immediate integer operand, with bits [4:0] specifying which comparison +/// operation to use: \n +/// 0x00: Equal (ordered, non-signaling) \n +/// 0x01: Less-than (ordered, signaling) \n +/// 0x02: Less-than-or-equal (ordered, signaling) \n +/// 0x03: Unordered (non-signaling) \n +/// 0x04: Not-equal (unordered, non-signaling) \n +/// 0x05: Not-less-than (unordered, signaling) \n +/// 0x06: Not-less-than-or-equal (unordered, signaling) \n +/// 0x07: Ordered (non-signaling) \n +/// 0x08: Equal (unordered, non-signaling) \n +/// 0x09: Not-greater-than-or-equal (unordered, signaling) \n +/// 0x0A: Not-greater-than (unordered, signaling) \n +/// 0x0B: False (ordered, non-signaling) \n +/// 0x0C: Not-equal (ordered, non-signaling) \n +/// 0x0D: Greater-than-or-equal (ordered, signaling) \n +/// 0x0E: Greater-than (ordered, signaling) \n +/// 0x0F: True (unordered, non-signaling) \n +/// 0x10: Equal (ordered, signaling) \n +/// 0x11: Less-than (ordered, non-signaling) \n +/// 0x12: Less-than-or-equal (ordered, non-signaling) \n +/// 0x13: Unordered (signaling) \n +/// 0x14: Not-equal (unordered, signaling) \n +/// 0x15: Not-less-than (unordered, non-signaling) \n +/// 0x16: Not-less-than-or-equal (unordered, non-signaling) \n +/// 0x17: Ordered (signaling) \n +/// 0x18: Equal (unordered, signaling) \n +/// 0x19: Not-greater-than-or-equal (unordered, non-signaling) \n +/// 0x1A: Not-greater-than (unordered, non-signaling) \n +/// 0x1B: False (ordered, signaling) \n +/// 0x1C: Not-equal (ordered, signaling) \n +/// 0x1D: Greater-than-or-equal (ordered, non-signaling) \n +/// 0x1E: Greater-than (ordered, non-signaling) \n +/// 0x1F: True (unordered, signaling) +/// \returns A 128-bit vector of [2 x double] containing the comparison results. +#define _mm_cmp_sd(a, b, c) \ + ((__m128d)__builtin_ia32_cmpsd((__v2df)(__m128d)(a), \ + (__v2df)(__m128d)(b), (c))) + +/// Compares each of the corresponding scalar values of two 128-bit +/// vectors of [4 x float], using the operation specified by the immediate +/// integer operand. +/// +/// If the result is true, all 32 bits of the destination vector are set; +/// otherwise they are cleared. +/// +/// \headerfile +/// +/// \code +/// __m128 _mm_cmp_ss(__m128 a, __m128 b, const int c); +/// \endcode +/// +/// This intrinsic corresponds to the VCMPSS instruction. +/// +/// \param a +/// A 128-bit vector of [4 x float]. +/// \param b +/// A 128-bit vector of [4 x float]. +/// \param c +/// An immediate integer operand, with bits [4:0] specifying which comparison +/// operation to use: \n +/// 0x00: Equal (ordered, non-signaling) \n +/// 0x01: Less-than (ordered, signaling) \n +/// 0x02: Less-than-or-equal (ordered, signaling) \n +/// 0x03: Unordered (non-signaling) \n +/// 0x04: Not-equal (unordered, non-signaling) \n +/// 0x05: Not-less-than (unordered, signaling) \n +/// 0x06: Not-less-than-or-equal (unordered, signaling) \n +/// 0x07: Ordered (non-signaling) \n +/// 0x08: Equal (unordered, non-signaling) \n +/// 0x09: Not-greater-than-or-equal (unordered, signaling) \n +/// 0x0A: Not-greater-than (unordered, signaling) \n +/// 0x0B: False (ordered, non-signaling) \n +/// 0x0C: Not-equal (ordered, non-signaling) \n +/// 0x0D: Greater-than-or-equal (ordered, signaling) \n +/// 0x0E: Greater-than (ordered, signaling) \n +/// 0x0F: True (unordered, non-signaling) \n +/// 0x10: Equal (ordered, signaling) \n +/// 0x11: Less-than (ordered, non-signaling) \n +/// 0x12: Less-than-or-equal (ordered, non-signaling) \n +/// 0x13: Unordered (signaling) \n +/// 0x14: Not-equal (unordered, signaling) \n +/// 0x15: Not-less-than (unordered, non-signaling) \n +/// 0x16: Not-less-than-or-equal (unordered, non-signaling) \n +/// 0x17: Ordered (signaling) \n +/// 0x18: Equal (unordered, signaling) \n +/// 0x19: Not-greater-than-or-equal (unordered, non-signaling) \n +/// 0x1A: Not-greater-than (unordered, non-signaling) \n +/// 0x1B: False (ordered, signaling) \n +/// 0x1C: Not-equal (ordered, signaling) \n +/// 0x1D: Greater-than-or-equal (ordered, non-signaling) \n +/// 0x1E: Greater-than (ordered, non-signaling) \n +/// 0x1F: True (unordered, signaling) +/// \returns A 128-bit vector of [4 x float] containing the comparison results. +#define _mm_cmp_ss(a, b, c) \ + ((__m128)__builtin_ia32_cmpss((__v4sf)(__m128)(a), \ + (__v4sf)(__m128)(b), (c))) + /// Takes a [8 x i32] vector and returns the vector element value /// indexed by the immediate constant operand. /// diff --git a/clang/lib/Headers/emmintrin.h b/clang/lib/Headers/emmintrin.h index 20cd1d4d732fc..8de2864b11065 100644 --- a/clang/lib/Headers/emmintrin.h +++ b/clang/lib/Headers/emmintrin.h @@ -4742,127 +4742,6 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_castsi128_pd(__m128i __a) { return (__m128d)__a; } -/// Compares each of the corresponding double-precision values of two -/// 128-bit vectors of [2 x double], using the operation specified by the -/// immediate integer operand. -/// -/// Returns a [2 x double] vector consisting of two doubles corresponding to -/// the two comparison results: zero if the comparison is false, and all 1's -/// if the comparison is true. -/// -/// \headerfile -/// -/// \code -/// __m128d _mm_cmp_pd(__m128d a, __m128d b, const int c); -/// \endcode -/// -/// This intrinsic corresponds to the (V)CMPPD instruction. -/// -/// \param a -/// A 128-bit vector of [2 x double]. -/// \param b -/// A 128-bit vector of [2 x double]. -/// \param c -/// An immediate integer operand, with bits [4:0] specifying which comparison -/// operation to use: \n -/// (Note that without avx enabled, only bits [2:0] are supported) \n -/// 0x00: Equal (ordered, non-signaling) \n -/// 0x01: Less-than (ordered, signaling) \n -/// 0x02: Less-than-or-equal (ordered, signaling) \n -/// 0x03: Unordered (non-signaling) \n -/// 0x04: Not-equal (unordered, non-signaling) \n -/// 0x05: Not-less-than (unordered, signaling) \n -/// 0x06: Not-less-than-or-equal (unordered, signaling) \n -/// 0x07: Ordered (non-signaling) \n -/// 0x08: Equal (unordered, non-signaling) \n -/// 0x09: Not-greater-than-or-equal (unordered, signaling) \n -/// 0x0A: Not-greater-than (unordered, signaling) \n -/// 0x0B: False (ordered, non-signaling) \n -/// 0x0C: Not-equal (ordered, non-signaling) \n -/// 0x0D: Greater-than-or-equal (ordered, signaling) \n -/// 0x0E: Greater-than (ordered, signaling) \n -/// 0x0F: True (unordered, non-signaling) \n -/// 0x10: Equal (ordered, signaling) \n -/// 0x11: Less-than (ordered, non-signaling) \n -/// 0x12: Less-than-or-equal (ordered, non-signaling) \n -/// 0x13: Unordered (signaling) \n -/// 0x14: Not-equal (unordered, signaling) \n -/// 0x15: Not-less-than (unordered, non-signaling) \n -/// 0x16: Not-less-than-or-equal (unordered, non-signaling) \n -/// 0x17: Ordered (signaling) \n -/// 0x18: Equal (unordered, signaling) \n -/// 0x19: Not-greater-than-or-equal (unordered, non-signaling) \n -/// 0x1A: Not-greater-than (unordered, non-signaling) \n -/// 0x1B: False (ordered, signaling) \n -/// 0x1C: Not-equal (ordered, signaling) \n -/// 0x1D: Greater-than-or-equal (ordered, non-signaling) \n -/// 0x1E: Greater-than (ordered, non-signaling) \n -/// 0x1F: True (unordered, signaling) -/// \returns A 128-bit vector of [2 x double] containing the comparison results. -#define _mm_cmp_pd(a, b, c) \ - ((__m128d)__builtin_ia32_cmppd((__v2df)(__m128d)(a), (__v2df)(__m128d)(b), \ - (c))) - -/// Compares each of the corresponding scalar double-precision values of -/// two 128-bit vectors of [2 x double], using the operation specified by the -/// immediate integer operand. -/// -/// If the result is true, all 64 bits of the destination vector are set; -/// otherwise they are cleared. -/// -/// \headerfile -/// -/// \code -/// __m128d _mm_cmp_sd(__m128d a, __m128d b, const int c); -/// \endcode -/// -/// This intrinsic corresponds to the (V)CMPSD instruction. -/// -/// \param a -/// A 128-bit vector of [2 x double]. -/// \param b -/// A 128-bit vector of [2 x double]. -/// \param c -/// An immediate integer operand, with bits [4:0] specifying which comparison -/// operation to use: \n -/// (Note that without avx enabled, only bits [2:0] are supported) \n -/// 0x00: Equal (ordered, non-signaling) \n -/// 0x01: Less-than (ordered, signaling) \n -/// 0x02: Less-than-or-equal (ordered, signaling) \n -/// 0x03: Unordered (non-signaling) \n -/// 0x04: Not-equal (unordered, non-signaling) \n -/// 0x05: Not-less-than (unordered, signaling) \n -/// 0x06: Not-less-than-or-equal (unordered, signaling) \n -/// 0x07: Ordered (non-signaling) \n -/// 0x08: Equal (unordered, non-signaling) \n -/// 0x09: Not-greater-than-or-equal (unordered, signaling) \n -/// 0x0A: Not-greater-than (unordered, signaling) \n -/// 0x0B: False (ordered, non-signaling) \n -/// 0x0C: Not-equal (ordered, non-signaling) \n -/// 0x0D: Greater-than-or-equal (ordered, signaling) \n -/// 0x0E: Greater-than (ordered, signaling) \n -/// 0x0F: True (unordered, non-signaling) \n -/// 0x10: Equal (ordered, signaling) \n -/// 0x11: Less-than (ordered, non-signaling) \n -/// 0x12: Less-than-or-equal (ordered, non-signaling) \n -/// 0x13: Unordered (signaling) \n -/// 0x14: Not-equal (unordered, signaling) \n -/// 0x15: Not-less-than (unordered, non-signaling) \n -/// 0x16: Not-less-than-or-equal (unordered, non-signaling) \n -/// 0x17: Ordered (signaling) \n -/// 0x18: Equal (unordered, signaling) \n -/// 0x19: Not-greater-than-or-equal (unordered, non-signaling) \n -/// 0x1A: Not-greater-than (unordered, non-signaling) \n -/// 0x1B: False (ordered, signaling) \n -/// 0x1C: Not-equal (ordered, signaling) \n -/// 0x1D: Greater-than-or-equal (ordered, non-signaling) \n -/// 0x1E: Greater-than (ordered, non-signaling) \n -/// 0x1F: True (unordered, signaling) -/// \returns A 128-bit vector of [2 x double] containing the comparison results. -#define _mm_cmp_sd(a, b, c) \ - ((__m128d)__builtin_ia32_cmpsd((__v2df)(__m128d)(a), (__v2df)(__m128d)(b), \ - (c))) - #if defined(__cplusplus) extern "C" { #endif diff --git a/clang/lib/Headers/xmmintrin.h b/clang/lib/Headers/xmmintrin.h index 73b1ab4bb4a3d..2d1d33c69f0bb 100644 --- a/clang/lib/Headers/xmmintrin.h +++ b/clang/lib/Headers/xmmintrin.h @@ -2936,134 +2936,6 @@ _mm_movemask_ps(__m128 __a) return __builtin_ia32_movmskps((__v4sf)__a); } -/* Compare */ -#define _CMP_EQ_OQ 0x00 /* Equal (ordered, non-signaling) */ -#define _CMP_LT_OS 0x01 /* Less-than (ordered, signaling) */ -#define _CMP_LE_OS 0x02 /* Less-than-or-equal (ordered, signaling) */ -#define _CMP_UNORD_Q 0x03 /* Unordered (non-signaling) */ -#define _CMP_NEQ_UQ 0x04 /* Not-equal (unordered, non-signaling) */ -#define _CMP_NLT_US 0x05 /* Not-less-than (unordered, signaling) */ -#define _CMP_NLE_US 0x06 /* Not-less-than-or-equal (unordered, signaling) */ -#define _CMP_ORD_Q 0x07 /* Ordered (non-signaling) */ - -/// Compares each of the corresponding values of two 128-bit vectors of -/// [4 x float], using the operation specified by the immediate integer -/// operand. -/// -/// Returns a [4 x float] vector consisting of four floats corresponding to -/// the four comparison results: zero if the comparison is false, and all 1's -/// if the comparison is true. -/// -/// \headerfile -/// -/// \code -/// __m128 _mm_cmp_ps(__m128 a, __m128 b, const int c); -/// \endcode -/// -/// This intrinsic corresponds to the (V)CMPPS instruction. -/// -/// \param a -/// A 128-bit vector of [4 x float]. -/// \param b -/// A 128-bit vector of [4 x float]. -/// \param c -/// An immediate integer operand, with bits [4:0] specifying which comparison -/// operation to use: \n -/// (Note that without avx enabled, only bits [2:0] are supported) \n -/// 0x00: Equal (ordered, non-signaling) \n -/// 0x01: Less-than (ordered, signaling) \n -/// 0x02: Less-than-or-equal (ordered, signaling) \n -/// 0x03: Unordered (non-signaling) \n -/// 0x04: Not-equal (unordered, non-signaling) \n -/// 0x05: Not-less-than (unordered, signaling) \n -/// 0x06: Not-less-than-or-equal (unordered, signaling) \n -/// 0x07: Ordered (non-signaling) \n -/// 0x08: Equal (unordered, non-signaling) \n -/// 0x09: Not-greater-than-or-equal (unordered, signaling) \n -/// 0x0A: Not-greater-than (unordered, signaling) \n -/// 0x0B: False (ordered, non-signaling) \n -/// 0x0C: Not-equal (ordered, non-signaling) \n -/// 0x0D: Greater-than-or-equal (ordered, signaling) \n -/// 0x0E: Greater-than (ordered, signaling) \n -/// 0x0F: True (unordered, non-signaling) \n -/// 0x10: Equal (ordered, signaling) \n -/// 0x11: Less-than (ordered, non-signaling) \n -/// 0x12: Less-than-or-equal (ordered, non-signaling) \n -/// 0x13: Unordered (signaling) \n -/// 0x14: Not-equal (unordered, signaling) \n -/// 0x15: Not-less-than (unordered, non-signaling) \n -/// 0x16: Not-less-than-or-equal (unordered, non-signaling) \n -/// 0x17: Ordered (signaling) \n -/// 0x18: Equal (unordered, signaling) \n -/// 0x19: Not-greater-than-or-equal (unordered, non-signaling) \n -/// 0x1A: Not-greater-than (unordered, non-signaling) \n -/// 0x1B: False (ordered, signaling) \n -/// 0x1C: Not-equal (ordered, signaling) \n -/// 0x1D: Greater-than-or-equal (ordered, non-signaling) \n -/// 0x1E: Greater-than (ordered, non-signaling) \n -/// 0x1F: True (unordered, signaling) -/// \returns A 128-bit vector of [4 x float] containing the comparison results. -#define _mm_cmp_ps(a, b, c) \ - ((__m128)__builtin_ia32_cmpps((__v4sf)(__m128)(a), (__v4sf)(__m128)(b), (c))) - -/// Compares each of the corresponding scalar values of two 128-bit -/// vectors of [4 x float], using the operation specified by the immediate -/// integer operand. -/// -/// If the result is true, all 32 bits of the destination vector are set; -/// otherwise they are cleared. -/// -/// \headerfile -/// -/// \code -/// __m128 _mm_cmp_ss(__m128 a, __m128 b, const int c); -/// \endcode -/// -/// This intrinsic corresponds to the (V)CMPSS instruction. -/// -/// \param a -/// A 128-bit vector of [4 x float]. -/// \param b -/// A 128-bit vector of [4 x float]. -/// \param c -/// An immediate integer operand, with bits [4:0] specifying which comparison -/// operation to use: \n -/// (Note that without avx enabled, only bits [2:0] are supported) \n -/// 0x00: Equal (ordered, non-signaling) \n -/// 0x01: Less-than (ordered, signaling) \n -/// 0x02: Less-than-or-equal (ordered, signaling) \n -/// 0x03: Unordered (non-signaling) \n -/// 0x04: Not-equal (unordered, non-signaling) \n -/// 0x05: Not-less-than (unordered, signaling) \n -/// 0x06: Not-less-than-or-equal (unordered, signaling) \n -/// 0x07: Ordered (non-signaling) \n -/// 0x08: Equal (unordered, non-signaling) \n -/// 0x09: Not-greater-than-or-equal (unordered, signaling) \n -/// 0x0A: Not-greater-than (unordered, signaling) \n -/// 0x0B: False (ordered, non-signaling) \n -/// 0x0C: Not-equal (ordered, non-signaling) \n -/// 0x0D: Greater-than-or-equal (ordered, signaling) \n -/// 0x0E: Greater-than (ordered, signaling) \n -/// 0x0F: True (unordered, non-signaling) \n -/// 0x10: Equal (ordered, signaling) \n -/// 0x11: Less-than (ordered, non-signaling) \n -/// 0x12: Less-than-or-equal (ordered, non-signaling) \n -/// 0x13: Unordered (signaling) \n -/// 0x14: Not-equal (unordered, signaling) \n -/// 0x15: Not-less-than (unordered, non-signaling) \n -/// 0x16: Not-less-than-or-equal (unordered, non-signaling) \n -/// 0x17: Ordered (signaling) \n -/// 0x18: Equal (unordered, signaling) \n -/// 0x19: Not-greater-than-or-equal (unordered, non-signaling) \n -/// 0x1A: Not-greater-than (unordered, non-signaling) \n -/// 0x1B: False (ordered, signaling) \n -/// 0x1C: Not-equal (ordered, signaling) \n -/// 0x1D: Greater-than-or-equal (ordered, non-signaling) \n -/// 0x1E: Greater-than (ordered, non-signaling) \n -/// 0x1F: True (unordered, signaling) -/// \returns A 128-bit vector of [4 x float] containing the comparison results. -#define _mm_cmp_ss(a, b, c) \ - ((__m128)__builtin_ia32_cmpss((__v4sf)(__m128)(a), (__v4sf)(__m128)(b), (c))) #define _MM_ALIGN16 __attribute__((aligned(16))) diff --git a/clang/lib/Index/IndexSymbol.cpp b/clang/lib/Index/IndexSymbol.cpp index d7316538f6061..cfdffeed834e6 100644 --- a/clang/lib/Index/IndexSymbol.cpp +++ b/clang/lib/Index/IndexSymbol.cpp @@ -346,7 +346,6 @@ SymbolInfo index::getSymbolInfo(const Decl *D) { } break; case Decl::ClassTemplatePartialSpecialization: - case Decl::ClassScopeFunctionSpecialization: case Decl::ClassTemplateSpecialization: case Decl::CXXRecord: case Decl::Enum: diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 37c3e4175d473..feed1b9ecd71a 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -57,7 +57,7 @@ using namespace clang; bool Token::isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const { if (isAnnotation()) return false; - if (IdentifierInfo *II = getIdentifierInfo()) + if (const IdentifierInfo *II = getIdentifierInfo()) return II->getObjCKeywordID() == objcKey; return false; } @@ -66,7 +66,7 @@ bool Token::isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const { tok::ObjCKeywordKind Token::getObjCKeywordID() const { if (isAnnotation()) return tok::objc_not_keyword; - IdentifierInfo *specId = getIdentifierInfo(); + const IdentifierInfo *specId = getIdentifierInfo(); return specId ? specId->getObjCKeywordID() : tok::objc_not_keyword; } @@ -1893,7 +1893,7 @@ bool Lexer::LexIdentifierContinue(Token &Result, const char *CurPtr) { // Fill in Result.IdentifierInfo and update the token kind, // looking up the identifier in the identifier table. - IdentifierInfo *II = PP->LookUpIdentifierInfo(Result); + const IdentifierInfo *II = PP->LookUpIdentifierInfo(Result); // Note that we have to call PP->LookUpIdentifierInfo() even for code // completion, it writes IdentifierInfo into Result, and callers rely on it. @@ -4458,7 +4458,7 @@ bool Lexer::LexDependencyDirectiveToken(Token &Result) { if (Result.is(tok::raw_identifier)) { Result.setRawIdentifierData(TokPtr); if (!isLexingRawMode()) { - IdentifierInfo *II = PP->LookUpIdentifierInfo(Result); + const IdentifierInfo *II = PP->LookUpIdentifierInfo(Result); if (II->isHandleIdentifierCase()) return PP->HandleIdentifier(Result); } diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 7899bfa1c4f58..e3065c17dc70b 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -1896,26 +1896,27 @@ static bool trySimplifyPath(SmallVectorImpl &Components, bool Preprocessor::checkModuleIsAvailable(const LangOptions &LangOpts, const TargetInfo &TargetInfo, - DiagnosticsEngine &Diags, Module *M) { + const Module &M, + DiagnosticsEngine &Diags) { Module::Requirement Requirement; Module::UnresolvedHeaderDirective MissingHeader; Module *ShadowingModule = nullptr; - if (M->isAvailable(LangOpts, TargetInfo, Requirement, MissingHeader, - ShadowingModule)) + if (M.isAvailable(LangOpts, TargetInfo, Requirement, MissingHeader, + ShadowingModule)) return false; if (MissingHeader.FileNameLoc.isValid()) { Diags.Report(MissingHeader.FileNameLoc, diag::err_module_header_missing) << MissingHeader.IsUmbrella << MissingHeader.FileName; } else if (ShadowingModule) { - Diags.Report(M->DefinitionLoc, diag::err_module_shadowed) << M->Name; + Diags.Report(M.DefinitionLoc, diag::err_module_shadowed) << M.Name; Diags.Report(ShadowingModule->DefinitionLoc, diag::note_previous_definition); } else { // FIXME: Track the location at which the requirement was specified, and // use it here. - Diags.Report(M->DefinitionLoc, diag::err_module_unavailable) - << M->getFullModuleName() << Requirement.second << Requirement.first; + Diags.Report(M.DefinitionLoc, diag::err_module_unavailable) + << M.getFullModuleName() << Requirement.second << Requirement.first; } return true; } @@ -2260,8 +2261,9 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( // unavailable, diagnose the situation and bail out. // FIXME: Remove this; loadModule does the same check (but produces // slightly worse diagnostics). - if (checkModuleIsAvailable(getLangOpts(), getTargetInfo(), getDiagnostics(), - SuggestedModule.getModule())) { + if (checkModuleIsAvailable(getLangOpts(), getTargetInfo(), + *SuggestedModule.getModule(), + getDiagnostics())) { Diag(FilenameTok.getLocation(), diag::note_implicit_top_level_module_import_here) << SuggestedModule.getModule()->getTopLevelModuleName(); diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index 58da4410dee64..35ab42cb6b5ef 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -1769,7 +1769,7 @@ struct PragmaModuleBeginHandler : public PragmaHandler { // If the module isn't available, it doesn't make sense to enter it. if (Preprocessor::checkModuleIsAvailable( - PP.getLangOpts(), PP.getTargetInfo(), PP.getDiagnostics(), M)) { + PP.getLangOpts(), PP.getTargetInfo(), *M, PP.getDiagnostics())) { PP.Diag(BeginLoc, diag::note_pp_module_begin_here) << M->getTopLevelModuleName(); return; diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 73c37bc5161c4..ede4c51487ffb 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -817,8 +817,8 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) { } // If this is a macro to be expanded, do it. - if (MacroDefinition MD = getMacroDefinition(&II)) { - auto *MI = MD.getMacroInfo(); + if (const MacroDefinition MD = getMacroDefinition(&II)) { + const auto *MI = MD.getMacroInfo(); assert(MI && "macro definition with no macro info?"); if (!DisableMacroExpansion) { if (!Identifier.isExpandDisabled() && MI->isEnabled()) { @@ -998,6 +998,18 @@ void Preprocessor::Lex(Token &Result) { } } +void Preprocessor::LexTokensUntilEOF(std::vector *Tokens) { + while (1) { + Token Tok; + Lex(Tok); + if (Tok.isOneOf(tok::unknown, tok::eof, tok::eod, + tok::annot_repl_input_end)) + break; + if (Tokens != nullptr) + Tokens->push_back(Tok); + } +} + /// Lex a header-name token (including one formed from header-name-tokens if /// \p AllowConcatenation is \c true). /// diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 3cad57e719aad..bcc70c04dec91 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -4038,7 +4038,7 @@ void Parser::ParseDeclarationSpecifiers( isStorageClass = true; break; case tok::kw_auto: - if (getLangOpts().CPlusPlus11) { + if (getLangOpts().CPlusPlus11 || getLangOpts().C23) { if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, PrevSpec, DiagID, Policy); @@ -7703,7 +7703,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // Parse the constant-expression or assignment-expression now (depending // on dialect). if (getLangOpts().CPlusPlus) { - NumElements = ParseConstantExpression(); + NumElements = ParseArrayBoundExpression(); } else { EnterExpressionEvaluationContext Unevaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 711990bff2851..9dbfc1c8c5e9f 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -221,6 +221,15 @@ ExprResult Parser::ParseConstantExpression() { return ParseConstantExpressionInExprEvalContext(NotTypeCast); } +ExprResult Parser::ParseArrayBoundExpression() { + EnterExpressionEvaluationContext ConstantEvaluated( + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + // If we parse the bound of a VLA... we parse a non-constant + // constant-expression! + Actions.ExprEvalContexts.back().InConditionallyConstantEvaluateContext = true; + return ParseConstantExpressionInExprEvalContext(NotTypeCast); +} + ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) { EnterExpressionEvaluationContext ConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 8a8a126bf7244..995834a78c795 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -3416,6 +3416,17 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_ompx_attribute: Clause = ParseOpenMPOMPXAttributesClause(WrongDirective); break; + case OMPC_ompx_bare: + if (WrongDirective) + Diag(Tok, diag::note_ompx_bare_clause) + << getOpenMPClauseName(CKind) << "target teams"; + if (!ErrorFound && !getLangOpts().OpenMPExtensions) { + Diag(Tok, diag::err_omp_unexpected_clause_extension_only) + << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); + ErrorFound = true; + } + Clause = ParseOpenMPClause(CKind, WrongDirective); + break; default: break; } diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 2d0d575f173a8..781f24cb71ae9 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -1375,8 +1375,9 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { StorageClassSpecLoc = SourceLocation(); } // Diagnose if we've recovered from an ill-formed 'auto' storage class - // specifier in a pre-C++11 dialect of C++. - if (!S.getLangOpts().CPlusPlus11 && TypeSpecType == TST_auto) + // specifier in a pre-C++11 dialect of C++ or in a pre-C23 dialect of C. + if (!S.getLangOpts().CPlusPlus11 && !S.getLangOpts().C23 && + TypeSpecType == TST_auto) S.Diag(TSTLoc, diag::ext_auto_type_specifier); if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11 && StorageClassSpec == SCS_auto) diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 4489cb0deae4c..67533ccbdf347 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -221,7 +221,6 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, CurScope(nullptr), Ident_super(nullptr) { assert(pp.TUKind == TUKind); TUScope = nullptr; - isConstantEvaluatedOverride = false; LoadedExternalKnownNamespaces = false; for (unsigned I = 0; I != NSAPI::NumNSNumberLiteralMethods; ++I) @@ -2072,7 +2071,7 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { targetDiag(D->getLocation(), diag::note_defined_here, FD) << D; } - if (Ty->isRVVType()) + if (TI.hasRISCVVTypes() && Ty->isRVVType()) checkRVVTypeSupport(Ty, Loc, D); // Don't allow SVE types in functions without a SVE target. diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp index 3336dbf474df0..7c4083e4ec4d4 100644 --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -812,7 +812,7 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); assert(Callee && "Callee may not be null."); - auto &ExprEvalCtx = ExprEvalContexts.back(); + const auto &ExprEvalCtx = currentEvaluationContext(); if (ExprEvalCtx.isUnevaluated() || ExprEvalCtx.isConstantEvaluated()) return true; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 3b0cc154c2e46..446e35218bff0 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1076,7 +1076,7 @@ static bool ProcessFormatStringLiteral(const Expr *FormatExpr, void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, CallExpr *TheCall) { if (TheCall->isValueDependent() || TheCall->isTypeDependent() || - isConstantEvaluated()) + isConstantEvaluatedContext()) return; bool UseDABAttr = false; @@ -3192,7 +3192,7 @@ bool Sema::CheckCDEBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, bool Sema::CheckARMCoprocessorImmediate(const TargetInfo &TI, const Expr *CoprocArg, bool WantCDE) { - if (isConstantEvaluated()) + if (isConstantEvaluatedContext()) return false; // We can't check the value of a dependent argument. @@ -6276,10 +6276,6 @@ bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case X86::BI__builtin_ia32_cmpss: case X86::BI__builtin_ia32_cmppd: case X86::BI__builtin_ia32_cmpsd: - i = 2; - l = 0; - u = TI.hasFeature("avx") ? 31 : 7; - break; case X86::BI__builtin_ia32_cmpps256: case X86::BI__builtin_ia32_cmppd256: case X86::BI__builtin_ia32_cmpps128_mask: @@ -6616,7 +6612,7 @@ static void CheckNonNullArguments(Sema &S, assert((FDecl || Proto) && "Need a function declaration or prototype"); // Already checked by constant evaluator. - if (S.isConstantEvaluated()) + if (S.isConstantEvaluatedContext()) return; // Check the attributes attached to the method/function itself. llvm::SmallBitVector NonNullArgs; @@ -8980,7 +8976,7 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, /// TheCall is a constant expression in the range [Low, High]. bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, int High, bool RangeIsError) { - if (isConstantEvaluated()) + if (isConstantEvaluatedContext()) return false; llvm::APSInt Result; @@ -9694,7 +9690,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef Args, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg, llvm::APSInt Offset, bool IgnoreStringsWithoutSpecifiers = false) { - if (S.isConstantEvaluated()) + if (S.isConstantEvaluatedContext()) return SLCT_NotALiteral; tryAgain: assert(Offset.isSigned() && "invalid offset"); @@ -9734,8 +9730,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef Args, bool CheckLeft = true, CheckRight = true; bool Cond; - if (C->getCond()->EvaluateAsBooleanCondition(Cond, S.getASTContext(), - S.isConstantEvaluated())) { + if (C->getCond()->EvaluateAsBooleanCondition( + Cond, S.getASTContext(), S.isConstantEvaluatedContext())) { if (Cond) CheckRight = false; else @@ -9999,9 +9995,11 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef Args, Expr::EvalResult LResult, RResult; bool LIsInt = BinOp->getLHS()->EvaluateAsInt( - LResult, S.Context, Expr::SE_NoSideEffects, S.isConstantEvaluated()); + LResult, S.Context, Expr::SE_NoSideEffects, + S.isConstantEvaluatedContext()); bool RIsInt = BinOp->getRHS()->EvaluateAsInt( - RResult, S.Context, Expr::SE_NoSideEffects, S.isConstantEvaluated()); + RResult, S.Context, Expr::SE_NoSideEffects, + S.isConstantEvaluatedContext()); if (LIsInt != RIsInt) { BinaryOperatorKind BinOpKind = BinOp->getOpcode(); @@ -10029,7 +10027,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef Args, Expr::EvalResult IndexResult; if (ASE->getRHS()->EvaluateAsInt(IndexResult, S.Context, Expr::SE_NoSideEffects, - S.isConstantEvaluated())) { + S.isConstantEvaluatedContext())) { sumOffsets(Offset, IndexResult.Val.getInt(), BO_Add, /*RHS is int*/ true); E = ASE->getBase(); @@ -13959,7 +13957,7 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, return false; IntRange OtherValueRange = GetExprRange( - S.Context, Other, S.isConstantEvaluated(), /*Approximate*/ false); + S.Context, Other, S.isConstantEvaluatedContext(), /*Approximate=*/false); QualType OtherT = Other->getType(); if (const auto *AT = OtherT->getAs()) @@ -14174,8 +14172,9 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) { } // Otherwise, calculate the effective range of the signed operand. - IntRange signedRange = GetExprRange( - S.Context, signedOperand, S.isConstantEvaluated(), /*Approximate*/ true); + IntRange signedRange = + GetExprRange(S.Context, signedOperand, S.isConstantEvaluatedContext(), + /*Approximate=*/true); // Go ahead and analyze implicit conversions in the operands. Note // that we skip the implicit conversions on both sides. @@ -14193,8 +14192,8 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) { if (E->isEqualityOp()) { unsigned comparisonWidth = S.Context.getIntWidth(T); IntRange unsignedRange = - GetExprRange(S.Context, unsignedOperand, S.isConstantEvaluated(), - /*Approximate*/ true); + GetExprRange(S.Context, unsignedOperand, S.isConstantEvaluatedContext(), + /*Approximate=*/true); // We should never be unable to prove that the unsigned operand is // non-negative. @@ -15057,7 +15056,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (Target->isUnsaturatedFixedPointType()) { Expr::EvalResult Result; if (E->EvaluateAsFixedPoint(Result, S.Context, Expr::SE_AllowSideEffects, - S.isConstantEvaluated())) { + S.isConstantEvaluatedContext())) { llvm::APFixedPoint Value = Result.Val.getFixedPoint(); llvm::APFixedPoint MaxVal = S.Context.getFixedPointMax(T); llvm::APFixedPoint MinVal = S.Context.getFixedPointMin(T); @@ -15072,7 +15071,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, } } else if (Target->isIntegerType()) { Expr::EvalResult Result; - if (!S.isConstantEvaluated() && + if (!S.isConstantEvaluatedContext() && E->EvaluateAsFixedPoint(Result, S.Context, Expr::SE_AllowSideEffects)) { llvm::APFixedPoint FXResult = Result.Val.getFixedPoint(); @@ -15095,7 +15094,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, } else if (Target->isUnsaturatedFixedPointType()) { if (Source->isIntegerType()) { Expr::EvalResult Result; - if (!S.isConstantEvaluated() && + if (!S.isConstantEvaluatedContext() && E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) { llvm::APSInt Value = Result.Val.getInt(); @@ -15121,8 +15120,9 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (SourceBT && TargetBT && SourceBT->isIntegerType() && TargetBT->isFloatingType() && !IsListInit) { // Determine the number of precision bits in the source integer type. - IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated(), - /*Approximate*/ true); + IntRange SourceRange = + GetExprRange(S.Context, E, S.isConstantEvaluatedContext(), + /*Approximate=*/true); unsigned int SourcePrecision = SourceRange.Width; // Determine the number of precision bits in the @@ -15190,8 +15190,8 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, IntRange SourceTypeRange = IntRange::forTargetOfCanonicalType(S.Context, Source); - IntRange LikelySourceRange = - GetExprRange(S.Context, E, S.isConstantEvaluated(), /*Approximate*/ true); + IntRange LikelySourceRange = GetExprRange( + S.Context, E, S.isConstantEvaluatedContext(), /*Approximate=*/true); IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target); if (LikelySourceRange.Width > TargetRange.Width) { @@ -15199,7 +15199,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // TODO: this should happen for bitfield stores, too. Expr::EvalResult Result; if (E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects, - S.isConstantEvaluated())) { + S.isConstantEvaluatedContext())) { llvm::APSInt Value(32); Value = Result.Val.getInt(); @@ -16063,7 +16063,8 @@ class SequenceChecker : public ConstEvaluatedExprVisitor { if (!EvalOK || E->isValueDependent()) return false; EvalOK = E->EvaluateAsBooleanCondition( - Result, Self.SemaRef.Context, Self.SemaRef.isConstantEvaluated()); + Result, Self.SemaRef.Context, + Self.SemaRef.isConstantEvaluatedContext()); return EvalOK; } @@ -17190,7 +17191,7 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const ArraySubscriptExpr *ASE, bool AllowOnePastEnd, bool IndexNegated) { // Already diagnosed by the constant evaluator. - if (isConstantEvaluated()) + if (isConstantEvaluatedContext()) return; IndexExpr = IndexExpr->IgnoreParenImpCasts(); @@ -18579,7 +18580,7 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, TypeTagData TypeInfo; if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context, TypeTagForDatatypeMagicValues.get(), FoundWrongKind, - TypeInfo, isConstantEvaluated())) { + TypeInfo, isConstantEvaluatedContext())) { if (FoundWrongKind) Diag(TypeTagExpr->getExprLoc(), diag::warn_type_tag_for_datatype_wrong_kind) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 5c0b1ad7c5f7c..f249d41bc9bfb 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9775,7 +9775,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, bool isMemberSpecialization = false; bool isFunctionTemplateSpecialization = false; - bool isDependentClassScopeExplicitSpecialization = false; bool HasExplicitTemplateArgs = false; TemplateArgumentListInfo TemplateArgs; @@ -10415,12 +10414,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc); HasExplicitTemplateArgs = false; - } else { - assert((isFunctionTemplateSpecialization || - D.getDeclSpec().isFriendSpecified()) && - "should have a 'template<>' for this decl"); + } else if (isFriend) { // "friend void foo<>(int);" is an implicit specialization decl. isFunctionTemplateSpecialization = true; + } else { + assert(isFunctionTemplateSpecialization && + "should have a 'template<>' for this decl"); } } else if (isFriend && isFunctionTemplateSpecialization) { // This combination is only possible in a recovery case; the user @@ -10443,32 +10442,54 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (getLangOpts().CUDA && !isFunctionTemplateSpecialization) maybeAddCUDAHostDeviceAttrs(NewFD, Previous); - // If it's a friend (and only if it's a friend), it's possible - // that either the specialized function type or the specialized - // template is dependent, and therefore matching will fail. In - // this case, don't check the specialization yet. - if (isFunctionTemplateSpecialization && isFriend && - (NewFD->getType()->isDependentType() || DC->isDependentContext() || - TemplateSpecializationType::anyInstantiationDependentTemplateArguments( - TemplateArgs.arguments()))) { - assert(HasExplicitTemplateArgs && - "friend function specialization without template args"); - if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs, - Previous)) - NewFD->setInvalidDecl(); - } else if (isFunctionTemplateSpecialization) { - if (CurContext->isDependentContext() && CurContext->isRecord() - && !isFriend) { - isDependentClassScopeExplicitSpecialization = true; - } else if (!NewFD->isInvalidDecl() && - CheckFunctionTemplateSpecialization( - NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr), - Previous)) - NewFD->setInvalidDecl(); + // Handle explict specializations of function templates + // and friend function declarations with an explicit + // template argument list. + if (isFunctionTemplateSpecialization) { + bool isDependentSpecialization = false; + if (isFriend) { + // For friend function specializations, this is a dependent + // specialization if its semantic context is dependent, its + // type is dependent, or if its template-id is dependent. + isDependentSpecialization = + DC->isDependentContext() || NewFD->getType()->isDependentType() || + (HasExplicitTemplateArgs && + TemplateSpecializationType:: + anyInstantiationDependentTemplateArguments( + TemplateArgs.arguments())); + assert((!isDependentSpecialization || + (HasExplicitTemplateArgs == isDependentSpecialization)) && + "dependent friend function specialization without template " + "args"); + } else { + // For class-scope explicit specializations of function templates, + // if the lexical context is dependent, then the specialization + // is dependent. + isDependentSpecialization = + CurContext->isRecord() && CurContext->isDependentContext(); + } + + TemplateArgumentListInfo *ExplicitTemplateArgs = + HasExplicitTemplateArgs ? &TemplateArgs : nullptr; + if (isDependentSpecialization) { + // If it's a dependent specialization, it may not be possible + // to determine the primary template (for explicit specializations) + // or befriended declaration (for friends) until the enclosing + // template is instantiated. In such cases, we store the declarations + // found by name lookup and defer resolution until instantiation. + if (CheckDependentFunctionTemplateSpecialization( + NewFD, ExplicitTemplateArgs, Previous)) + NewFD->setInvalidDecl(); + } else if (!NewFD->isInvalidDecl()) { + if (CheckFunctionTemplateSpecialization(NewFD, ExplicitTemplateArgs, + Previous)) + NewFD->setInvalidDecl(); + } // C++ [dcl.stc]p1: // A storage-class-specifier shall not be specified in an explicit // specialization (14.7.3) + // FIXME: We should be checking this for dependent specializations. FunctionTemplateSpecializationInfo *Info = NewFD->getTemplateSpecializationInfo(); if (Info && SC != SC_None) { @@ -10491,21 +10512,19 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } // Perform semantic checking on the function declaration. - if (!isDependentClassScopeExplicitSpecialization) { - if (!NewFD->isInvalidDecl() && NewFD->isMain()) - CheckMain(NewFD, D.getDeclSpec()); + if (!NewFD->isInvalidDecl() && NewFD->isMain()) + CheckMain(NewFD, D.getDeclSpec()); - if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint()) - CheckMSVCRTEntryPoint(NewFD); + if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint()) + CheckMSVCRTEntryPoint(NewFD); - if (!NewFD->isInvalidDecl()) - D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, - isMemberSpecialization, - D.isFunctionDefinition())); - else if (!Previous.empty()) - // Recover gracefully from an invalid redeclaration. - D.setRedeclaration(true); - } + if (!NewFD->isInvalidDecl()) + D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, + isMemberSpecialization, + D.isFunctionDefinition())); + else if (!Previous.empty()) + // Recover gracefully from an invalid redeclaration. + D.setRedeclaration(true); assert((NewFD->isInvalidDecl() || NewFD->isMultiVersion() || !D.isRedeclaration() || @@ -10817,19 +10836,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - // Here we have an function template explicit specialization at class scope. - // The actual specialization will be postponed to template instatiation - // time via the ClassScopeFunctionSpecializationDecl node. - if (isDependentClassScopeExplicitSpecialization) { - ClassScopeFunctionSpecializationDecl *NewSpec = - ClassScopeFunctionSpecializationDecl::Create( - Context, CurContext, NewFD->getLocation(), - cast(NewFD), - HasExplicitTemplateArgs, TemplateArgs); - CurContext->addDecl(NewSpec); - AddToScope = false; - } - // Diagnose availability attributes. Availability cannot be used on functions // that are run during load/unload. if (const auto *attr = NewFD->getAttr()) { @@ -12863,6 +12869,15 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, DeducedType *Deduced = Type->getContainedDeducedType(); assert(Deduced && "deduceVarTypeFromInitializer for non-deduced type"); + // Diagnose auto array declarations in C23, unless it's a supported extension. + if (getLangOpts().C23 && Type->isArrayType() && + !isa_and_present(Init)) { + Diag(Range.getBegin(), diag::err_auto_not_allowed) + << (int)Deduced->getContainedAutoType()->getKeyword() + << /*in array decl*/ 23 << Range; + return QualType(); + } + // C++11 [dcl.spec.auto]p3 if (!Init) { assert(VDecl && "no init for init capture deduction?"); @@ -18149,7 +18164,8 @@ ExprResult Sema::VerifyBitField(SourceLocation FieldLoc, // Zero-width bitfield is ok for anonymous field. if (Value == 0 && FieldName) - return Diag(FieldLoc, diag::err_bitfield_has_zero_width) << FieldName; + return Diag(FieldLoc, diag::err_bitfield_has_zero_width) + << FieldName << BitWidth->getSourceRange(); if (Value.isSigned() && Value.isNegative()) { if (FieldName) @@ -18203,8 +18219,8 @@ ExprResult Sema::VerifyBitField(SourceLocation FieldLoc, /// to create a FieldDecl object for it. Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth) { - FieldDecl *Res = HandleField(S, cast_or_null(TagD), - DeclStart, D, static_cast(BitfieldWidth), + FieldDecl *Res = HandleField(S, cast_if_present(TagD), DeclStart, + D, BitfieldWidth, /*InitStyle=*/ICIS_NoInit, AS_public); return Res; } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 304aa7d105e26..cf45fc388083c 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -16796,12 +16796,11 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, LangOpts.CPlusPlus11? diag::ext_offsetof_non_standardlayout_type : diag::ext_offsetof_non_pod_type; - if (!IsSafe && !DidWarnAboutNonPOD && - DiagRuntimeBehavior(BuiltinLoc, nullptr, - PDiag(DiagID) - << SourceRange(Components[0].LocStart, OC.LocEnd) - << CurrentType)) + if (!IsSafe && !DidWarnAboutNonPOD && !isUnevaluatedContext()) { + Diag(BuiltinLoc, DiagID) + << SourceRange(Components[0].LocStart, OC.LocEnd) << CurrentType; DidWarnAboutNonPOD = true; + } } // Look for the field. @@ -18312,7 +18311,7 @@ void Sema::MarkExpressionAsImmediateEscalating(Expr *E) { ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) { if (isUnevaluatedContext() || !E.isUsable() || !Decl || - !Decl->isImmediateFunction() || isConstantEvaluated() || + !Decl->isImmediateFunction() || isAlwaysConstantEvaluatedContext() || isCheckingDefaultArgumentOrInitializer() || RebuildingImmediateInvocation || isImmediateFunctionContext()) return E; @@ -18409,6 +18408,8 @@ static void EvaluateAndDiagnoseImmediateInvocation( assert(FD && FD->isImmediateFunction() && "could not find an immediate function in this expression"); + if (FD->isInvalidDecl()) + return; SemaRef.Diag(CE->getBeginLoc(), diag::err_invalid_consteval_call) << FD << FD->isConsteval(); if (auto Context = @@ -20736,7 +20737,7 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { OdrUse = false; if (auto *FD = dyn_cast(E->getDecl())) { - if (!isUnevaluatedContext() && !isConstantEvaluated() && + if (!isUnevaluatedContext() && !isConstantEvaluatedContext() && !isImmediateFunctionContext() && !isCheckingDefaultArgumentOrInitializer() && FD->isImmediateFunction() && !RebuildingImmediateInvocation && diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index d42a21976821a..eb755e2a0c454 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -17553,6 +17553,9 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_partial: Res = ActOnOpenMPPartialClause(nullptr, StartLoc, /*LParenLoc=*/{}, EndLoc); break; + case OMPC_ompx_bare: + Res = ActOnOpenMPXBareClause(StartLoc, EndLoc); + break; case OMPC_if: case OMPC_final: case OMPC_num_threads: @@ -24279,3 +24282,8 @@ OMPClause *Sema::ActOnOpenMPXAttributeClause(ArrayRef Attrs, SourceLocation EndLoc) { return new (Context) OMPXAttributeClause(Attrs, StartLoc, LParenLoc, EndLoc); } + +OMPClause *Sema::ActOnOpenMPXBareClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPXBareClause(StartLoc, EndLoc); +} diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 5ddae2d15518d..ce78994e65538 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -10440,6 +10440,21 @@ bool clang::isBetterOverloadCandidate( // -- F1 is the copy deduction candidate(16.3.1.8) and F2 is not if (Guide1->getDeductionCandidateKind() == DeductionCandidate::Copy) return true; + if (Guide2->getDeductionCandidateKind() == DeductionCandidate::Copy) + return false; + + // --F1 is generated from a non-template constructor and F2 is generated + // from a constructor template + const auto *Constructor1 = Guide1->getCorrespondingConstructor(); + const auto *Constructor2 = Guide2->getCorrespondingConstructor(); + if (Constructor1 && Constructor2) { + bool isC1Templated = Constructor1->getTemplatedKind() != + FunctionDecl::TemplatedKind::TK_NonTemplate; + bool isC2Templated = Constructor2->getTemplatedKind() != + FunctionDecl::TemplatedKind::TK_NonTemplate; + if (isC1Templated != isC2Templated) + return isC2Templated; + } } } @@ -10483,7 +10498,7 @@ bool clang::isBetterOverloadCandidate( if (AS1 != AS2) { if (Qualifiers::isAddressSpaceSupersetOf(AS2, AS1)) return true; - if (Qualifiers::isAddressSpaceSupersetOf(AS2, AS1)) + if (Qualifiers::isAddressSpaceSupersetOf(AS1, AS2)) return false; } } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 080f005e04402..ff370dd1e080b 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -9334,10 +9334,9 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, /// /// There really isn't any useful analysis we can do here, so we /// just store the information. -bool -Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, - const TemplateArgumentListInfo &ExplicitTemplateArgs, - LookupResult &Previous) { +bool Sema::CheckDependentFunctionTemplateSpecialization( + FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs, + LookupResult &Previous) { // Remove anything from Previous that isn't a function template in // the correct context. DeclContext *FDLookupContext = FD->getDeclContext()->getRedeclContext(); @@ -9361,13 +9360,14 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, } F.done(); + bool IsFriend = FD->getFriendObjectKind() != Decl::FOK_None; if (Previous.empty()) { - Diag(FD->getLocation(), - diag::err_dependent_function_template_spec_no_match); + Diag(FD->getLocation(), diag::err_dependent_function_template_spec_no_match) + << IsFriend; for (auto &P : DiscardedCandidates) Diag(P.second->getLocation(), diag::note_dependent_function_template_spec_discard_reason) - << P.first; + << P.first << IsFriend; return true; } diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 69b857d3510dc..62fbd903a0404 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -4842,9 +4842,25 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, return TDK_Success; } + // Make sure that we treat 'char[]' equaly as 'char*' in C23 mode. + auto *String = dyn_cast(Init); + if (getLangOpts().C23 && String && Type.getType()->isArrayType()) { + Diag(Type.getBeginLoc(), diag::ext_c23_auto_non_plain_identifier); + TypeLoc TL = TypeLoc(Init->getType(), Type.getOpaqueData()); + Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(TL); + assert(!Result.isNull() && "substituting DependentTy can't fail"); + return TDK_Success; + } + + // Emit a warning if 'auto*' is used in pedantic and in C23 mode. + if (getLangOpts().C23 && Type.getType()->isPointerType()) { + Diag(Type.getBeginLoc(), diag::ext_c23_auto_non_plain_identifier); + } + auto *InitList = dyn_cast(Init); if (!getLangOpts().CPlusPlus && InitList) { - Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c); + Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c) + << (int)AT->getKeyword() << getLangOpts().C23; return TDK_AlreadyDiagnosed; } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 0b2b775f19a01..ec0f7d1fe0ddd 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2140,7 +2140,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( Function = CXXDeductionGuideDecl::Create( SemaRef.Context, DC, D->getInnerLocStart(), InstantiatedExplicitSpecifier, NameInfo, T, TInfo, - D->getSourceRange().getEnd(), /*Ctor=*/nullptr, + D->getSourceRange().getEnd(), DGuide->getCorrespondingConstructor(), DGuide->getDeductionCandidateKind()); Function->setAccess(D->getAccess()); } else { @@ -2247,42 +2247,46 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( D->isLocalExternDecl() ? Sema::ForExternalRedeclaration : SemaRef.forRedeclarationInCurContext()); - if (DependentFunctionTemplateSpecializationInfo *Info - = D->getDependentSpecializationInfo()) { - assert(isFriend && "non-friend has dependent specialization info?"); + if (DependentFunctionTemplateSpecializationInfo *DFTSI = + D->getDependentSpecializationInfo()) { + assert(isFriend && "dependent specialization info on " + "non-member non-friend function?"); // Instantiate the explicit template arguments. - TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), - Info->getRAngleLoc()); - if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs, - ExplicitArgs)) - return nullptr; - - // Map the candidate templates to their instantiations. - for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) { - Decl *Temp = SemaRef.FindInstantiatedDecl(D->getLocation(), - Info->getTemplate(I), - TemplateArgs); - if (!Temp) return nullptr; + TemplateArgumentListInfo ExplicitArgs; + if (const auto *ArgsWritten = DFTSI->TemplateArgumentsAsWritten) { + ExplicitArgs.setLAngleLoc(ArgsWritten->getLAngleLoc()); + ExplicitArgs.setRAngleLoc(ArgsWritten->getRAngleLoc()); + if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs, + ExplicitArgs)) + return nullptr; + } - Previous.addDecl(cast(Temp)); + // Map the candidates for the primary template to their instantiations. + for (FunctionTemplateDecl *FTD : DFTSI->getCandidates()) { + if (NamedDecl *ND = + SemaRef.FindInstantiatedDecl(D->getLocation(), FTD, TemplateArgs)) + Previous.addDecl(ND); + else + return nullptr; } - if (SemaRef.CheckFunctionTemplateSpecialization(Function, - &ExplicitArgs, - Previous)) + if (SemaRef.CheckFunctionTemplateSpecialization( + Function, + DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr, + Previous)) Function->setInvalidDecl(); IsExplicitSpecialization = true; - } else if (const ASTTemplateArgumentListInfo *Info = + } else if (const ASTTemplateArgumentListInfo *ArgsWritten = D->getTemplateSpecializationArgsAsWritten()) { // The name of this function was written as a template-id. SemaRef.LookupQualifiedName(Previous, DC); // Instantiate the explicit template arguments. - TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), - Info->getRAngleLoc()); - if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs, + TemplateArgumentListInfo ExplicitArgs(ArgsWritten->getLAngleLoc(), + ArgsWritten->getRAngleLoc()); + if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs, ExplicitArgs)) return nullptr; @@ -2404,8 +2408,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( CXXMethodDecl *D, TemplateParameterList *TemplateParams, - std::optional - ClassScopeSpecializationArgs, RewriteKind FunctionRewriteKind) { FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); if (FunctionTemplate && !TemplateParams) { @@ -2635,41 +2637,41 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( // If the name of this function was written as a template-id, instantiate // the explicit template arguments. - if (DependentFunctionTemplateSpecializationInfo *Info - = D->getDependentSpecializationInfo()) { - assert(isFriend && "non-friend has dependent specialization info?"); - + if (DependentFunctionTemplateSpecializationInfo *DFTSI = + D->getDependentSpecializationInfo()) { // Instantiate the explicit template arguments. - TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), - Info->getRAngleLoc()); - if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs, - ExplicitArgs)) - return nullptr; - - // Map the candidate templates to their instantiations. - for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) { - Decl *Temp = SemaRef.FindInstantiatedDecl(D->getLocation(), - Info->getTemplate(I), - TemplateArgs); - if (!Temp) return nullptr; + TemplateArgumentListInfo ExplicitArgs; + if (const auto *ArgsWritten = DFTSI->TemplateArgumentsAsWritten) { + ExplicitArgs.setLAngleLoc(ArgsWritten->getLAngleLoc()); + ExplicitArgs.setRAngleLoc(ArgsWritten->getRAngleLoc()); + if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs, + ExplicitArgs)) + return nullptr; + } - Previous.addDecl(cast(Temp)); + // Map the candidates for the primary template to their instantiations. + for (FunctionTemplateDecl *FTD : DFTSI->getCandidates()) { + if (NamedDecl *ND = + SemaRef.FindInstantiatedDecl(D->getLocation(), FTD, TemplateArgs)) + Previous.addDecl(ND); + else + return nullptr; } - if (SemaRef.CheckFunctionTemplateSpecialization(Method, - &ExplicitArgs, - Previous)) + if (SemaRef.CheckFunctionTemplateSpecialization( + Method, DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr, + Previous)) Method->setInvalidDecl(); IsExplicitSpecialization = true; - } else if (const ASTTemplateArgumentListInfo *Info = - ClassScopeSpecializationArgs.value_or( - D->getTemplateSpecializationArgsAsWritten())) { + } else if (const ASTTemplateArgumentListInfo *ArgsWritten = + D->getTemplateSpecializationArgsAsWritten()) { SemaRef.LookupQualifiedName(Previous, DC); - TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), - Info->getRAngleLoc()); - if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs, + TemplateArgumentListInfo ExplicitArgs(ArgsWritten->getLAngleLoc(), + ArgsWritten->getRAngleLoc()); + + if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs, ExplicitArgs)) return nullptr; @@ -2678,14 +2680,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( Previous)) Method->setInvalidDecl(); - IsExplicitSpecialization = true; - } else if (ClassScopeSpecializationArgs) { - // Class-scope explicit specialization written without explicit template - // arguments. - SemaRef.LookupQualifiedName(Previous, DC); - if (SemaRef.CheckFunctionTemplateSpecialization(Method, nullptr, Previous)) - Method->setInvalidDecl(); - IsExplicitSpecialization = true; } else if (!FunctionTemplate || TemplateParams || isFriend) { SemaRef.LookupQualifiedName(Previous, Record); @@ -3510,13 +3504,6 @@ Decl *TemplateDeclInstantiator::VisitUsingPackDecl(UsingPackDecl *D) { return NewD; } -Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( - ClassScopeFunctionSpecializationDecl *Decl) { - CXXMethodDecl *OldFD = Decl->getSpecialization(); - return cast_or_null( - VisitCXXMethodDecl(OldFD, nullptr, Decl->getTemplateArgsAsWritten())); -} - Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( OMPThreadPrivateDecl *D) { SmallVector Vars; @@ -4094,14 +4081,14 @@ FunctionDecl *Sema::SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD, Decl *R; if (auto *MD = dyn_cast(Spaceship)) { R = Instantiator.VisitCXXMethodDecl( - MD, nullptr, std::nullopt, + MD, /*TemplateParams=*/nullptr, TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual); } else { assert(Spaceship->getFriendObjectKind() && "defaulted spaceship is neither a member nor a friend"); R = Instantiator.VisitFunctionDecl( - Spaceship, nullptr, + Spaceship, /*TemplateParams=*/nullptr, TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual); if (!R) return nullptr; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 8f732682e0379..068971f8130a4 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -9880,11 +9880,14 @@ QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) { DisallowedKind = 5; else if (T->isSizelessType()) DisallowedKind = 6; - else if (!T.isTriviallyCopyableType(Context)) + else if (!T.isTriviallyCopyableType(Context) && getLangOpts().CPlusPlus) // Some other non-trivially-copyable type (probably a C++ class) DisallowedKind = 7; else if (T->isBitIntType()) DisallowedKind = 8; + else if (getLangOpts().C23 && T->isUndeducedAutoType()) + // _Atomic auto is prohibited in C23 + DisallowedKind = 9; if (DisallowedKind != -1) { Diag(Loc, diag::err_atomic_specifier_bad_type) << DisallowedKind << T; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 0fc5ad8e3bde6..8fafdd4f5caa1 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2391,6 +2391,15 @@ class TreeTransform { EndLoc); } + /// Build a new OpenMP 'ompx_bare' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPXBareClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPXBareClause(StartLoc, EndLoc); + } + /// Build a new OpenMP 'align' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. @@ -5490,6 +5499,9 @@ TreeTransform::TransformDependentSizedArrayType(TypeLocBuilder &TLB, EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); + // If we have a VLA then it won't be a constant. + SemaRef.ExprEvalContexts.back().InConditionallyConstantEvaluateContext = true; + // Prefer the expression from the TypeLoc; the other may have been uniqued. Expr *origSize = TL.getSizeExpr(); if (!origSize) origSize = T->getSizeExpr(); @@ -10804,6 +10816,11 @@ TreeTransform::TransformOMPXAttributeClause(OMPXAttributeClause *C) { NewAttrs, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } +template +OMPClause *TreeTransform::TransformOMPXBareClause(OMPXBareClause *C) { + return getDerived().RebuildOMPXBareClause(C->getBeginLoc(), C->getEndLoc()); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index 72e5821074809..6110e287b7fb5 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -424,7 +424,6 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::StaticAssert: case Decl::Block: case Decl::Captured: - case Decl::ClassScopeFunctionSpecialization: case Decl::Import: case Decl::OMPThreadPrivate: case Decl::OMPAllocate: diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 0c9c5992c267b..9ea8c8eacaa93 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -1444,6 +1444,79 @@ llvm::Error ASTReader::ReadSourceManagerBlock(ModuleFile &F) { } } +llvm::Expected +ASTReader::readSLocOffset(ModuleFile *F, unsigned Index) { + BitstreamCursor &Cursor = F->SLocEntryCursor; + SavedStreamPosition SavedPosition(Cursor); + if (llvm::Error Err = Cursor.JumpToBit(F->SLocEntryOffsetsBase + + F->SLocEntryOffsets[Index])) + return std::move(Err); + + Expected MaybeEntry = Cursor.advance(); + if (!MaybeEntry) + return MaybeEntry.takeError(); + + llvm::BitstreamEntry Entry = MaybeEntry.get(); + if (Entry.Kind != llvm::BitstreamEntry::Record) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "incorrectly-formatted source location entry in AST file"); + + RecordData Record; + StringRef Blob; + Expected MaybeSLOC = Cursor.readRecord(Entry.ID, Record, &Blob); + if (!MaybeSLOC) + return MaybeSLOC.takeError(); + + switch (MaybeSLOC.get()) { + default: + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "incorrectly-formatted source location entry in AST file"); + case SM_SLOC_FILE_ENTRY: + case SM_SLOC_BUFFER_ENTRY: + case SM_SLOC_EXPANSION_ENTRY: + return F->SLocEntryBaseOffset + Record[0]; + } +} + +int ASTReader::getSLocEntryID(SourceLocation::UIntTy SLocOffset) { + auto SLocMapI = + GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - SLocOffset - 1); + assert(SLocMapI != GlobalSLocOffsetMap.end() && + "Corrupted global sloc offset map"); + ModuleFile *F = SLocMapI->second; + + bool Invalid = false; + + auto It = llvm::upper_bound( + llvm::index_range(0, F->LocalNumSLocEntries), SLocOffset, + [&](SourceLocation::UIntTy Offset, std::size_t LocalIndex) { + int ID = F->SLocEntryBaseID + LocalIndex; + std::size_t Index = -ID - 2; + if (!SourceMgr.SLocEntryOffsetLoaded[Index]) { + assert(!SourceMgr.SLocEntryLoaded[Index]); + auto MaybeEntryOffset = readSLocOffset(F, LocalIndex); + if (!MaybeEntryOffset) { + Error(MaybeEntryOffset.takeError()); + Invalid = true; + return true; + } + SourceMgr.LoadedSLocEntryTable[Index] = + SrcMgr::SLocEntry::getOffsetOnly(*MaybeEntryOffset); + SourceMgr.SLocEntryOffsetLoaded[Index] = true; + } + return Offset < SourceMgr.LoadedSLocEntryTable[Index].getOffset(); + }); + + if (Invalid) + return 0; + + // The iterator points to the first entry with start offset greater than the + // offset of interest. The previous entry must contain the offset of interest. + return F->SLocEntryBaseID + *std::prev(It); +} + bool ASTReader::ReadSLocEntry(int ID) { if (ID == 0) return false; @@ -3226,7 +3299,6 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F, case SOURCE_LOCATION_OFFSETS: case MODULE_OFFSET_MAP: case SOURCE_MANAGER_LINE_TABLE: - case SOURCE_LOCATION_PRELOADS: case PPD_ENTITIES_OFFSETS: case HEADER_SEARCH_TABLE: case IMPORTED_MODULES: @@ -3576,18 +3648,6 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F, ParseLineTable(F, Record); break; - case SOURCE_LOCATION_PRELOADS: { - // Need to transform from the local view (1-based IDs) to the global view, - // which is based off F.SLocEntryBaseID. - if (!F.PreloadSLocEntries.empty()) - return llvm::createStringError( - std::errc::illegal_byte_sequence, - "Multiple SOURCE_LOCATION_PRELOADS records in AST file"); - - F.PreloadSLocEntries.swap(Record); - break; - } - case EXT_VECTOR_DECLS: for (unsigned I = 0, N = Record.size(); I != N; ++I) ExtVectorDecls.push_back(getGlobalDeclID(F, Record[I])); @@ -4417,16 +4477,6 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, ModuleKind Type, for (ImportedModule &M : Loaded) { ModuleFile &F = *M.Mod; - // Preload SLocEntries. - for (unsigned I = 0, N = F.PreloadSLocEntries.size(); I != N; ++I) { - int Index = int(F.PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID; - // Load it through the SourceManager and don't call ReadSLocEntry() - // directly because the entry may have already been loaded in which case - // calling ReadSLocEntry() directly would trigger an assertion in - // SourceManager. - SourceMgr.getLoadedSLocEntryByID(Index); - } - // Map the original source file ID into the ID space of the current // compilation. if (F.OriginalSourceFileID.isValid()) @@ -7385,15 +7435,20 @@ TemplateArgumentLoc ASTRecordReader::readTemplateArgumentLoc() { return TemplateArgumentLoc(Arg, readTemplateArgumentLocInfo(Arg.getKind())); } -const ASTTemplateArgumentListInfo * -ASTRecordReader::readASTTemplateArgumentListInfo() { - SourceLocation LAngleLoc = readSourceLocation(); - SourceLocation RAngleLoc = readSourceLocation(); +void ASTRecordReader::readTemplateArgumentListInfo( + TemplateArgumentListInfo &Result) { + Result.setLAngleLoc(readSourceLocation()); + Result.setRAngleLoc(readSourceLocation()); unsigned NumArgsAsWritten = readInt(); - TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc); for (unsigned i = 0; i != NumArgsAsWritten; ++i) - TemplArgsInfo.addArgument(readTemplateArgumentLoc()); - return ASTTemplateArgumentListInfo::Create(getContext(), TemplArgsInfo); + Result.addArgument(readTemplateArgumentLoc()); +} + +const ASTTemplateArgumentListInfo * +ASTRecordReader::readASTTemplateArgumentListInfo() { + TemplateArgumentListInfo Result; + readTemplateArgumentListInfo(Result); + return ASTTemplateArgumentListInfo::Create(getContext(), Result); } Decl *ASTReader::GetExternalDecl(uint32_t ID) { @@ -10447,6 +10502,9 @@ OMPClause *OMPClauseReader::readClause() { case llvm::omp::OMPC_ompx_attribute: C = new (Context) OMPXAttributeClause(); break; + case llvm::omp::OMPC_ompx_bare: + C = new (Context) OMPXBareClause(); + break; #define OMP_CLAUSE_NO_CLASS(Enum, Str) \ case llvm::omp::Enum: \ break; @@ -11548,6 +11606,8 @@ void OMPClauseReader::VisitOMPXAttributeClause(OMPXAttributeClause *C) { C->setLocEnd(Record.readSourceLocation()); } +void OMPClauseReader::VisitOMPXBareClause(OMPXBareClause *C) {} + OMPTraitInfo *ASTRecordReader::readOMPTraitInfo() { OMPTraitInfo &TI = getContext().getNewOMPTraitInfo(); TI.Sets.resize(readUInt32()); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index d553b3c6d78de..3a3477c39efae 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -358,9 +358,7 @@ namespace clang { } void VisitClassTemplatePartialSpecializationDecl( - ClassTemplatePartialSpecializationDecl *D); - void VisitClassScopeFunctionSpecializationDecl( - ClassScopeFunctionSpecializationDecl *D); + ClassTemplatePartialSpecializationDecl *D); RedeclarableResult VisitVarTemplateSpecializationDeclImpl(VarTemplateSpecializationDecl *D); @@ -950,27 +948,16 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true); // Template args as written. - SmallVector TemplArgLocs; - SourceLocation LAngleLoc, RAngleLoc; - bool HasTemplateArgumentsAsWritten = Record.readInt(); - if (HasTemplateArgumentsAsWritten) { - unsigned NumTemplateArgLocs = Record.readInt(); - TemplArgLocs.reserve(NumTemplateArgLocs); - for (unsigned i = 0; i != NumTemplateArgLocs; ++i) - TemplArgLocs.push_back(Record.readTemplateArgumentLoc()); - - LAngleLoc = readSourceLocation(); - RAngleLoc = readSourceLocation(); - } + TemplateArgumentListInfo TemplArgsWritten; + bool HasTemplateArgumentsAsWritten = Record.readBool(); + if (HasTemplateArgumentsAsWritten) + Record.readTemplateArgumentListInfo(TemplArgsWritten); SourceLocation POI = readSourceLocation(); ASTContext &C = Reader.getContext(); - TemplateArgumentList *TemplArgList - = TemplateArgumentList::CreateCopy(C, TemplArgs); - TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc); - for (unsigned i = 0, e = TemplArgLocs.size(); i != e; ++i) - TemplArgsInfo.addArgument(TemplArgLocs[i]); + TemplateArgumentList *TemplArgList = + TemplateArgumentList::CreateCopy(C, TemplArgs); MemberSpecializationInfo *MSInfo = nullptr; if (Record.readInt()) { @@ -985,7 +972,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FunctionTemplateSpecializationInfo *FTInfo = FunctionTemplateSpecializationInfo::Create( C, FD, Template, TSK, TemplArgList, - HasTemplateArgumentsAsWritten ? &TemplArgsInfo : nullptr, POI, + HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr, POI, MSInfo); FD->TemplateOrSpecialization = FTInfo; @@ -1016,21 +1003,20 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { } case FunctionDecl::TK_DependentFunctionTemplateSpecialization: { // Templates. - UnresolvedSet<8> TemplDecls; - unsigned NumTemplates = Record.readInt(); - while (NumTemplates--) - TemplDecls.addDecl(readDeclAs()); + UnresolvedSet<8> Candidates; + unsigned NumCandidates = Record.readInt(); + while (NumCandidates--) + Candidates.addDecl(readDeclAs()); // Templates args. - TemplateArgumentListInfo TemplArgs; - unsigned NumArgs = Record.readInt(); - while (NumArgs--) - TemplArgs.addArgument(Record.readTemplateArgumentLoc()); - TemplArgs.setLAngleLoc(readSourceLocation()); - TemplArgs.setRAngleLoc(readSourceLocation()); - - FD->setDependentTemplateSpecialization(Reader.getContext(), - TemplDecls, TemplArgs); + TemplateArgumentListInfo TemplArgsWritten; + bool HasTemplateArgumentsAsWritten = Record.readBool(); + if (HasTemplateArgumentsAsWritten) + Record.readTemplateArgumentListInfo(TemplArgsWritten); + + FD->setDependentTemplateSpecialization( + Reader.getContext(), Candidates, + HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr); // These are not merged; we don't need to merge redeclarations of dependent // template friends. break; @@ -2002,13 +1988,16 @@ void ASTDeclReader::ReadCXXDefinitionData( case LCK_StarThis: case LCK_This: case LCK_VLAType: - *ToCapture++ = Capture(Loc, IsImplicit, Kind, nullptr,SourceLocation()); + new (ToCapture) + Capture(Loc, IsImplicit, Kind, nullptr, SourceLocation()); + ToCapture++; break; case LCK_ByCopy: case LCK_ByRef: auto *Var = readDeclAs(); SourceLocation EllipsisLoc = readSourceLocation(); - *ToCapture++ = Capture(Loc, IsImplicit, Kind, Var, EllipsisLoc); + new (ToCapture) Capture(Loc, IsImplicit, Kind, Var, EllipsisLoc); + ToCapture++; break; } } @@ -2522,14 +2511,6 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl( } } -void ASTDeclReader::VisitClassScopeFunctionSpecializationDecl( - ClassScopeFunctionSpecializationDecl *D) { - VisitDecl(D); - D->Specialization = readDeclAs(); - if (Record.readInt()) - D->TemplateArgs = Record.readASTTemplateArgumentListInfo(); -} - void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D); @@ -3878,9 +3859,6 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION: D = VarTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID); break; - case DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION: - D = ClassScopeFunctionSpecializationDecl::CreateDeserialized(Context, ID); - break; case DECL_FUNCTION_TEMPLATE: D = FunctionTemplateDecl::CreateDeserialized(Context, ID); break; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 201e2fcaaec91..27700c711d52f 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -839,7 +839,6 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(METHOD_POOL); RECORD(PP_COUNTER_VALUE); RECORD(SOURCE_LOCATION_OFFSETS); - RECORD(SOURCE_LOCATION_PRELOADS); RECORD(EXT_VECTOR_DECLS); RECORD(UNUSED_FILESCOPED_DECLS); RECORD(PPD_ENTITIES_OFFSETS); @@ -1030,7 +1029,6 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(DECL_INDIRECTFIELD); RECORD(DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK); RECORD(DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK); - RECORD(DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION); RECORD(DECL_IMPORT); RECORD(DECL_OMP_THREADPRIVATE); RECORD(DECL_EMPTY); @@ -2138,7 +2136,6 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // entry, which is always the same dummy entry. std::vector SLocEntryOffsets; uint64_t SLocEntryOffsetsBase = Stream.GetCurrentBitNo(); - RecordData PreloadSLocs; SLocEntryOffsets.reserve(SourceMgr.local_sloc_entry_size() - 1); for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) { @@ -2214,9 +2211,6 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record, StringRef(Name.data(), Name.size() + 1)); EmitBlob = true; - - if (Name == "") - PreloadSLocs.push_back(SLocEntryOffsets.size()); } if (EmitBlob) { @@ -2278,9 +2272,6 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, bytes(SLocEntryOffsets)); } - // Write the source location entry preloads array, telling the AST - // reader which source locations entries it should load eagerly. - Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs); // Write the line table. It depends on remapping working, so it must come // after the source location offsets. @@ -4622,12 +4613,12 @@ time_t ASTWriter::getTimestampForOutput(const FileEntry *E) const { ASTFileSignature ASTWriter::WriteAST(Sema &SemaRef, StringRef OutputFile, Module *WritingModule, StringRef isysroot, - bool hasErrors, bool ShouldCacheASTInMemory) { llvm::TimeTraceScope scope("WriteAST", OutputFile); WritingAST = true; - ASTHasCompilerErrors = hasErrors; + ASTHasCompilerErrors = + SemaRef.PP.getDiagnostics().hasUncompilableErrorOccurred(); // Emit the file header. Stream.Emit((unsigned)'C', 8); @@ -7258,6 +7249,8 @@ void OMPClauseWriter::VisitOMPXAttributeClause(OMPXAttributeClause *C) { Record.AddSourceLocation(C->getEndLoc()); } +void OMPClauseWriter::VisitOMPXBareClause(OMPXBareClause *C) {} + void ASTRecordWriter::writeOMPTraitInfo(const OMPTraitInfo *TI) { writeUInt32(TI->Sets.size()); for (const auto &Set : TI->Sets) { diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 91c8ed9f75db1..8a2ea7c7624ce 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -81,8 +81,6 @@ namespace clang { void VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D); void VisitVarTemplatePartialSpecializationDecl( VarTemplatePartialSpecializationDecl *D); - void VisitClassScopeFunctionSpecializationDecl( - ClassScopeFunctionSpecializationDecl *D); void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); void VisitValueDecl(ValueDecl *D); void VisitEnumConstantDecl(EnumConstantDecl *D); @@ -617,15 +615,9 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { // Template args as written. Record.push_back(FTSInfo->TemplateArgumentsAsWritten != nullptr); - if (FTSInfo->TemplateArgumentsAsWritten) { - Record.push_back(FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs); - for (int i=0, e = FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs; - i!=e; ++i) - Record.AddTemplateArgumentLoc( - (*FTSInfo->TemplateArgumentsAsWritten)[i]); - Record.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->LAngleLoc); - Record.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->RAngleLoc); - } + if (FTSInfo->TemplateArgumentsAsWritten) + Record.AddASTTemplateArgumentListInfo( + FTSInfo->TemplateArgumentsAsWritten); Record.AddSourceLocation(FTSInfo->getPointOfInstantiation()); @@ -650,17 +642,16 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { DependentFunctionTemplateSpecializationInfo * DFTSInfo = D->getDependentSpecializationInfo(); - // Templates. - Record.push_back(DFTSInfo->getNumTemplates()); - for (int i=0, e = DFTSInfo->getNumTemplates(); i != e; ++i) - Record.AddDeclRef(DFTSInfo->getTemplate(i)); + // Candidates. + Record.push_back(DFTSInfo->getCandidates().size()); + for (FunctionTemplateDecl *FTD : DFTSInfo->getCandidates()) + Record.AddDeclRef(FTD); // Templates args. - Record.push_back(DFTSInfo->getNumTemplateArgs()); - for (int i=0, e = DFTSInfo->getNumTemplateArgs(); i != e; ++i) - Record.AddTemplateArgumentLoc(DFTSInfo->getTemplateArg(i)); - Record.AddSourceLocation(DFTSInfo->getLAngleLoc()); - Record.AddSourceLocation(DFTSInfo->getRAngleLoc()); + Record.push_back(DFTSInfo->TemplateArgumentsAsWritten != nullptr); + if (DFTSInfo->TemplateArgumentsAsWritten) + Record.AddASTTemplateArgumentListInfo( + DFTSInfo->TemplateArgumentsAsWritten); break; } } @@ -1739,17 +1730,6 @@ void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl( Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION; } -void ASTDeclWriter::VisitClassScopeFunctionSpecializationDecl( - ClassScopeFunctionSpecializationDecl *D) { - VisitDecl(D); - Record.AddDeclRef(D->getSpecialization()); - Record.push_back(D->hasExplicitTemplateArgs()); - if (D->hasExplicitTemplateArgs()) - Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten()); - Code = serialization::DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION; -} - - void ASTDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { VisitRedeclarableTemplateDecl(D); diff --git a/clang/lib/Serialization/GeneratePCH.cpp b/clang/lib/Serialization/GeneratePCH.cpp index 601a24b4aec46..cf8084333811f 100644 --- a/clang/lib/Serialization/GeneratePCH.cpp +++ b/clang/lib/Serialization/GeneratePCH.cpp @@ -65,12 +65,8 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { // Emit the PCH file to the Buffer. assert(SemaPtr && "No Sema?"); - Buffer->Signature = - Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot, - // For serialization we are lenient if the errors were - // only warn-as-error kind. - PP.getDiagnostics().hasUncompilableErrorOccurred(), - ShouldCacheASTInMemory); + Buffer->Signature = Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot, + ShouldCacheASTInMemory); Buffer->IsComplete = true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 18c7f3e4f6e6b..d3a4020280616 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1961,13 +1961,10 @@ ProgramStateRef MallocChecker::FreeMemAux( // Parameters, locals, statics, globals, and memory returned by // __builtin_alloca() shouldn't be freed. if (!isa(MS)) { - // FIXME: at the time this code was written, malloc() regions were - // represented by conjured symbols, which are all in UnknownSpaceRegion. - // This means that there isn't actually anything from HeapSpaceRegion - // that should be freed, even though we allow it here. - // Of course, free() can work on memory allocated outside the current - // function, so UnknownSpaceRegion is always a possibility. - // False negatives are better than false positives. + // Regions returned by malloc() are represented by SymbolicRegion objects + // within HeapSpaceRegion. Of course, free() can work on memory allocated + // outside the current function, so UnknownSpaceRegion is also a + // possibility here. if (isa(R)) HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange()); diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp index a20d24db158f5..66e9a501c348e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp @@ -202,7 +202,7 @@ static QualType getInnerPointerType(CheckerContext C, const CXXRecordDecl *RD) { static QualType getPointerTypeFromTemplateArg(const CallEvent &Call, CheckerContext &C) { const auto *FD = dyn_cast_or_null(Call.getDecl()); - if (!FD || !FD->isFunctionTemplateSpecialization()) + if (!FD || !FD->getPrimaryTemplate()) return {}; const auto &TemplateArgs = FD->getTemplateSpecializationArgs()->asArray(); if (TemplateArgs.size() == 0) diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp index 5e028c4431fe9..40115b7b5ae25 100644 --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -295,8 +295,7 @@ void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) { static std::string getModuleContextHash(const ModuleDeps &MD, const CowCompilerInvocation &CI, bool EagerLoadModules) { - llvm::HashBuilder, - llvm::support::endianness::native> + llvm::HashBuilder, llvm::endianness::native> HashBuilder; SmallString<32> Scratch; diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c index c0ec5f8339dd1..974ca72702f7d 100644 --- a/clang/test/AST/Interp/c.c +++ b/clang/test/AST/Interp/c.c @@ -14,25 +14,36 @@ _Static_assert(!!1.0, ""); // pedantic-ref-warning {{not an integer constant exp // pedantic-expected-warning {{not an integer constant expression}} _Static_assert(!!1, ""); -/// FIXME: Should also be rejected in the new interpreter int a = (1 == 1 ? 5 : 3); _Static_assert(a == 5, ""); // ref-error {{not an integral constant expression}} \ // pedantic-ref-error {{not an integral constant expression}} \ - // pedantic-expected-warning {{not an integer constant expression}} + // expected-error {{not an integral constant expression}} \ + // pedantic-expected-error {{not an integral constant expression}} + const int b = 3; _Static_assert(b == 3, ""); // pedantic-ref-warning {{not an integer constant expression}} \ // pedantic-expected-warning {{not an integer constant expression}} +/// FIXME: The new interpreter is missing the "initializer of 'c' unknown" diagnostics. const int c; // ref-note {{declared here}} \ - // pedantic-ref-note {{declared here}} \ - // expected-note {{declared here}} \ - // pedantic-expected-note {{declared here}} + // pedantic-ref-note {{declared here}} _Static_assert(c == 0, ""); // ref-error {{not an integral constant expression}} \ // ref-note {{initializer of 'c' is unknown}} \ // pedantic-ref-error {{not an integral constant expression}} \ // pedantic-ref-note {{initializer of 'c' is unknown}} \ // expected-error {{not an integral constant expression}} \ - // expected-note {{initializer of 'c' is unknown}} \ - // pedantic-expected-error {{not an integral constant expression}} \ - // pedantic-expected-note {{initializer of 'c' is unknown}} + // pedantic-expected-error {{not an integral constant expression}} + +_Static_assert(&c != 0, ""); // ref-warning {{always true}} \ + // pedantic-ref-warning {{always true}} \ + // pedantic-ref-warning {{is a GNU extension}} \ + // expected-warning {{always true}} \ + // pedantic-expected-warning {{always true}} \ + // pedantic-expected-warning {{is a GNU extension}} +_Static_assert(&a != 0, ""); // ref-warning {{always true}} \ + // pedantic-ref-warning {{always true}} \ + // pedantic-ref-warning {{is a GNU extension}} \ + // expected-warning {{always true}} \ + // pedantic-expected-warning {{always true}} \ + // pedantic-expected-warning {{is a GNU extension}} diff --git a/clang/test/AST/Interp/intap.cpp b/clang/test/AST/Interp/intap.cpp new file mode 100644 index 0000000000000..4ca65e1040484 --- /dev/null +++ b/clang/test/AST/Interp/intap.cpp @@ -0,0 +1,79 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -fms-extensions -std=c++11 -verify %s +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -fms-extensions -std=c++20 -verify %s +// RUN: %clang_cc1 -std=c++11 -fms-extensions -verify=ref %s +// RUN: %clang_cc1 -std=c++20 -fms-extensions -verify=ref %s + +#ifdef __SIZEOF_INT128__ +namespace i128 { + typedef __int128 int128_t; + typedef unsigned __int128 uint128_t; + constexpr int128_t I128_1 = 12; + static_assert(I128_1 == 12, ""); + static_assert(I128_1 != 10, ""); + static_assert(I128_1 != 12, ""); // expected-error{{failed}} \ + // ref-error{{failed}} \ + // expected-note{{evaluates to}} \ + // ref-note{{evaluates to}} + + static const __uint128_t UINT128_MAX =__uint128_t(__int128_t(-1L)); + static_assert(UINT128_MAX == -1, ""); + + static const __int128_t INT128_MAX = UINT128_MAX >> (__int128_t)1; + static_assert(INT128_MAX != 0, ""); + static const __int128_t INT128_MIN = -INT128_MAX - 1; + constexpr __int128 A = INT128_MAX + 1; // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{outside the range}} \ + // ref-error {{must be initialized by a constant expression}} \ + // ref-note {{outside the range}} + constexpr int128_t Two = (int128_t)1 << 1ul; + static_assert(Two == 2, ""); + + constexpr uint128_t AllOnes = ~static_cast(0); + static_assert(AllOnes == UINT128_MAX, ""); + +#if __cplusplus >= 201402L + template + constexpr T CastFrom(__int128_t A) { + T B = (T)A; + return B; + } + static_assert(CastFrom(12) == 12, ""); + static_assert(CastFrom(12) == 12, ""); + static_assert(CastFrom(12) == 12, ""); + static_assert(CastFrom(12) == 12, ""); + static_assert(CastFrom(12) == 12, ""); + static_assert(CastFrom(12) == 12, ""); + static_assert(CastFrom(12) == 12, ""); + static_assert(CastFrom(12) == 12, ""); + + static_assert(CastFrom(AllOnes) == -1, ""); + static_assert(CastFrom(AllOnes) == 0xFF, ""); + static_assert(CastFrom(AllOnes) == -1, ""); + static_assert(CastFrom(AllOnes) == 0xFFFF, ""); + static_assert(CastFrom(AllOnes) == -1, ""); + static_assert(CastFrom(AllOnes) == -1, ""); + static_assert(CastFrom(AllOnes) == AllOnes, ""); + + template + constexpr __int128 CastTo(T A) { + int128_t B = (int128_t)A; + return B; + } + static_assert(CastTo(12) == 12, ""); + static_assert(CastTo(12) == 12, ""); + static_assert(CastTo(12) == 12, ""); + static_assert(CastTo(12) == 12, ""); + static_assert(CastTo(12) == 12, ""); + static_assert(CastTo(12) == 12, ""); + static_assert(CastTo(12) == 12, ""); +#endif + + constexpr int128_t Error = __LDBL_MAX__; // ref-warning {{implicit conversion of out of range value}} \ + // ref-error {{must be initialized by a constant expression}} \ + // ref-note {{is outside the range of representable values of type}} \ + // expected-warning {{implicit conversion of out of range value}} \ + // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{is outside the range of representable values of type}} +} + +#endif diff --git a/clang/test/AST/Interp/lambda.cpp b/clang/test/AST/Interp/lambda.cpp index da1d706af1d05..f8400898acc0c 100644 --- a/clang/test/AST/Interp/lambda.cpp +++ b/clang/test/AST/Interp/lambda.cpp @@ -179,3 +179,24 @@ namespace LambdasAsParams { } static_assert(heh() == 1.0); } + +namespace ThisCapture { + class Foo { + public: + int b = 32; + int a; + + constexpr Foo() : a([this](){ return b + 1;}()) {} + + constexpr int Aplus2() const { + auto F = [this]() { + return a + 2; + }; + + return F(); + } + }; + constexpr Foo F; + static_assert(F.a == 33, ""); + static_assert(F.Aplus2() == (33 + 2), ""); +} diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index 00875bcf44dc8..ceda59405ea91 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -26,81 +26,6 @@ static_assert(number != 10, ""); // expected-error{{failed}} \ // expected-note{{evaluates to}} \ // ref-note{{evaluates to}} - -#ifdef __SIZEOF_INT128__ -namespace i128 { - typedef __int128 int128_t; - typedef unsigned __int128 uint128_t; - constexpr int128_t I128_1 = 12; - static_assert(I128_1 == 12, ""); - static_assert(I128_1 != 10, ""); - static_assert(I128_1 != 12, ""); // expected-error{{failed}} \ - // ref-error{{failed}} \ - // expected-note{{evaluates to}} \ - // ref-note{{evaluates to}} - - static const __uint128_t UINT128_MAX =__uint128_t(__int128_t(-1L)); - static_assert(UINT128_MAX == -1, ""); - - static const __int128_t INT128_MAX = UINT128_MAX >> (__int128_t)1; - static_assert(INT128_MAX != 0, ""); - static const __int128_t INT128_MIN = -INT128_MAX - 1; - constexpr __int128 A = INT128_MAX + 1; // expected-error {{must be initialized by a constant expression}} \ - // expected-note {{outside the range}} \ - // ref-error {{must be initialized by a constant expression}} \ - // ref-note {{outside the range}} - constexpr int128_t Two = (int128_t)1 << 1ul; - static_assert(Two == 2, ""); - - constexpr uint128_t AllOnes = ~static_cast(0); - static_assert(AllOnes == UINT128_MAX, ""); - -#if __cplusplus >= 201402L - template - constexpr T CastFrom(__int128_t A) { - T B = (T)A; - return B; - } - static_assert(CastFrom(12) == 12, ""); - static_assert(CastFrom(12) == 12, ""); - static_assert(CastFrom(12) == 12, ""); - static_assert(CastFrom(12) == 12, ""); - static_assert(CastFrom(12) == 12, ""); - static_assert(CastFrom(12) == 12, ""); - static_assert(CastFrom(12) == 12, ""); - static_assert(CastFrom(12) == 12, ""); - - static_assert(CastFrom(AllOnes) == -1, ""); - static_assert(CastFrom(AllOnes) == 0xFF, ""); - static_assert(CastFrom(AllOnes) == -1, ""); - static_assert(CastFrom(AllOnes) == 0xFFFF, ""); - static_assert(CastFrom(AllOnes) == -1, ""); - static_assert(CastFrom(AllOnes) == -1, ""); - static_assert(CastFrom(AllOnes) == AllOnes, ""); - - template - constexpr __int128 CastTo(T A) { - int128_t B = (int128_t)A; - return B; - } - static_assert(CastTo(12) == 12, ""); - static_assert(CastTo(12) == 12, ""); - static_assert(CastTo(12) == 12, ""); - static_assert(CastTo(12) == 12, ""); - static_assert(CastTo(12) == 12, ""); - static_assert(CastTo(12) == 12, ""); - static_assert(CastTo(12) == 12, ""); -#endif - -constexpr int128_t Error = __LDBL_MAX__; // ref-warning {{implicit conversion of out of range value}} \ - // ref-error {{must be initialized by a constant expression}} \ - // ref-note {{is outside the range of representable values of type}} \ - // expected-warning {{implicit conversion of out of range value}} \ - // expected-error {{must be initialized by a constant expression}} \ - // expected-note {{is outside the range of representable values of type}} -} -#endif - constexpr bool b = number; static_assert(b, ""); constexpr int one = true; diff --git a/clang/test/AST/ast-dump-decl.cpp b/clang/test/AST/ast-dump-decl.cpp index 6848a2b01da2c..017e640aeaea6 100644 --- a/clang/test/AST/ast-dump-decl.cpp +++ b/clang/test/AST/ast-dump-decl.cpp @@ -645,11 +645,16 @@ class TestClassScopeFunctionSpecialization { template void foo(U a) { } template<> void foo(int a) { } }; -// CHECK: ClassScopeFunctionSpecializationDecl -// CHECK-NEXT: CXXMethod{{.*}} foo 'void (int)' +// CHECK: FunctionTemplateDecl{{.*}} foo +// CHECK-NEXT: TemplateTypeParmDecl{{.*}} referenced class depth 1 index 0 U +// CHECK-NEXT: CXXMethodDecl{{.*}} foo 'void (U)' implicit-inline // CHECK-NEXT: ParmVarDecl // CHECK-NEXT: CompoundStmt +// CHECK-NEXT: CXXMethodDecl{{.*}} foo 'void (int)' explicit_specialization implicit-inline // CHECK-NEXT: TemplateArgument{{.*}} 'int' +// CHECK-NEXT: BuiltinType{{.*}} 'int' +// CHECK-NEXT: ParmVarDecl +// CHECK-NEXT: CompoundStmt namespace TestTemplateTypeParmDecl { template void foo(); diff --git a/clang/test/C/C2x/n3007.c b/clang/test/C/C2x/n3007.c new file mode 100644 index 0000000000000..1fd20332ceb47 --- /dev/null +++ b/clang/test/C/C2x/n3007.c @@ -0,0 +1,186 @@ +// RUN: %clang_cc1 -std=c2x -verify -pedantic -Wno-comments %s + +/* WG14 N3007: Yes + * Type Inference for object definitions + */ +void test_qualifiers(int x, const int y, int * restrict z) { + const auto a = x; + auto b = y; + static auto c = 1UL; + int* pa = &a; // expected-warning {{initializing 'int *' with an expression of type 'const int *' discards qualifiers}} + const int* pb = &b; + int* pc = &c; // expected-warning {{incompatible pointer types initializing 'int *' with an expression of type 'unsigned long *'}} + + const int ci = 12; + auto yup = ci; + yup = 12; + + auto r_test = z; + + _Static_assert(_Generic(a, int : 1)); + _Static_assert(_Generic(c, unsigned long : 1)); + _Static_assert(_Generic(pa, int * : 1)); + _Static_assert(_Generic(pb, const int * : 1)); + _Static_assert(_Generic(r_test, int * : 1)); +} + +void test_atomic(void) { + _Atomic auto i = 12; // expected-error {{_Atomic cannot be applied to type 'auto' in C23}} + _Atomic(auto) j = 12; // expected-error {{'auto' not allowed here}} \ + expected-error {{a type specifier is required for all declarations}} + + _Atomic(int) foo(void); + auto k = foo(); + + _Static_assert(_Generic(&i, _Atomic auto *: 1)); // expected-error {{_Atomic cannot be applied to type 'auto' in C23}} \ + expected-error {{'auto' not allowed here}} + _Static_assert(_Generic(k, int: 1)); +} + +void test_double(void) { + double A[3] = { 0 }; + auto pA = A; + auto qA = &A; + auto pi = 3.14; + + _Static_assert(_Generic(A, double * : 1)); + _Static_assert(_Generic(pA, double * : 1)); + _Static_assert(_Generic(qA, double (*)[3] : 1)); + _Static_assert(_Generic(pi, double : 1)); +} + +int test_auto_param(auto a) { // expected-error {{'auto' not allowed in function prototype}} + return (int)(a * 2); +} + +auto test_auto_return(float a, int b) { // expected-error {{'auto' not allowed in function return type}} + return ((a * b) * (a / b)); +} + +[[clang::overloadable]] auto test(auto x) { // expected-error {{'auto' not allowed in function prototype}} \ + expected-error {{'auto' not allowed in function return type}} + return x; +} + +void test_sizeof_alignas(void) { + (void)sizeof(auto); // expected-error {{expected expression}} + _Alignas(auto) int a[4]; // expected-error {{expected expression}} +} + +void test_arrary(void) { + auto a[4]; // expected-error {{'auto' not allowed in array declaration}} + auto b[] = {1, 2}; // expected-error {{cannot use 'auto' with array in C}} +} + +void test_initializer_list(void) { + auto a = {}; // expected-error {{cannot use 'auto' with array in C}} + auto b = { 0 }; // expected-error {{cannot use 'auto' with array in C}} + auto c = { 1, }; // expected-error {{cannot use 'auto' with array in C}} + auto d = { 1 , 2 }; // expected-error {{cannot use 'auto' with array in C}} + auto e = (int [3]){ 1, 2, 3 }; +} + +void test_structs(void) { + // FIXME: Both of these should be diagnosed as invalid underspecified + // declarations as described in N3006. + auto p1 = (struct { int a; } *)0; + struct s; + auto p2 = (struct s { int a; } *)0; + + struct B { auto b; }; // expected-error {{'auto' not allowed in struct member}} +} + +void test_typedefs(void) { + typedef auto auto_type; // expected-error {{'auto' not allowed in typedef}} + + typedef auto (*fp)(void); // expected-error {{'auto' not allowed in typedef}} + typedef void (*fp)(auto); // expected-error {{'auto' not allowed in function prototype}} + + _Generic(0, auto : 1); // expected-error {{'auto' not allowed here}} +} + +void test_misc(void) { + auto something; // expected-error {{declaration of variable 'something' with deduced type 'auto' requires an initializer}} + auto test_char = 'A'; + auto test_char_ptr = "test"; + auto test_char_ptr2[] = "another test"; // expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + auto auto_size = sizeof(auto); // expected-error {{expected expression}} + + _Static_assert(_Generic(test_char, int : 1)); + _Static_assert(_Generic(test_char_ptr, char * : 1)); + _Static_assert(_Generic(test_char_ptr2, char * : 1)); +} + +void test_no_integer_promotions(void) { + short s; + auto a = s; + _Generic(a, int : 1); // expected-error {{controlling expression type 'short' not compatible with any generic association type}} +} + +void test_compound_literals(void) { + auto a = (int){}; + auto b = (int){ 0 }; + auto c = (int){ 0, }; + auto d = (int){ 0, 1 }; // expected-warning {{excess elements in scalar initializer}} + + auto auto_cl = (auto){13}; // expected-error {{expected expression}} + + _Static_assert(_Generic(a, int : 1)); + _Static_assert(_Generic(b, int : 1)); + _Static_assert(_Generic(c, int : 1)); +} + +void test_pointers(void) { + int a; + auto *ptr = &a; // expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + auto *ptr2 = a; // expected-error {{variable 'ptr2' with type 'auto *' has incompatible initializer of type 'int'}} \ + expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + auto nptr = nullptr; + + _Static_assert(_Generic(ptr, int * : 1)); + _Static_assert(_Generic(ptr2, int * : 1)); +} + +void test_scopes(void) { + double a = 7; + double b = 9; + { + auto a = a * a; // expected-error {{variable 'a' declared with deduced type 'auto' cannot appear in its own initializer}} \ + expected-error {{variable 'a' declared with deduced type 'auto' cannot appear in its own initializer}} + } + { + auto b = a * a; + auto a = b; + + _Static_assert(_Generic(a, double : 1)); + _Static_assert(_Generic(b, double : 1)); + } +} + +void test_loop(void) { + auto j = 4; + for (auto i = j; i < 2 * j; i++); + + _Static_assert(_Generic(j, int : 1)); +} + +#define AUTO_MACRO(_NAME, ARG, ARG2, ARG3) \ +auto _NAME = ARG + (ARG2 / ARG3); + +// This macro should only work with integers due to the usage of binary operators +#define AUTO_INT_MACRO(_NAME, ARG, ARG2, ARG3) \ +auto _NAME = (ARG ^ ARG2) & ARG3; + +void test_macros(int in_int) { + auto a = in_int + 1; + AUTO_MACRO(b, 1.3, 2.5f, 3); + AUTO_INT_MACRO(c, 64, 23, 0xff); + AUTO_INT_MACRO(not_valid, 51.5, 25, 0xff); // expected-error {{invalid operands to binary expression ('double' and 'int')}} + + auto result = (a + (int)b) - c; + + _Static_assert(_Generic(a, int : 1)); + _Static_assert(_Generic(b, double : 1)); + _Static_assert(_Generic(c, int : 1)); + _Static_assert(_Generic(result, int : 1)); +} diff --git a/clang/test/CXX/drs/dr7xx.cpp b/clang/test/CXX/drs/dr7xx.cpp index f6a2e5923bedb..11901b80d6462 100644 --- a/clang/test/CXX/drs/dr7xx.cpp +++ b/clang/test/CXX/drs/dr7xx.cpp @@ -111,6 +111,11 @@ namespace dr727 { // dr727: partial template struct C {}; template static const int N; + + template + struct E { + template<> void f() {} // expected-error {{no candidate function template}} + }; }; void d(D di) { diff --git a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp index 4eac0a1ac510f..49fde292f6a36 100644 --- a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp +++ b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp @@ -85,3 +85,38 @@ int main() { } + +namespace deduceTemplatedConstructor { +template struct IsSame { + static constexpr bool value = false; +}; + +template struct IsSame { + static constexpr bool value = true; +}; +template struct A { + using value_type = T; + A(value_type); + A(const A&); + A(T, T, int); + template + A(int, T, U); +}; + +A x(1, 2, 3); // no-error +static_assert(IsSame>::value); + +template +A(T) -> A; + +A a(42); +static_assert(IsSame>::value); +A b = a; +static_assert(IsSame>::value); + +template +A(A) -> A>; + +A b2 = a; +static_assert(IsSame>>::value); +} diff --git a/clang/test/CodeGen/PowerPC/ppc64-inline-asm.c b/clang/test/CodeGen/PowerPC/ppc64-inline-asm.c index e3f2c2ff5507c..005bf5c7fa144 100644 --- a/clang/test/CodeGen/PowerPC/ppc64-inline-asm.c +++ b/clang/test/CodeGen/PowerPC/ppc64-inline-asm.c @@ -47,6 +47,6 @@ void testZ(void *addr) { void testZwOff(void *addr, long long off) { asm volatile ("dcbz %y0\n" :: "Z"(*(unsigned char *)(addr + off)) : "memory"); // CHECK-LABEL: void @testZwOff(ptr noundef %addr, i64 noundef %off) -// CHECK: %[[VAL:[^ ]+]] = getelementptr i8, ptr %addr, i64 %off +// CHECK: %[[VAL:[^ ]+]] = getelementptr inbounds i8, ptr %addr, i64 %off // CHECK: call void asm sideeffect "dcbz ${0:y}\0A", "*Z,~{memory}"(ptr elementtype(i8) %[[VAL]]) } diff --git a/clang/test/CodeGen/X86/avx-builtins.c b/clang/test/CodeGen/X86/avx-builtins.c index 2d54b50642507..9178ecaf3f8fe 100644 --- a/clang/test/CodeGen/X86/avx-builtins.c +++ b/clang/test/CodeGen/X86/avx-builtins.c @@ -596,6 +596,54 @@ __m256 test_mm256_cmp_ps_true_us(__m256 a, __m256 b) { return _mm256_cmp_ps(a, b, _CMP_TRUE_US); } +__m128d test_mm_cmp_pd_eq_oq(__m128d a, __m128d b) { + // CHECK-LABEL: test_mm_cmp_pd_eq_oq + // CHECK: fcmp oeq <2 x double> %{{.*}}, %{{.*}} + return _mm_cmp_pd(a, b, _CMP_EQ_OQ); +} + +__m128d test_mm_cmp_pd_lt_os(__m128d a, __m128d b) { + // CHECK-LABEL: test_mm_cmp_pd_lt_os + // CHECK: fcmp olt <2 x double> %{{.*}}, %{{.*}} + return _mm_cmp_pd(a, b, _CMP_LT_OS); +} + +__m128d test_mm_cmp_pd_le_os(__m128d a, __m128d b) { + // CHECK-LABEL: test_mm_cmp_pd_le_os + // CHECK: fcmp ole <2 x double> %{{.*}}, %{{.*}} + return _mm_cmp_pd(a, b, _CMP_LE_OS); +} + +__m128d test_mm_cmp_pd_unord_q(__m128d a, __m128d b) { + // CHECK-LABEL: test_mm_cmp_pd_unord_q + // CHECK: fcmp uno <2 x double> %{{.*}}, %{{.*}} + return _mm_cmp_pd(a, b, _CMP_UNORD_Q); +} + +__m128d test_mm_cmp_pd_neq_uq(__m128d a, __m128d b) { + // CHECK-LABEL: test_mm_cmp_pd_neq_uq + // CHECK: fcmp une <2 x double> %{{.*}}, %{{.*}} + return _mm_cmp_pd(a, b, _CMP_NEQ_UQ); +} + +__m128d test_mm_cmp_pd_nlt_us(__m128d a, __m128d b) { + // CHECK-LABEL: test_mm_cmp_pd_nlt_us + // CHECK: fcmp uge <2 x double> %{{.*}}, %{{.*}} + return _mm_cmp_pd(a, b, _CMP_NLT_US); +} + +__m128d test_mm_cmp_pd_nle_us(__m128d a, __m128d b) { + // CHECK-LABEL: test_mm_cmp_pd_nle_us + // CHECK: fcmp ugt <2 x double> %{{.*}}, %{{.*}} + return _mm_cmp_pd(a, b, _CMP_NLE_US); +} + +__m128d test_mm_cmp_pd_ord_q(__m128d a, __m128d b) { + // CHECK-LABEL: test_mm_cmp_pd_ord_q + // CHECK: fcmp ord <2 x double> %{{.*}}, %{{.*}} + return _mm_cmp_pd(a, b, _CMP_ORD_Q); +} + __m128d test_mm_cmp_pd_eq_uq(__m128d a, __m128d b) { // CHECK-LABEL: test_mm_cmp_pd_eq_uq // CHECK: fcmp ueq <2 x double> %{{.*}}, %{{.*}} @@ -740,6 +788,54 @@ __m128d test_mm_cmp_pd_true_us(__m128d a, __m128d b) { return _mm_cmp_pd(a, b, _CMP_TRUE_US); } +__m128 test_mm_cmp_ps_eq_oq(__m128 a, __m128 b) { + // CHECK-LABEL: test_mm_cmp_ps_eq_oq + // CHECK: fcmp oeq <4 x float> %{{.*}}, %{{.*}} + return _mm_cmp_ps(a, b, _CMP_EQ_OQ); +} + +__m128 test_mm_cmp_ps_lt_os(__m128 a, __m128 b) { + // CHECK-LABEL: test_mm_cmp_ps_lt_os + // CHECK: fcmp olt <4 x float> %{{.*}}, %{{.*}} + return _mm_cmp_ps(a, b, _CMP_LT_OS); +} + +__m128 test_mm_cmp_ps_le_os(__m128 a, __m128 b) { + // CHECK-LABEL: test_mm_cmp_ps_le_os + // CHECK: fcmp ole <4 x float> %{{.*}}, %{{.*}} + return _mm_cmp_ps(a, b, _CMP_LE_OS); +} + +__m128 test_mm_cmp_ps_unord_q(__m128 a, __m128 b) { + // CHECK-LABEL: test_mm_cmp_ps_unord_q + // CHECK: fcmp uno <4 x float> %{{.*}}, %{{.*}} + return _mm_cmp_ps(a, b, _CMP_UNORD_Q); +} + +__m128 test_mm_cmp_ps_neq_uq(__m128 a, __m128 b) { + // CHECK-LABEL: test_mm_cmp_ps_neq_uq + // CHECK: fcmp une <4 x float> %{{.*}}, %{{.*}} + return _mm_cmp_ps(a, b, _CMP_NEQ_UQ); +} + +__m128 test_mm_cmp_ps_nlt_us(__m128 a, __m128 b) { + // CHECK-LABEL: test_mm_cmp_ps_nlt_us + // CHECK: fcmp uge <4 x float> %{{.*}}, %{{.*}} + return _mm_cmp_ps(a, b, _CMP_NLT_US); +} + +__m128 test_mm_cmp_ps_nle_us(__m128 a, __m128 b) { + // CHECK-LABEL: test_mm_cmp_ps_nle_us + // CHECK: fcmp ugt <4 x float> %{{.*}}, %{{.*}} + return _mm_cmp_ps(a, b, _CMP_NLE_US); +} + +__m128 test_mm_cmp_ps_ord_q(__m128 a, __m128 b) { + // CHECK-LABEL: test_mm_cmp_ps_ord_q + // CHECK: fcmp ord <4 x float> %{{.*}}, %{{.*}} + return _mm_cmp_ps(a, b, _CMP_ORD_Q); +} + __m128 test_mm_cmp_ps_eq_uq(__m128 a, __m128 b) { // CHECK-LABEL: test_mm_cmp_ps_eq_uq // CHECK: fcmp ueq <4 x float> %{{.*}}, %{{.*}} diff --git a/clang/test/CodeGen/X86/avx-shuffle-builtins.c b/clang/test/CodeGen/X86/avx-shuffle-builtins.c index 9917598f6eb15..9109247e534f4 100644 --- a/clang/test/CodeGen/X86/avx-shuffle-builtins.c +++ b/clang/test/CodeGen/X86/avx-shuffle-builtins.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -ffreestanding %s -O3 -triple=x86_64-apple-darwin -target-feature +avx -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -ffreestanding %s -O3 -triple=i386-apple-darwin -target-feature +avx -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -ffreestanding %s -O3 -triple=x86_64-apple-darwin -target-feature +avx -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,X64 +// RUN: %clang_cc1 -ffreestanding %s -O3 -triple=i386-apple-darwin -target-feature +avx -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,X86 // FIXME: This is testing optimized generation of shuffle instructions and should be fixed. @@ -129,8 +129,11 @@ __m256i test_mm256_insertf128_si256_1(__m256i a, __m128i b) { // Make sure we have the correct mask for each extractf128 case. __m128 test_mm256_extractf128_ps_0(__m256 a) { - // CHECK-LABEL: test_mm256_extractf128_ps_0 - // CHECK: shufflevector{{.*}} + // X64-LABEL: test_mm256_extractf128_ps_0 + // X64: shufflevector{{.*}} + // + // X86-LABEL: test_mm256_extractf128_ps_0 + // X86: shufflevector{{.*}} return _mm256_extractf128_ps(a, 0); } @@ -142,13 +145,16 @@ __m128d test_mm256_extractf128_pd_0(__m256d a) { __m128i test_mm256_extractf128_si256_0(__m256i a) { // CHECK-LABEL: test_mm256_extractf128_si256_0 - // CHECK: shufflevector{{.*}} + // CHECK: shufflevector{{.*}} return _mm256_extractf128_si256(a, 0); } __m128 test_mm256_extractf128_ps_1(__m256 a) { - // CHECK-LABEL: test_mm256_extractf128_ps_1 - // CHECK: shufflevector{{.*}} + // X64-LABEL: test_mm256_extractf128_ps_1 + // X64: shufflevector{{.*}} + // + // X86-LABEL: test_mm256_extractf128_ps_1 + // X86: shufflevector{{.*}} return _mm256_extractf128_ps(a, 1); } @@ -160,7 +166,7 @@ __m128d test_mm256_extractf128_pd_1(__m256d a) { __m128i test_mm256_extractf128_si256_1(__m256i a) { // CHECK-LABEL: test_mm256_extractf128_si256_1 - // CHECK: shufflevector{{.*}} + // CHECK: shufflevector{{.*}} return _mm256_extractf128_si256(a, 1); } diff --git a/clang/test/CodeGen/X86/cmp-avx-builtins-error.c b/clang/test/CodeGen/X86/cmp-avx-builtins-error.c deleted file mode 100644 index 2b35aa84492b6..0000000000000 --- a/clang/test/CodeGen/X86/cmp-avx-builtins-error.c +++ /dev/null @@ -1,22 +0,0 @@ -// RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-unknown-unknown \ -// RUN: -target-feature +avx -emit-llvm -fsyntax-only -verify -// RUN: %clang_cc1 %s -ffreestanding -triple=i386-unknown-unknown \ -// RUN: -target-feature +avx -emit-llvm -fsyntax-only -verify - -#include - -__m128d test_mm_cmp_pd(__m128d a, __m128d b) { - return _mm_cmp_pd(a, b, 32); // expected-error {{argument value 32 is outside the valid range [0, 31]}} -} - -__m128d test_mm_cmp_sd(__m128d a, __m128d b) { - return _mm_cmp_sd(a, b, 32); // expected-error {{argument value 32 is outside the valid range [0, 31]}} -} - -__m128 test_mm_cmp_ps(__m128 a, __m128 b) { - return _mm_cmp_pd(a, b, 32); // expected-error {{argument value 32 is outside the valid range [0, 31]}} -} - -__m128 test_mm_cmp_ss(__m128 a, __m128 b) { - return _mm_cmp_sd(a, b, 32); // expected-error {{argument value 32 is outside the valid range [0, 31]}} -} diff --git a/clang/test/CodeGen/X86/sse-builtins.c b/clang/test/CodeGen/X86/sse-builtins.c index 82f67da39e02b..885c82856522d 100644 --- a/clang/test/CodeGen/X86/sse-builtins.c +++ b/clang/test/CodeGen/X86/sse-builtins.c @@ -813,57 +813,3 @@ __m128 test_mm_xor_ps(__m128 A, __m128 B) { // CHECK: xor <4 x i32> return _mm_xor_ps(A, B); } - -__m128 test_mm_cmp_ps_eq_oq(__m128 a, __m128 b) { - // CHECK-LABEL: test_mm_cmp_ps_eq_oq - // CHECK: fcmp oeq <4 x float> %{{.*}}, %{{.*}} - return _mm_cmp_ps(a, b, _CMP_EQ_OQ); -} - -__m128 test_mm_cmp_ps_lt_os(__m128 a, __m128 b) { - // CHECK-LABEL: test_mm_cmp_ps_lt_os - // CHECK: fcmp olt <4 x float> %{{.*}}, %{{.*}} - return _mm_cmp_ps(a, b, _CMP_LT_OS); -} - -__m128 test_mm_cmp_ps_le_os(__m128 a, __m128 b) { - // CHECK-LABEL: test_mm_cmp_ps_le_os - // CHECK: fcmp ole <4 x float> %{{.*}}, %{{.*}} - return _mm_cmp_ps(a, b, _CMP_LE_OS); -} - -__m128 test_mm_cmp_ps_unord_q(__m128 a, __m128 b) { - // CHECK-LABEL: test_mm_cmp_ps_unord_q - // CHECK: fcmp uno <4 x float> %{{.*}}, %{{.*}} - return _mm_cmp_ps(a, b, _CMP_UNORD_Q); -} - -__m128 test_mm_cmp_ps_neq_uq(__m128 a, __m128 b) { - // CHECK-LABEL: test_mm_cmp_ps_neq_uq - // CHECK: fcmp une <4 x float> %{{.*}}, %{{.*}} - return _mm_cmp_ps(a, b, _CMP_NEQ_UQ); -} - -__m128 test_mm_cmp_ps_nlt_us(__m128 a, __m128 b) { - // CHECK-LABEL: test_mm_cmp_ps_nlt_us - // CHECK: fcmp uge <4 x float> %{{.*}}, %{{.*}} - return _mm_cmp_ps(a, b, _CMP_NLT_US); -} - -__m128 test_mm_cmp_ps_nle_us(__m128 a, __m128 b) { - // CHECK-LABEL: test_mm_cmp_ps_nle_us - // CHECK: fcmp ugt <4 x float> %{{.*}}, %{{.*}} - return _mm_cmp_ps(a, b, _CMP_NLE_US); -} - -__m128 test_mm_cmp_ps_ord_q(__m128 a, __m128 b) { - // CHECK-LABEL: test_mm_cmp_ps_ord_q - // CHECK: fcmp ord <4 x float> %{{.*}}, %{{.*}} - return _mm_cmp_ps(a, b, _CMP_ORD_Q); -} - -__m128 test_mm_cmp_ss(__m128 A, __m128 B) { - // CHECK-LABEL: test_mm_cmp_ss - // CHECK: call <4 x float> @llvm.x86.sse.cmp.ss(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 7) - return _mm_cmp_ss(A, B, _CMP_ORD_Q); -} diff --git a/clang/test/CodeGen/X86/sse2-builtins.c b/clang/test/CodeGen/X86/sse2-builtins.c index 09b57e3a63727..7165d2791827c 100644 --- a/clang/test/CodeGen/X86/sse2-builtins.c +++ b/clang/test/CodeGen/X86/sse2-builtins.c @@ -1719,57 +1719,3 @@ __m128i test_mm_xor_si128(__m128i A, __m128i B) { // CHECK: xor <2 x i64> %{{.*}}, %{{.*}} return _mm_xor_si128(A, B); } - -__m128d test_mm_cmp_pd_eq_oq(__m128d a, __m128d b) { - // CHECK-LABEL: test_mm_cmp_pd_eq_oq - // CHECK: fcmp oeq <2 x double> %{{.*}}, %{{.*}} - return _mm_cmp_pd(a, b, _CMP_EQ_OQ); -} - -__m128d test_mm_cmp_pd_lt_os(__m128d a, __m128d b) { - // CHECK-LABEL: test_mm_cmp_pd_lt_os - // CHECK: fcmp olt <2 x double> %{{.*}}, %{{.*}} - return _mm_cmp_pd(a, b, _CMP_LT_OS); -} - -__m128d test_mm_cmp_pd_le_os(__m128d a, __m128d b) { - // CHECK-LABEL: test_mm_cmp_pd_le_os - // CHECK: fcmp ole <2 x double> %{{.*}}, %{{.*}} - return _mm_cmp_pd(a, b, _CMP_LE_OS); -} - -__m128d test_mm_cmp_pd_unord_q(__m128d a, __m128d b) { - // CHECK-LABEL: test_mm_cmp_pd_unord_q - // CHECK: fcmp uno <2 x double> %{{.*}}, %{{.*}} - return _mm_cmp_pd(a, b, _CMP_UNORD_Q); -} - -__m128d test_mm_cmp_pd_neq_uq(__m128d a, __m128d b) { - // CHECK-LABEL: test_mm_cmp_pd_neq_uq - // CHECK: fcmp une <2 x double> %{{.*}}, %{{.*}} - return _mm_cmp_pd(a, b, _CMP_NEQ_UQ); -} - -__m128d test_mm_cmp_pd_nlt_us(__m128d a, __m128d b) { - // CHECK-LABEL: test_mm_cmp_pd_nlt_us - // CHECK: fcmp uge <2 x double> %{{.*}}, %{{.*}} - return _mm_cmp_pd(a, b, _CMP_NLT_US); -} - -__m128d test_mm_cmp_pd_nle_us(__m128d a, __m128d b) { - // CHECK-LABEL: test_mm_cmp_pd_nle_us - // CHECK: fcmp ugt <2 x double> %{{.*}}, %{{.*}} - return _mm_cmp_pd(a, b, _CMP_NLE_US); -} - -__m128d test_mm_cmp_pd_ord_q(__m128d a, __m128d b) { - // CHECK-LABEL: test_mm_cmp_pd_ord_q - // CHECK: fcmp ord <2 x double> %{{.*}}, %{{.*}} - return _mm_cmp_pd(a, b, _CMP_ORD_Q); -} - -__m128d test_mm_cmp_sd(__m128d A, __m128d B) { - // CHECK-LABEL: test_mm_cmp_sd - // CHECK: call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 7) - return _mm_cmp_sd(A, B, _CMP_ORD_Q); -} diff --git a/clang/test/CodeGen/aarch64-neon-vcmla.c b/clang/test/CodeGen/aarch64-neon-vcmla.c index 59ac17a24cccf..9cd046d63d1b5 100644 --- a/clang/test/CodeGen/aarch64-neon-vcmla.c +++ b/clang/test/CodeGen/aarch64-neon-vcmla.c @@ -167,10 +167,8 @@ float16x4_t test_vcmla_laneq_f16(float16x4_t acc, float16x4_t lhs, float16x8_t r } // CHECK-LABEL: @test_vcmlaq_lane_f16( -// CHECK: [[CPLX:%.*]] = bitcast <4 x half> %rhs to <2 x i32> -// CHECK: [[DUP:%.*]] = shufflevector <2 x i32> [[CPLX]], <2 x i32> undef, <4 x i32> -// CHECK: [[DUP_FLT:%.*]] = bitcast <4 x i32> [[DUP]] to <8 x half> -// CHECK: [[RES:%.*]] = tail call <8 x half> @llvm.aarch64.neon.vcmla.rot0.v8f16(<8 x half> %acc, <8 x half> %lhs, <8 x half> [[DUP_FLT]]) +// CHECK: [[DUP:%.*]] = shufflevector <4 x half> %rhs, <4 x half> poison, <8 x i32> +// CHECK: [[RES:%.*]] = tail call <8 x half> @llvm.aarch64.neon.vcmla.rot0.v8f16(<8 x half> %acc, <8 x half> %lhs, <8 x half> [[DUP]]) // CHECK: ret <8 x half> [[RES]] float16x8_t test_vcmlaq_lane_f16(float16x8_t acc, float16x8_t lhs, float16x4_t rhs) { return vcmlaq_lane_f16(acc, lhs, rhs, 1); @@ -243,10 +241,8 @@ float16x4_t test_vcmla_rot90_laneq_f16(float16x4_t acc, float16x4_t lhs, float16 } // CHECK-LABEL: @test_vcmlaq_rot90_lane_f16( -// CHECK: [[CPLX:%.*]] = bitcast <4 x half> %rhs to <2 x i32> -// CHECK: [[DUP:%.*]] = shufflevector <2 x i32> [[CPLX]], <2 x i32> undef, <4 x i32> -// CHECK: [[DUP_FLT:%.*]] = bitcast <4 x i32> [[DUP]] to <8 x half> -// CHECK: [[RES:%.*]] = tail call <8 x half> @llvm.aarch64.neon.vcmla.rot90.v8f16(<8 x half> %acc, <8 x half> %lhs, <8 x half> [[DUP_FLT]]) +// CHECK: [[DUP:%.*]] = shufflevector <4 x half> %rhs, <4 x half> poison, <8 x i32> +// CHECK: [[RES:%.*]] = tail call <8 x half> @llvm.aarch64.neon.vcmla.rot90.v8f16(<8 x half> %acc, <8 x half> %lhs, <8 x half> [[DUP]]) // CHECK: ret <8 x half> [[RES]] float16x8_t test_vcmlaq_rot90_lane_f16(float16x8_t acc, float16x8_t lhs, float16x4_t rhs) { return vcmlaq_rot90_lane_f16(acc, lhs, rhs, 1); @@ -319,10 +315,8 @@ float16x4_t test_vcmla_rot180_laneq_f16(float16x4_t acc, float16x4_t lhs, float1 } // CHECK-LABEL: @test_vcmlaq_rot180_lane_f16( -// CHECK: [[CPLX:%.*]] = bitcast <4 x half> %rhs to <2 x i32> -// CHECK: [[DUP:%.*]] = shufflevector <2 x i32> [[CPLX]], <2 x i32> undef, <4 x i32> -// CHECK: [[DUP_FLT:%.*]] = bitcast <4 x i32> [[DUP]] to <8 x half> -// CHECK: [[RES:%.*]] = tail call <8 x half> @llvm.aarch64.neon.vcmla.rot180.v8f16(<8 x half> %acc, <8 x half> %lhs, <8 x half> [[DUP_FLT]]) +// CHECK: [[DUP:%.*]] = shufflevector <4 x half> %rhs, <4 x half> poison, <8 x i32> +// CHECK: [[RES:%.*]] = tail call <8 x half> @llvm.aarch64.neon.vcmla.rot180.v8f16(<8 x half> %acc, <8 x half> %lhs, <8 x half> [[DUP]]) // CHECK: ret <8 x half> [[RES]] float16x8_t test_vcmlaq_rot180_lane_f16(float16x8_t acc, float16x8_t lhs, float16x4_t rhs) { return vcmlaq_rot180_lane_f16(acc, lhs, rhs, 1); @@ -395,10 +389,8 @@ float16x4_t test_vcmla_rot270_laneq_f16(float16x4_t acc, float16x4_t lhs, float1 } // CHECK-LABEL: @test_vcmlaq_rot270_lane_f16( -// CHECK: [[CPLX:%.*]] = bitcast <4 x half> %rhs to <2 x i32> -// CHECK: [[DUP:%.*]] = shufflevector <2 x i32> [[CPLX]], <2 x i32> undef, <4 x i32> -// CHECK: [[DUP_FLT:%.*]] = bitcast <4 x i32> [[DUP]] to <8 x half> -// CHECK: [[RES:%.*]] = tail call <8 x half> @llvm.aarch64.neon.vcmla.rot270.v8f16(<8 x half> %acc, <8 x half> %lhs, <8 x half> [[DUP_FLT]]) +// CHECK: [[DUP:%.*]] = shufflevector <4 x half> %rhs, <4 x half> poison, <8 x i32> +// CHECK: [[RES:%.*]] = tail call <8 x half> @llvm.aarch64.neon.vcmla.rot270.v8f16(<8 x half> %acc, <8 x half> %lhs, <8 x half> [[DUP]]) // CHECK: ret <8 x half> [[RES]] float16x8_t test_vcmlaq_rot270_lane_f16(float16x8_t acc, float16x8_t lhs, float16x4_t rhs) { return vcmlaq_rot270_lane_f16(acc, lhs, rhs, 1); diff --git a/clang/test/CodeGen/address-space.c b/clang/test/CodeGen/address-space.c index 83a434d88b8e8..c92fc0dd96870 100644 --- a/clang/test/CodeGen/address-space.c +++ b/clang/test/CodeGen/address-space.c @@ -53,7 +53,7 @@ void test4(MyStruct __attribute__((address_space(2))) *pPtr) { // X86: [[ALLOCA:%.*]] = alloca ptr addrspace(1) // X86-NEXT: store ptr addrspace(1) %arg, ptr [[ALLOCA]] // X86-NEXT: load ptr addrspace(1), ptr [[ALLOCA]] -// X86-NEXT: getelementptr i8, ptr addrspace(1) +// X86-NEXT: getelementptr inbounds i8, ptr addrspace(1) // X86-NEXT: ret ptr addrspace(1) void __attribute__((address_space(1)))* void_ptr_arithmetic_test(void __attribute__((address_space(1))) *arg) { diff --git a/clang/test/CodeGen/auto.c b/clang/test/CodeGen/auto.c new file mode 100644 index 0000000000000..e5bc1bf66138f --- /dev/null +++ b/clang/test/CodeGen/auto.c @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -std=c2x -emit-llvm %s -o - | FileCheck %s + +void basic_types(void) { + auto nb = 4; // CHECK: alloca i32 + auto dbl = 4.3; // CHECK: alloca double + auto lng = 4UL; // CHECK: alloca i{{32|64}} + auto bl = true; // CHECK: alloca i8 + auto chr = 'A'; // CHECK: alloca i{{8|32}} + auto str = "Test"; // CHECK: alloca ptr + auto str2[] = "Test"; // CHECK: alloca [5 x i8] + auto nptr = nullptr; // CHECK: alloca ptr +} + +void misc_declarations(void) { + // FIXME: this should end up being rejected when we implement underspecified + // declarations in N3006. + auto strct_ptr = (struct { int a; } *)0; // CHECK: alloca ptr + auto int_cl = (int){13}; // CHECK: alloca i32 + auto double_cl = (double){2.5}; // CHECK: alloca double + + auto se = ({ // CHECK: alloca i32 + auto snb = 12; // CHECK: alloca i32 + snb; + }); +} + +void loop(void) { + auto j = 4; // CHECK: alloca i32 + for (auto i = j; i < 2 * j; i++); // CHECK: alloca i32 +} + +#define AUTO_MACRO(_NAME, ARG, ARG2, ARG3) auto _NAME = ARG + (ARG2 / ARG3); + +#define AUTO_INT_MACRO(_NAME, ARG, ARG2, ARG3) auto _NAME = (ARG ^ ARG2) & ARG3; + +int macros(int in_int) { + auto a = in_int + 1; // CHECK: alloca i32 + AUTO_MACRO(b, 1.3, 2.5f, 3); // CHECK: alloca double + AUTO_INT_MACRO(c, 64, 23, 0xff); // CHECK: alloca i32 + return (a + (int)b) - c; // CHECK: ret i32 %{{.*}} +} diff --git a/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c b/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c index 0e0a9b157464a..015102940890a 100644 --- a/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c +++ b/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c @@ -35,6 +35,7 @@ // CHECK-SANITIZE-ANYRECOVER-C-DAG: @[[LINE_1400:.*]] = {{.*}}, i32 1400, i32 15 } } // CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1500:.*]] = {{.*}}, i32 1500, i32 15 } } // CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1600:.*]] = {{.*}}, i32 1600, i32 15 } } +// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1700:.*]] = {{.*}}, i32 1700, i32 15 } } #ifdef __cplusplus extern "C" { @@ -427,6 +428,48 @@ char *allones_allones_OK(void) { return base + offset; } +// C++ does not allow void* arithmetic even as a GNU extension. Replace void* +// with char* in that case to keep test expectations the same. +#ifdef __cplusplus +char *void_ptr(char *base, unsigned long offset) { +#else +char *void_ptr(void *base, unsigned long offset) { +#endif + // CHECK: define{{.*}} ptr @void_ptr(ptr noundef %[[BASE:.*]], i64 noundef %[[OFFSET:.*]]) + // CHECK-NEXT: [[ENTRY:.*]]: + // CHECK-NEXT: %[[BASE_ADDR:.*]] = alloca ptr, align 8 + // CHECK-NEXT: %[[OFFSET_ADDR:.*]] = alloca i64, align 8 + // CHECK-NEXT: store ptr %[[BASE]], ptr %[[BASE_ADDR]], align 8 + // CHECK-NEXT: store i64 %[[OFFSET]], ptr %[[OFFSET_ADDR]], align 8 + // CHECK-NEXT: %[[BASE_RELOADED:.*]] = load ptr, ptr %[[BASE_ADDR]], align 8 + // CHECK-NEXT: %[[OFFSET_RELOADED:.*]] = load i64, ptr %[[OFFSET_ADDR]], align 8 + // CHECK-NEXT: %[[ADD_PTR:.*]] = getelementptr inbounds i8, ptr %[[BASE_RELOADED]], i64 %[[OFFSET_RELOADED]] + // CHECK-SANITIZE-NEXT: %[[COMPUTED_OFFSET_AGGREGATE:.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 1, i64 %[[OFFSET_RELOADED]]), !nosanitize + // CHECK-SANITIZE-NEXT: %[[COMPUTED_OFFSET_OVERFLOWED:.*]] = extractvalue { i64, i1 } %[[COMPUTED_OFFSET_AGGREGATE]], 1, !nosanitize + // CHECK-SANITIZE-NEXT: %[[OR_OV:.+]] = or i1 %[[COMPUTED_OFFSET_OVERFLOWED]], false, !nosanitize + // CHECK-SANITIZE-NEXT: %[[COMPUTED_OFFSET:.*]] = extractvalue { i64, i1 } %[[COMPUTED_OFFSET_AGGREGATE]], 0, !nosanitize + // CHECK-SANITIZE-NEXT: %[[BASE_RELOADED_INT:.*]] = ptrtoint ptr %[[BASE_RELOADED]] to i64, !nosanitize + // CHECK-SANITIZE-NEXT: %[[COMPUTED_GEP:.*]] = add i64 %[[BASE_RELOADED_INT]], %[[COMPUTED_OFFSET]], !nosanitize + // CHECK-SANITIZE-NEXT: %[[BASE_IS_NOT_NULLPTR:.*]] = icmp ne ptr %[[BASE_RELOADED]], null, !nosanitize + // CHECK-SANITIZE-NEXT: %[[COMPUTED_GEP_IS_NOT_NULL:.*]] = icmp ne i64 %[[COMPUTED_GEP]], 0, !nosanitize + // CHECK-SANITIZE-C-NEXT: %[[BOTH_POINTERS_ARE_NULL_OR_BOTH_ARE_NONNULL:.*]] = and i1 %[[BASE_IS_NOT_NULLPTR]], %[[COMPUTED_GEP_IS_NOT_NULL]], !nosanitize + // CHECK-SANITIZE-CPP-NEXT: %[[BOTH_POINTERS_ARE_NULL_OR_BOTH_ARE_NONNULL:.*]] = icmp eq i1 %[[BASE_IS_NOT_NULLPTR]], %[[COMPUTED_GEP_IS_NOT_NULL]], !nosanitize + // CHECK-SANITIZE-NEXT: %[[COMPUTED_OFFSET_DID_NOT_OVERFLOW:.*]] = xor i1 %[[OR_OV]], true, !nosanitize + // CHECK-SANITIZE-NEXT: %[[COMPUTED_GEP_IS_UGE_BASE:.*]] = icmp uge i64 %[[COMPUTED_GEP]], %[[BASE_RELOADED_INT]], !nosanitize + // CHECK-SANITIZE-NEXT: %[[GEP_DID_NOT_OVERFLOW:.*]] = and i1 %[[COMPUTED_GEP_IS_UGE_BASE]], %[[COMPUTED_OFFSET_DID_NOT_OVERFLOW]], !nosanitize + // CHECK-SANITIZE-NEXT: %[[GEP_IS_OKAY:.*]] = and i1 %[[BOTH_POINTERS_ARE_NULL_OR_BOTH_ARE_NONNULL]], %[[GEP_DID_NOT_OVERFLOW]], !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[GEP_IS_OKAY]], label %[[CONT:.*]], label %[[HANDLER_POINTER_OVERFLOW:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_POINTER_OVERFLOW]]: + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_pointer_overflow_abort(ptr @[[LINE_1700]], i64 %[[BASE_RELOADED_INT]], i64 %[[COMPUTED_GEP]]) + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_pointer_overflow(ptr @[[LINE_1700]], i64 %[[BASE_RELOADED_INT]], i64 %[[COMPUTED_GEP]]) + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.ubsantrap(i8 19){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: ret ptr %[[ADD_PTR]] +#line 1700 + return base + offset; +} + #ifdef __cplusplus } #endif diff --git a/clang/test/CodeGen/catch-undef-behavior.c b/clang/test/CodeGen/catch-undef-behavior.c index ca0df0f002f89..af37ef9e8565b 100644 --- a/clang/test/CodeGen/catch-undef-behavior.c +++ b/clang/test/CodeGen/catch-undef-behavior.c @@ -27,6 +27,9 @@ // CHECK-UBSAN: @[[SCHAR:.*]] = private unnamed_addr constant { i16, i16, [14 x i8] } { i16 0, i16 7, [14 x i8] c"'signed char'\00" } // CHECK-UBSAN: @[[LINE_1500:.*]] = {{.*}}, i32 1500, i32 10 {{.*}} @[[FP16]], {{.*}} } +// CHECK-UBSAN: @[[PLONG:.*]] = private unnamed_addr constant { i16, i16, [9 x i8] } { i16 -1, i16 0, [9 x i8] c"'long *'\00" } +// CHECK-UBSAN: @[[LINE_1600:.*]] = {{.*}}, i32 1600, i32 10 {{.*}} @[[PLONG]], {{.*}} } + // PR6805 // CHECK-COMMON-LABEL: @foo void foo(void) { @@ -354,21 +357,69 @@ void call_decl_nonnull(int *a) { decl_nonnull(a); } -extern void *memcpy (void *, const void *, unsigned) __attribute__((nonnull(1, 2))); +extern void *memcpy(void *, const void *, unsigned long) __attribute__((nonnull(1, 2))); // CHECK-COMMON-LABEL: @call_memcpy_nonnull void call_memcpy_nonnull(void *p, void *q, int sz) { // CHECK-COMMON: icmp ne ptr {{.*}}, null // CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg // CHECK-TRAP: call void @llvm.ubsantrap(i8 16) + // CHECK-COMMON-NOT: call // CHECK-COMMON: icmp ne ptr {{.*}}, null // CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg // CHECK-TRAP: call void @llvm.ubsantrap(i8 16) + // CHECK-COMMON-NOT: call + + // CHECK-COMMON: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %0, ptr align 1 %1, i64 %conv, i1 false) + memcpy(p, q, sz); +} + +// CHECK-COMMON-LABEL: define{{.*}} void @call_memcpy( +void call_memcpy(long *p, short *q, int sz) { + // CHECK-COMMON: icmp ne ptr {{.*}}, null + // CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg( + // CHECK-TRAP: call void @llvm.ubsantrap(i8 16) + // CHECK-COMMON: and i64 %[[#]], 7, !nosanitize + // CHECK-COMMON: icmp eq i64 %[[#]], 0, !nosanitize + // CHECK-UBSAN: call void @__ubsan_handle_type_mismatch_v1(ptr @[[LINE_1600]] + // CHECK-TRAP: call void @llvm.ubsantrap(i8 22) + + // CHECK-COMMON: icmp ne ptr {{.*}}, null + // CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg( + // CHECK-TRAP: call void @llvm.ubsantrap(i8 16) + // CHECK-COMMON: and i64 %[[#]], 1, !nosanitize + // CHECK-COMMON: icmp eq i64 %[[#]], 0, !nosanitize + // CHECK-UBSAN: call void @__ubsan_handle_type_mismatch_v1( + // CHECK-TRAP: call void @llvm.ubsantrap(i8 22) + + // CHECK-COMMON: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %0, ptr align 2 %1, i64 %conv, i1 false) + + // CHECK-UBSAN-NOT: call void @__ubsan_handle_type_mismatch_v1( + // CHECK-COMMON: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[#]], ptr align 1 %[[#]], i64 %{{.*}}, i1 false) +#line 1600 memcpy(p, q, sz); + /// Casting to void * or char * drops the alignment requirement. + memcpy((void *)p, (char *)q, sz); } -extern void *memmove (void *, const void *, unsigned) __attribute__((nonnull(1, 2))); +// CHECK-COMMON-LABEL: define{{.*}} void @call_memcpy_inline( +void call_memcpy_inline(long *p, short *q) { + // CHECK-COMMON: and i64 %[[#]], 7, !nosanitize + // CHECK-COMMON: icmp eq i64 %[[#]], 0, !nosanitize + // CHECK-UBSAN: call void @__ubsan_handle_type_mismatch_v1( + // CHECK-TRAP: call void @llvm.ubsantrap(i8 22) + + // CHECK-COMMON: and i64 %[[#]], 1, !nosanitize + // CHECK-COMMON: icmp eq i64 %[[#]], 0, !nosanitize + // CHECK-UBSAN: call void @__ubsan_handle_type_mismatch_v1( + // CHECK-TRAP: call void @llvm.ubsantrap(i8 22) + + // CHECK-COMMON: call void @llvm.memcpy.inline.p0.p0.i64(ptr align 8 %0, ptr align 2 %1, i64 2, i1 false) + __builtin_memcpy_inline(p, q, 2); +} + +extern void *memmove(void *, const void *, unsigned long) __attribute__((nonnull(1, 2))); // CHECK-COMMON-LABEL: @call_memmove_nonnull void call_memmove_nonnull(void *p, void *q, int sz) { @@ -382,6 +433,28 @@ void call_memmove_nonnull(void *p, void *q, int sz) { memmove(p, q, sz); } +// CHECK-COMMON-LABEL: define{{.*}} void @call_memmove( +void call_memmove(long *p, short *q, int sz) { + // CHECK-COMMON: icmp ne ptr {{.*}}, null + // CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg( + // CHECK-TRAP: call void @llvm.ubsantrap(i8 16) + // CHECK-COMMON: and i64 %[[#]], 7, !nosanitize + // CHECK-COMMON: icmp eq i64 %[[#]], 0, !nosanitize + // CHECK-UBSAN: call void @__ubsan_handle_type_mismatch_v1( + // CHECK-TRAP: call void @llvm.ubsantrap(i8 22) + + // CHECK-COMMON: icmp ne ptr {{.*}}, null + // CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg( + // CHECK-TRAP: call void @llvm.ubsantrap(i8 16) + // CHECK-COMMON: and i64 %[[#]], 1, !nosanitize + // CHECK-COMMON: icmp eq i64 %[[#]], 0, !nosanitize + // CHECK-UBSAN: call void @__ubsan_handle_type_mismatch_v1( + // CHECK-TRAP: call void @llvm.ubsantrap(i8 22) + + // CHECK-COMMON: call void @llvm.memmove.p0.p0.i64(ptr align 8 %0, ptr align 2 %1, i64 %conv, i1 false) + memmove(p, q, sz); +} + // CHECK-COMMON-LABEL: @call_nonnull_variadic __attribute__((nonnull)) void nonnull_variadic(int a, ...); void call_nonnull_variadic(int a, int *b) { diff --git a/clang/test/CodeGen/large-data-threshold.c b/clang/test/CodeGen/large-data-threshold.c index 650a7fbb0094e..29ae19e9b7189 100644 --- a/clang/test/CodeGen/large-data-threshold.c +++ b/clang/test/CodeGen/large-data-threshold.c @@ -5,7 +5,7 @@ // RUN: %clang_cc1 -triple x86_64-unknown-unknown -S %s -o - -mcmodel=medium -mlarge-data-threshold=200 | FileCheck %s --check-prefix=ASM-SMALL // RUN: %clang_cc1 -triple x86_64-unknown-unknown -S %s -o - -mcmodel=medium -mlarge-data-threshold=2 | FileCheck %s --check-prefix=ASM-LARGE -// IR-DEFAULT: !{i32 1, !"Large Data Threshold", i64 0} +// IR-DEFAULT: !{i32 1, !"Large Data Threshold", i64 65535} // IR-CUSTOM: !{i32 1, !"Large Data Threshold", i64 200} // ASM-SMALL-NOT: movabsq diff --git a/clang/test/CodeGen/target-features-error-2.c b/clang/test/CodeGen/target-features-error-2.c index 4f8bc8712aa51..60586fb57f1c0 100644 --- a/clang/test/CodeGen/target-features-error-2.c +++ b/clang/test/CodeGen/target-features-error-2.c @@ -14,8 +14,8 @@ int baz(__m256i a) { #endif #if NEED_AVX_2 -__m256 need_avx(__m256 a, __m256 b) { - return _mm256_cmp_ps(a, b, 0); // expected-error {{'__builtin_ia32_cmpps256' needs target feature avx}} +__m128 need_avx(__m128 a, __m128 b) { + return _mm_cmp_ps(a, b, 0); // expected-error {{'__builtin_ia32_cmpps' needs target feature avx}} } #endif diff --git a/clang/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp b/clang/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp index 2ec620eb19d22..5c4b86744287e 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp @@ -94,9 +94,9 @@ void* test9(B* x) { return dynamic_cast(x); } // CHECK-NEXT: [[VBTBL:%.*]] = load ptr, ptr [[VBPTR]], align 4 // CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i32, ptr [[VBTBL]], i32 1 // CHECK-NEXT: [[VBOFFS:%.*]] = load i32, ptr [[VBOFFP]], align 4 -// CHECK-NEXT: [[DELTA:%.*]] = add nsw i32 [[VBOFFS]], 4 -// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8, ptr %x, i32 [[DELTA]] -// CHECK-NEXT: [[CALL:%.*]] = tail call ptr @__RTCastToVoid(ptr nonnull [[ADJ]]) +// CHECK-NEXT: [[BASE:%.*]] = getelementptr i8, ptr %x, i32 [[VBOFFS]] +// CHECK-NEXT: [[ADJ:%.*]] = getelementptr i8, ptr [[BASE]], i32 4 +// CHECK-NEXT: [[CALL:%.*]] = tail call ptr @__RTCastToVoid(ptr [[ADJ]]) // CHECK-NEXT: br label // CHECK: [[RET:%.*]] = phi ptr // CHECK-NEXT: ret ptr [[RET]] diff --git a/clang/test/CodeGenCXX/strict-vtable-pointers-GH67937.cpp b/clang/test/CodeGenCXX/strict-vtable-pointers-GH67937.cpp new file mode 100644 index 0000000000000..692ca23a69abe --- /dev/null +++ b/clang/test/CodeGenCXX/strict-vtable-pointers-GH67937.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 %s -I%S -triple=x86_64-pc-windows-msvc -fstrict-vtable-pointers -disable-llvm-passes -O1 -emit-llvm -o %t.ll +// RUN: FileCheck %s < %t.ll + +struct A { + virtual ~A(); +}; +struct B : virtual A {}; +class C : B {}; +C foo; + +// CHECK-LABEL: define {{.*}} @"??0C@@QEAA@XZ"(ptr {{.*}} %this, i32 {{.*}} %is_most_derived) +// CHECK: ctor.init_vbases: +// CHECK-NEXT: %0 = getelementptr inbounds i8, ptr %this1, i64 0 +// CHECK-NEXT: store ptr @"??_8C@@7B@", ptr %0 +// CHECK-NEXT: %1 = call ptr @llvm.launder.invariant.group.p0(ptr %this1) +// CHECK-NEXT: %2 = getelementptr inbounds i8, ptr %1, i64 8 +// CHECK-NEXT: %call = call noundef ptr @"??0A@@QEAA@XZ"(ptr {{.*}} %2) #2 +// CHECK-NEXT: br label %ctor.skip_vbases +// CHECK-EMPTY: +// CHECK-NEXT: ctor.skip_vbases: +// CHECK-NEXT: %3 = call ptr @llvm.launder.invariant.group.p0(ptr %this1) +// CHECK-NEXT: %call3 = call noundef ptr @"??0B@@QEAA@XZ"(ptr {{.*}} %3, i32 noundef 0) #2 diff --git a/clang/test/Driver/arm-abi.c b/clang/test/Driver/arm-abi.c index 7bf5977992f65..139456cf98e14 100644 --- a/clang/test/Driver/arm-abi.c +++ b/clang/test/Driver/arm-abi.c @@ -33,6 +33,8 @@ // RUN: | FileCheck -check-prefix=CHECK-AAPCS-LINUX %s // RUN: %clang -target arm--openbsd- %s -### -o %t.o 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-AAPCS-LINUX %s +// RUN: %clang -target arm--haiku- %s -### -o %t.o 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-AAPCS-LINUX %s // Otherwise, ABI is selected based on environment // RUN: %clang -target arm---android %s -### -o %t.o 2>&1 \ diff --git a/clang/test/Driver/clang-offload-bundler-zlib.c b/clang/test/Driver/clang-offload-bundler-zlib.c new file mode 100644 index 0000000000000..c46c32a4a0537 --- /dev/null +++ b/clang/test/Driver/clang-offload-bundler-zlib.c @@ -0,0 +1,75 @@ +// REQUIRES: zlib +// REQUIRES: x86-registered-target +// UNSUPPORTED: target={{.*}}-darwin{{.*}}, target={{.*}}-aix{{.*}} + +// +// Generate the host binary to be bundled. +// +// RUN: %clang -O0 -target %itanium_abi_triple %s -c -emit-llvm -o %t.bc + +// +// Generate an empty file to help with the checks of empty files. +// +// RUN: touch %t.empty + +// +// Generate device binaries to be bundled. +// +// RUN: echo 'Content of device file 1' > %t.tgt1 +// RUN: echo 'Content of device file 2' > %t.tgt2 + +// +// Check compression/decompression of offload bundle. +// +// RUN: env OFFLOAD_BUNDLER_COMPRESS=1 OFFLOAD_BUNDLER_VERBOSE=1 \ +// RUN: clang-offload-bundler -type=bc -targets=hip-amdgcn-amd-amdhsa--gfx900,hip-amdgcn-amd-amdhsa--gfx906 \ +// RUN: -input=%t.tgt1 -input=%t.tgt2 -output=%t.hip.bundle.bc 2>&1 | \ +// RUN: FileCheck -check-prefix=COMPRESS %s +// RUN: clang-offload-bundler -type=bc -list -input=%t.hip.bundle.bc | FileCheck -check-prefix=NOHOST %s +// RUN: env OFFLOAD_BUNDLER_VERBOSE=1 \ +// RUN: clang-offload-bundler -type=bc -targets=hip-amdgcn-amd-amdhsa--gfx900,hip-amdgcn-amd-amdhsa--gfx906 \ +// RUN: -output=%t.res.tgt1 -output=%t.res.tgt2 -input=%t.hip.bundle.bc -unbundle 2>&1 | \ +// RUN: FileCheck -check-prefix=DECOMPRESS %s +// RUN: diff %t.tgt1 %t.res.tgt1 +// RUN: diff %t.tgt2 %t.res.tgt2 + +// +// COMPRESS: Compression method used: +// DECOMPRESS: Decompression method: +// NOHOST-NOT: host- +// NOHOST-DAG: hip-amdgcn-amd-amdhsa--gfx900 +// NOHOST-DAG: hip-amdgcn-amd-amdhsa--gfx906 +// + +// +// Check -bundle-align option. +// + +// RUN: clang-offload-bundler -bundle-align=4096 -type=bc -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -input=%t.bc -input=%t.tgt1 -input=%t.tgt2 -output=%t.bundle3.bc -compress +// RUN: clang-offload-bundler -type=bc -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -output=%t.res.bc -output=%t.res.tgt1 -output=%t.res.tgt2 -input=%t.bundle3.bc -unbundle +// RUN: diff %t.bc %t.res.bc +// RUN: diff %t.tgt1 %t.res.tgt1 +// RUN: diff %t.tgt2 %t.res.tgt2 + +// +// Check unbundling archive. +// +// RUN: clang-offload-bundler -type=bc -targets=hip-amdgcn-amd-amdhsa--gfx900,hip-amdgcn-amd-amdhsa--gfx906 \ +// RUN: -input=%t.tgt1 -input=%t.tgt2 -output=%T/hip_bundle1.bc -compress +// RUN: clang-offload-bundler -type=bc -targets=hip-amdgcn-amd-amdhsa--gfx900,hip-amdgcn-amd-amdhsa--gfx906 \ +// RUN: -input=%t.tgt1 -input=%t.tgt2 -output=%T/hip_bundle2.bc -compress +// RUN: llvm-ar cr %T/hip_archive.a %T/hip_bundle1.bc %T/hip_bundle2.bc +// RUN: clang-offload-bundler -unbundle -type=a -targets=hip-amdgcn-amd-amdhsa--gfx900,hip-amdgcn-amd-amdhsa--gfx906 \ +// RUN: -output=%T/hip_900.a -output=%T/hip_906.a -input=%T/hip_archive.a +// RUN: llvm-ar t %T/hip_900.a | FileCheck -check-prefix=HIP-AR-900 %s +// RUN: llvm-ar t %T/hip_906.a | FileCheck -check-prefix=HIP-AR-906 %s +// HIP-AR-900-DAG: hip_bundle1-hip-amdgcn-amd-amdhsa--gfx900 +// HIP-AR-900-DAG: hip_bundle2-hip-amdgcn-amd-amdhsa--gfx900 +// HIP-AR-906-DAG: hip_bundle1-hip-amdgcn-amd-amdhsa--gfx906 +// HIP-AR-906-DAG: hip_bundle2-hip-amdgcn-amd-amdhsa--gfx906 + +// Some code so that we can create a binary out of this file. +int A = 0; +void test_func(void) { + ++A; +} diff --git a/clang/test/Driver/clang-offload-bundler-zstd.c b/clang/test/Driver/clang-offload-bundler-zstd.c new file mode 100644 index 0000000000000..b2b588b72d4d6 --- /dev/null +++ b/clang/test/Driver/clang-offload-bundler-zstd.c @@ -0,0 +1,72 @@ +// REQUIRES: zstd +// REQUIRES: x86-registered-target +// UNSUPPORTED: target={{.*}}-darwin{{.*}}, target={{.*}}-aix{{.*}} + +// +// Generate the host binary to be bundled. +// +// RUN: %clang -O0 -target %itanium_abi_triple %s -c -emit-llvm -o %t.bc + +// +// Generate an empty file to help with the checks of empty files. +// +// RUN: touch %t.empty + +// +// Generate device binaries to be bundled. +// +// RUN: echo 'Content of device file 1' > %t.tgt1 +// RUN: echo 'Content of device file 2' > %t.tgt2 + +// +// Check compression/decompression of offload bundle. +// +// RUN: clang-offload-bundler -type=bc -targets=hip-amdgcn-amd-amdhsa--gfx900,hip-amdgcn-amd-amdhsa--gfx906 \ +// RUN: -input=%t.tgt1 -input=%t.tgt2 -output=%t.hip.bundle.bc -compress -verbose 2>&1 | \ +// RUN: FileCheck -check-prefix=COMPRESS %s +// RUN: clang-offload-bundler -type=bc -list -input=%t.hip.bundle.bc | FileCheck -check-prefix=NOHOST %s +// RUN: clang-offload-bundler -type=bc -targets=hip-amdgcn-amd-amdhsa--gfx900,hip-amdgcn-amd-amdhsa--gfx906 \ +// RUN: -output=%t.res.tgt1 -output=%t.res.tgt2 -input=%t.hip.bundle.bc -unbundle -verbose 2>&1 | \ +// RUN: FileCheck -check-prefix=DECOMPRESS %s +// RUN: diff %t.tgt1 %t.res.tgt1 +// RUN: diff %t.tgt2 %t.res.tgt2 +// +// COMPRESS: Compression method used +// DECOMPRESS: Decompression method +// NOHOST-NOT: host- +// NOHOST-DAG: hip-amdgcn-amd-amdhsa--gfx900 +// NOHOST-DAG: hip-amdgcn-amd-amdhsa--gfx906 +// + +// +// Check -bundle-align option. +// + +// RUN: clang-offload-bundler -bundle-align=4096 -type=bc -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -input=%t.bc -input=%t.tgt1 -input=%t.tgt2 -output=%t.bundle3.bc -compress +// RUN: clang-offload-bundler -type=bc -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -output=%t.res.bc -output=%t.res.tgt1 -output=%t.res.tgt2 -input=%t.bundle3.bc -unbundle +// RUN: diff %t.bc %t.res.bc +// RUN: diff %t.tgt1 %t.res.tgt1 +// RUN: diff %t.tgt2 %t.res.tgt2 + +// +// Check unbundling archive. +// +// RUN: clang-offload-bundler -type=bc -targets=hip-amdgcn-amd-amdhsa--gfx900,hip-amdgcn-amd-amdhsa--gfx906 \ +// RUN: -input=%t.tgt1 -input=%t.tgt2 -output=%T/hip_bundle1.bc -compress +// RUN: clang-offload-bundler -type=bc -targets=hip-amdgcn-amd-amdhsa--gfx900,hip-amdgcn-amd-amdhsa--gfx906 \ +// RUN: -input=%t.tgt1 -input=%t.tgt2 -output=%T/hip_bundle2.bc -compress +// RUN: llvm-ar cr %T/hip_archive.a %T/hip_bundle1.bc %T/hip_bundle2.bc +// RUN: clang-offload-bundler -unbundle -type=a -targets=hip-amdgcn-amd-amdhsa--gfx900,hip-amdgcn-amd-amdhsa--gfx906 \ +// RUN: -output=%T/hip_900.a -output=%T/hip_906.a -input=%T/hip_archive.a +// RUN: llvm-ar t %T/hip_900.a | FileCheck -check-prefix=HIP-AR-900 %s +// RUN: llvm-ar t %T/hip_906.a | FileCheck -check-prefix=HIP-AR-906 %s +// HIP-AR-900-DAG: hip_bundle1-hip-amdgcn-amd-amdhsa--gfx900 +// HIP-AR-900-DAG: hip_bundle2-hip-amdgcn-amd-amdhsa--gfx900 +// HIP-AR-906-DAG: hip_bundle1-hip-amdgcn-amd-amdhsa--gfx906 +// HIP-AR-906-DAG: hip_bundle2-hip-amdgcn-amd-amdhsa--gfx906 + +// Some code so that we can create a binary out of this file. +int A = 0; +void test_func(void) { + ++A; +} diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c index 7a3616a2e9f0a..ebe8a0520bf0f 100644 --- a/clang/test/Driver/clang_f_opts.c +++ b/clang/test/Driver/clang_f_opts.c @@ -520,6 +520,11 @@ // CHECK-COVERAGE-COMPILATION-DIR: "-fcoverage-compilation-dir=." // CHECK-COVERAGE-COMPILATION-DIR-NOT: "-ffile-compilation-dir=." +// RUN: %clang -### -S -fverify-intermediate-code %s 2>&1 | FileCheck -check-prefix=CHECK-VERIFY-INTERMEDIATE-CODE %s +// RUN: %clang -### -S -fno-verify-intermediate-code %s 2>&1 | FileCheck -check-prefix=CHECK-NO-VERIFY-INTERMEDIATE-CODE %s +// CHECK-VERIFY-INTERMEDIATE-CODE-NOT: "-disable-llvm-verifier" +// CHECK-NO-VERIFY-INTERMEDIATE-CODE: "-disable-llvm-verifier" + // RUN: %clang -### -S -fdiscard-value-names %s 2>&1 | FileCheck -check-prefix=CHECK-DISCARD-NAMES %s // RUN: %clang -### -S -fno-discard-value-names %s 2>&1 | FileCheck -check-prefix=CHECK-NO-DISCARD-NAMES %s // CHECK-DISCARD-NAMES: "-discard-value-names" diff --git a/clang/test/Driver/cuda-detect.cu b/clang/test/Driver/cuda-detect.cu index ad6b90c90c7b7..077d555a3128f 100644 --- a/clang/test/Driver/cuda-detect.cu +++ b/clang/test/Driver/cuda-detect.cu @@ -29,7 +29,7 @@ // RUN: --sysroot=%S/Inputs/CUDA-nolibdevice --cuda-path-ignore-env 2>&1 | FileCheck %s -check-prefix NOCUDA // RUN: %clang -v --target=x86_64-unknown-linux \ // RUN: --sysroot=%S/Inputs/CUDA-nolibdevice --cuda-path-ignore-env 2>&1 | FileCheck %s -check-prefix NOCUDA -// RUN: %clang -v --target=x84_64-apple-macosx \ +// RUN: %clang -v --target=x86_64-apple-macosx \ // RUN: --sysroot=%S/Inputs/CUDA-nolibdevice --cuda-path-ignore-env 2>&1 | FileCheck %s -check-prefix NOCUDA // ... unless the user doesn't need libdevice diff --git a/clang/test/Driver/haiku.c b/clang/test/Driver/haiku.c index 021ab522be06e..3888c67329232 100644 --- a/clang/test/Driver/haiku.c +++ b/clang/test/Driver/haiku.c @@ -65,3 +65,8 @@ // CHECK-X86_64-SHARED-SAME: "-isysroot" "[[SYSROOT:[^"]+]]" // CHECK-X86_64-SHARED: "{{.*}}ld{{(.exe)?}}" // CHECK-X86_64-SHARED-NOT: "[[SYSROOT]]/boot/system/develop/lib/start_dyn.o" + +// Check default ARM CPU, ARMv6 +// RUN: %clang -### %s 2>&1 --target=arm-unknown-haiku \ +// RUN: | FileCheck --check-prefix=CHECK-ARM-CPU %s +// CHECK-ARM-CPU: "-target-cpu" "arm1176jzf-s" diff --git a/clang/test/Driver/hip-offload-compress-zlib.hip b/clang/test/Driver/hip-offload-compress-zlib.hip new file mode 100644 index 0000000000000..a29b6d037350d --- /dev/null +++ b/clang/test/Driver/hip-offload-compress-zlib.hip @@ -0,0 +1,45 @@ +// REQUIRES: zlib +// REQUIRES: x86-registered-target +// REQUIRES: amdgpu-registered-target + +// Test compress bundled bitcode. + +// RUN: rm -rf %T/a.bc +// RUN: %clang -c -v --target=x86_64-linux-gnu \ +// RUN: -x hip --offload-arch=gfx1100 --offload-arch=gfx1101 \ +// RUN: -fgpu-rdc -nogpuinc -nogpulib \ +// RUN: %S/Inputs/hip_multiple_inputs/a.cu \ +// RUN: --offload-compress --offload-device-only --gpu-bundle-output \ +// RUN: -o %T/a.bc \ +// RUN: 2>&1 | FileCheck %s + +// CHECK: clang-offload-bundler{{.*}} -type=bc +// CHECK-SAME: -targets={{.*}}hip-amdgcn-amd-amdhsa-gfx1100,hip-amdgcn-amd-amdhsa-gfx1101 +// CHECK-SAME: -compress -verbose +// CHECK: Compressed bundle format + +// Test uncompress of bundled bitcode. + +// RUN: %clang --hip-link -### -v --target=x86_64-linux-gnu \ +// RUN: --offload-arch=gfx1100 --offload-arch=gfx1101 \ +// RUN: -fgpu-rdc -nogpulib \ +// RUN: %T/a.bc --offload-device-only \ +// RUN: 2>&1 | FileCheck -check-prefix=UNBUNDLE %s + +// UNBUNDLE: clang-offload-bundler{{.*}} "-type=bc" +// UNBUNDLE-SAME: -targets={{.*}}hip-amdgcn-amd-amdhsa-gfx1100,hip-amdgcn-amd-amdhsa-gfx1101 +// UNBUNDLE-SAME: -unbundle +// UNBUNDLE-SAME: -verbose + +// Test compress bundled code objects. + +// RUN: %clang -c -### -v --target=x86_64-linux-gnu \ +// RUN: -x hip --offload-arch=gfx1100 --offload-arch=gfx1101 \ +// RUN: -nogpuinc -nogpulib \ +// RUN: %S/Inputs/hip_multiple_inputs/a.cu \ +// RUN: --offload-compress \ +// RUN: 2>&1 | FileCheck -check-prefix=CO %s + +// CO: clang-offload-bundler{{.*}} "-type=o" +// CO-SAME: -targets={{.*}}hipv4-amdgcn-amd-amdhsa--gfx1100,hipv4-amdgcn-amd-amdhsa--gfx1101 +// CO-SAME: "-compress" "-verbose" diff --git a/clang/test/Driver/hip-offload-compress-zstd.hip b/clang/test/Driver/hip-offload-compress-zstd.hip new file mode 100644 index 0000000000000..688c2c85329c1 --- /dev/null +++ b/clang/test/Driver/hip-offload-compress-zstd.hip @@ -0,0 +1,45 @@ +// REQUIRES: zstd +// REQUIRES: x86-registered-target +// REQUIRES: amdgpu-registered-target + +// Test compress bundled bitcode. + +// RUN: rm -rf %T/a.bc +// RUN: %clang -c -v --target=x86_64-linux-gnu \ +// RUN: -x hip --offload-arch=gfx1100 --offload-arch=gfx1101 \ +// RUN: -fgpu-rdc -nogpuinc -nogpulib \ +// RUN: %S/Inputs/hip_multiple_inputs/a.cu \ +// RUN: --offload-compress --offload-device-only --gpu-bundle-output \ +// RUN: -o %T/a.bc \ +// RUN: 2>&1 | FileCheck %s + +// CHECK: clang-offload-bundler{{.*}} -type=bc +// CHECK-SAME: -targets={{.*}}hip-amdgcn-amd-amdhsa-gfx1100,hip-amdgcn-amd-amdhsa-gfx1101 +// CHECK-SAME: -compress -verbose +// CHECK: Compressed bundle format + +// Test uncompress of bundled bitcode. + +// RUN: %clang --hip-link -### -v --target=x86_64-linux-gnu \ +// RUN: --offload-arch=gfx1100 --offload-arch=gfx1101 \ +// RUN: -fgpu-rdc -nogpulib \ +// RUN: %T/a.bc --offload-device-only \ +// RUN: 2>&1 | FileCheck -check-prefix=UNBUNDLE %s + +// UNBUNDLE: clang-offload-bundler{{.*}} "-type=bc" +// UNBUNDLE-SAME: -targets={{.*}}hip-amdgcn-amd-amdhsa-gfx1100,hip-amdgcn-amd-amdhsa-gfx1101 +// UNBUNDLE-SAME: -unbundle +// UNBUNDLE-SAME: -verbose + +// Test compress bundled code objects. + +// RUN: %clang -c -### -v --target=x86_64-linux-gnu \ +// RUN: -x hip --offload-arch=gfx1100 --offload-arch=gfx1101 \ +// RUN: -nogpuinc -nogpulib \ +// RUN: %S/Inputs/hip_multiple_inputs/a.cu \ +// RUN: --offload-compress \ +// RUN: 2>&1 | FileCheck -check-prefix=CO %s + +// CO: clang-offload-bundler{{.*}} "-type=o" +// CO-SAME: -targets={{.*}}hipv4-amdgcn-amd-amdhsa--gfx1100,hipv4-amdgcn-amd-amdhsa--gfx1101 +// CO-SAME: "-compress" "-verbose" diff --git a/clang/test/Driver/hipstdpar.c b/clang/test/Driver/hipstdpar.c index f12a6e8d9d252..69c5b177d170c 100644 --- a/clang/test/Driver/hipstdpar.c +++ b/clang/test/Driver/hipstdpar.c @@ -1,8 +1,9 @@ -// XFAIL: target={{.*}}-apple{{.*}} +// REQUIRES: x86-registered-target +// REQUIRES: amdgpu-registered-target +// REQUIRES: system-linux // XFAIL: target={{.*}}hexagon{{.*}} // XFAIL: target={{.*}}-scei{{.*}} // XFAIL: target={{.*}}-sie{{.*}} -// XFAIL: target={{.*}}-windows{{.*}} // RUN: not %clang -### --hipstdpar -nogpulib -nogpuinc --compile %s 2>&1 | \ // RUN: FileCheck --check-prefix=HIPSTDPAR-MISSING-LIB %s diff --git a/clang/test/Driver/mingw.cpp b/clang/test/Driver/mingw.cpp index 0f276820d0fff..bb22a0652b486 100644 --- a/clang/test/Driver/mingw.cpp +++ b/clang/test/Driver/mingw.cpp @@ -77,3 +77,6 @@ // CHECK_NO_SUBSYS-NOT: "--subsystem" // CHECK_SUBSYS_CONSOLE: "--subsystem" "console" // CHECK_SUBSYS_WINDOWS: "--subsystem" "windows" + +// RUN: %clang -target i686-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_NO_INIT_ARRAY %s +// CHECK_NO_INIT_ARRAY: "-fno-use-init-array" diff --git a/clang/test/Frontend/Inputs/dashE/dashE.h b/clang/test/Frontend/Inputs/dashE/dashE.h new file mode 100644 index 0000000000000..c1a9df40e34dd --- /dev/null +++ b/clang/test/Frontend/Inputs/dashE/dashE.h @@ -0,0 +1,3 @@ +int dashE_1; +#include +int dashE_2; diff --git a/clang/test/Frontend/Inputs/dashE/sys/a.h b/clang/test/Frontend/Inputs/dashE/sys/a.h new file mode 100644 index 0000000000000..55b2bcb4ccb40 --- /dev/null +++ b/clang/test/Frontend/Inputs/dashE/sys/a.h @@ -0,0 +1,3 @@ +int a_1; +#include +int a_2; diff --git a/clang/test/Frontend/Inputs/dashE/sys/b.h b/clang/test/Frontend/Inputs/dashE/sys/b.h new file mode 100644 index 0000000000000..67bdce58dfb97 --- /dev/null +++ b/clang/test/Frontend/Inputs/dashE/sys/b.h @@ -0,0 +1 @@ +int b_1; diff --git a/clang/test/Frontend/dashE-sysincludes.cpp b/clang/test/Frontend/dashE-sysincludes.cpp new file mode 100644 index 0000000000000..45c70670588f1 --- /dev/null +++ b/clang/test/Frontend/dashE-sysincludes.cpp @@ -0,0 +1,23 @@ +// RUN: mkdir -p %t.dir +// RUN: %clang_cc1 -E -fkeep-system-includes -I %S/Inputs/dashE -isystem %S/Inputs/dashE/sys %s | FileCheck %s + +int main_1 = 1; +#include +int main_2 = 1; +#include "dashE.h" +int main_3 = 1; + +// CHECK: main_1 +// CHECK: #include +// CHECK-NOT: a_1 +// CHECK-NOT: a_2 +// CHECK-NOT: b.h +// CHECK: main_2 +// CHECK-NOT: #include "dashE.h" +// CHECK: dashE_1 +// CHECK: #include +// CHECK-NOT: a_1 +// CHECK-NOT: a_2 +// CHECK-NOT: b.h +// CHECK: dashE_2 +// CHECK: main_3 diff --git a/clang/test/Frontend/rewrite-includes-cli-include.c b/clang/test/Frontend/rewrite-includes-cli-include.c index d63f966f79ca6..437bc2ffadf19 100644 --- a/clang/test/Frontend/rewrite-includes-cli-include.c +++ b/clang/test/Frontend/rewrite-includes-cli-include.c @@ -3,6 +3,7 @@ main_file_line // CHECK: {{^}}# 1 ""{{$}} // CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes2.h" 1{{$}} // CHECK-NEXT: {{^}}int included_line2;{{$}} +// CHECK-NEXT: {{^}}#endif /* rewrite-includes2.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 1 "" 2{{$}} // CHECK-NEXT: {{^}}# 1 "{{.*}}rewrite-includes-cli-include.c"{{$}} // CHECK-NEXT: FileCheck diff --git a/clang/test/Frontend/rewrite-includes.c b/clang/test/Frontend/rewrite-includes.c index 15254931250c1..7cca01c11e585 100644 --- a/clang/test/Frontend/rewrite-includes.c +++ b/clang/test/Frontend/rewrite-includes.c @@ -28,9 +28,9 @@ static int unused; // CHECK: {{^}}// STARTCOMPARE{{$}} // CHECK-NEXT: {{^}}#define A(a,b) a ## b{{$}} // CHECK-NEXT: {{^}}A(in,t) a;{{$}} -// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes1.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}#include "rewrite-includes1.h"{{$}} -// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#else /* rewrite-includes1.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 7 "{{.*}}rewrite-includes.c"{{$}} // CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes1.h" 1{{$}} // CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} @@ -38,22 +38,25 @@ static int unused; // CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 2 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes1.h" 3{{$}} // CHECK-NEXT: {{^}}int included_line1;{{$}} -// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) || defined(__CLANG_REWRITTEN_SYSTEM_INCLUDES) /* rewrite-includes2.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}#include "rewrite-includes2.h"{{$}} -// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#else /* rewrite-includes2.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 3 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes1.h" 3{{$}} // CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes2.h" 1 3{{$}} // CHECK-NEXT: {{^}}int included_line2;{{$}} +// CHECK-NEXT: {{^}}#endif /* rewrite-includes2.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 4 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes1.h" 2 3{{$}} +// CHECK-NEXT: {{^}}#endif /* rewrite-includes1.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 8 "{{.*}}rewrite-includes.c" 2{{$}} // CHECK-NEXT: {{^}}#ifdef FIRST{{$}} // CHECK-NEXT: {{^}}#define HEADER "rewrite-includes3.h"{{$}} -// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes3.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}#include HEADER{{$}} -// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#else /* rewrite-includes3.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 10 "{{.*}}rewrite-includes.c"{{$}} // CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes3.h" 1{{$}} // CHECK-NEXT: {{^}}unsigned int included_line3 = -10;{{$}} +// CHECK-NEXT: {{^}}#endif /* rewrite-includes3.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 11 "{{.*}}rewrite-includes.c" 2{{$}} // CHECK-NEXT: {{^}}#else{{$}} // CHECK-NEXT: {{^}}# 12 "{{.*}}rewrite-includes.c"{{$}} @@ -65,17 +68,18 @@ static int unused; // CHECK-NEXT: {{^}}#endif{{$}} // CHECK-NEXT: {{^}}# 14 "{{.*}}rewrite-includes.c"{{$}} // CHECK-NEXT: {{^}} // indented{{$}} -// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes5.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}#/**/include /**/ "rewrite-includes5.h" /**/ {{\\}}{{$}} // CHECK-NEXT: {{^}} {{$}} -// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#else /* rewrite-includes5.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 16 "{{.*}}rewrite-includes.c"{{$}} // CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes5.h" 1{{$}} // CHECK-NEXT: {{^}}int included_line5;{{$}} +// CHECK-NEXT: {{^}}#endif /* rewrite-includes5.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 17 "{{.*}}rewrite-includes.c" 2{{$}} -// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes6.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}#include "rewrite-includes6.h" // comment{{$}} -// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#else /* rewrite-includes6.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 17 "{{.*}}rewrite-includes.c"{{$}} // CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes6.h" 1{{$}} // CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} @@ -83,6 +87,7 @@ static int unused; // CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 2 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes6.h"{{$}} // CHECK-NEXT: {{^}}int included_line6;{{$}} +// CHECK-NEXT: {{^}}#endif /* rewrite-includes6.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 18 "{{.*}}rewrite-includes.c" 2{{$}} // CHECK-NEXT: {{^}} {{$}} // CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} @@ -91,9 +96,9 @@ static int unused; // CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 20 "{{.*}}rewrite-includes.c"{{$}} // CHECK-NEXT: {{^}}# 21 "{{.*}}rewrite-includes.c"{{$}} -// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes7.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}#include "rewrite-includes7.h"{{$}} -// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#else /* rewrite-includes7.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 21 "{{.*}}rewrite-includes.c"{{$}} // CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes7.h" 1{{$}} // CHECK-NEXT: {{^}}#ifndef REWRITE_INCLUDES_7{{$}} @@ -101,15 +106,16 @@ static int unused; // CHECK-NEXT: {{^}}int included_line7;{{$}} // CHECK-NEXT: {{^}}#endif{{$}} // CHECK-NEXT: {{^}}# 5 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes7.h"{{$}} +// CHECK-NEXT: {{^}}#endif /* rewrite-includes7.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 22 "{{.*}}rewrite-includes.c" 2{{$}} // CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}#include "rewrite-includes7.h"{{$}} // CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 22 "{{.*}}rewrite-includes.c"{{$}} // CHECK-NEXT: {{^}}# 23 "{{.*}}rewrite-includes.c"{{$}} -// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes8.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}#include "rewrite-includes8.h"{{$}} -// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#else /* rewrite-includes8.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 23 "{{.*}}rewrite-includes.c"{{$}} // CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes8.h" 1{{$}} // CHECK-NEXT: {{^}}#if 0 /* disabled by -frewrite-includes */{{$}} @@ -135,10 +141,11 @@ static int unused; // CHECK-NEXT: {{^}}# 5 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes8.h"{{$}} // CHECK-NEXT: {{^}}#endif{{$}} // CHECK-NEXT: {{^}}# 6 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes8.h"{{$}} +// CHECK-NEXT: {{^}}#endif /* rewrite-includes8.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 24 "{{.*}}rewrite-includes.c" 2{{$}} -// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes9.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}#include "rewrite-includes9.h"{{$}} -// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#else /* rewrite-includes9.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 24 "{{.*}}rewrite-includes.c"{{$}} // CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes9.h" 1{{$}} // CHECK-NEXT: {{^}}#if 0 /* disabled by -frewrite-includes */{{$}} @@ -147,15 +154,17 @@ static int unused; // CHECK-NEXT: {{^}}#endif /* disabled by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}#if 1 /* evaluated by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 2 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes9.h"{{$}} -// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes9.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}#include_next {{$}} -// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECK-NEXT: {{^}}#else /* rewrite-includes9.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 2 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes9.h"{{$}} // CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs(/|\\\\)NextIncludes(/|\\\\)}}rewrite-includes9.h" 1{{$}} // CHECK-NEXT: {{^}}int included_line9;{{$}} +// CHECK-NEXT: {{^}}#endif /* rewrite-includes9.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 3 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes9.h" 2{{$}} // CHECK-NEXT: {{^}}#endif{{$}} // CHECK-NEXT: {{^}}# 4 "{{.*[/\\]Inputs(/|\\\\)}}rewrite-includes9.h"{{$}} +// CHECK-NEXT: {{^}}#endif /* rewrite-includes9.h expanded by -frewrite-includes */{{$}} // CHECK-NEXT: {{^}}# 25 "{{.*}}rewrite-includes.c" 2{{$}} // CHECK-NEXT: {{^}}static int unused;{{$}} // CHECK-NEXT: {{^}}// ENDCOMPARE{{$}} @@ -163,59 +172,65 @@ static int unused; // CHECKNL: {{^}}// STARTCOMPARE{{$}} // CHECKNL-NEXT: {{^}}#define A(a,b) a ## b{{$}} // CHECKNL-NEXT: {{^}}A(in,t) a;{{$}} -// CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes1.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#include "rewrite-includes1.h"{{$}} -// CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#else /* rewrite-includes1.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#pragma clang system_header{{$}} // CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}int included_line1;{{$}} -// CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) || defined(__CLANG_REWRITTEN_SYSTEM_INCLUDES) /* rewrite-includes2.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#include "rewrite-includes2.h"{{$}} -// CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#else /* rewrite-includes2.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}int included_line2;{{$}} +// CHECKNL-NEXT: {{^}}#endif /* rewrite-includes2.h expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#endif /* rewrite-includes1.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#ifdef FIRST{{$}} // CHECKNL-NEXT: {{^}}#define HEADER "rewrite-includes3.h"{{$}} -// CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes3.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#include HEADER{{$}} -// CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#else /* rewrite-includes3.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}unsigned int included_line3 = -10;{{$}} +// CHECKNL-NEXT: {{^}}#endif /* rewrite-includes3.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#else{{$}} // CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#include "rewrite-includes4.h"{{$}} // CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#endif{{$}} // CHECKNL-NEXT: {{^}} // indented{{$}} -// CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes5.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#/**/include /**/ "rewrite-includes5.h" /**/ {{\\}}{{$}} // CHECKNL-NEXT: {{^}} {{$}} -// CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#else /* rewrite-includes5.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}int included_line5;{{$}} -// CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#endif /* rewrite-includes5.h expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes6.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#include "rewrite-includes6.h" // comment{{$}} -// CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#else /* rewrite-includes6.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#pragma once{{$}} // CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}int included_line6;{{$}} +// CHECKNL-NEXT: {{^}}#endif /* rewrite-includes6.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}} {{$}} // CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#include "rewrite-includes6.h" /* comment{{$}} // CHECKNL-NEXT: {{^}} continues */{{$}} // CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} -// CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes7.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#include "rewrite-includes7.h"{{$}} -// CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#else /* rewrite-includes7.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#ifndef REWRITE_INCLUDES_7{{$}} // CHECKNL-NEXT: {{^}}#define REWRITE_INCLUDES_7{{$}} // CHECKNL-NEXT: {{^}}int included_line7;{{$}} // CHECKNL-NEXT: {{^}}#endif{{$}} +// CHECKNL-NEXT: {{^}}#endif /* rewrite-includes7.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#include "rewrite-includes7.h"{{$}} // CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} -// CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes8.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#include "rewrite-includes8.h"{{$}} -// CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#else /* rewrite-includes8.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#if 0 /* disabled by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#if __has_include_next(){{$}} // CHECKNL-NEXT: {{^}}#endif{{$}} @@ -234,19 +249,22 @@ static int unused; // CHECKNL-NEXT: {{^}}#endif /* disabled by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#if 0 /* evaluated by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#endif{{$}} -// CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#endif /* rewrite-includes8.h expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes9.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#include "rewrite-includes9.h"{{$}} -// CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#else /* rewrite-includes9.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#if 0 /* disabled by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#if __has_include_next(){{$}} // CHECKNL-NEXT: {{^}}#endif{{$}} // CHECKNL-NEXT: {{^}}#endif /* disabled by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#if 1 /* evaluated by -frewrite-includes */{{$}} -// CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#if defined(__CLANG_REWRITTEN_INCLUDES) /* rewrite-includes9.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#include_next {{$}} -// CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}} +// CHECKNL-NEXT: {{^}}#else /* rewrite-includes9.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}int included_line9;{{$}} +// CHECKNL-NEXT: {{^}}#endif /* rewrite-includes9.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}#endif{{$}} +// CHECKNL-NEXT: {{^}}#endif /* rewrite-includes9.h expanded by -frewrite-includes */{{$}} // CHECKNL-NEXT: {{^}}static int unused;{{$}} // CHECKNL-NEXT: {{^}}// ENDCOMPARE{{$}} diff --git a/clang/test/Headers/__clang_hip_math.hip b/clang/test/Headers/__clang_hip_math.hip index fc18e14d82296..15eccc3b2baba 100644 --- a/clang/test/Headers/__clang_hip_math.hip +++ b/clang/test/Headers/__clang_hip_math.hip @@ -231,8 +231,8 @@ extern "C" __device__ uint64_t test___make_mantissa(const char *p) { // CHECK-LABEL: @test_abs( // CHECK-NEXT: entry: -// CHECK-NEXT: [[ABS_I:%.*]] = tail call noundef i32 @llvm.abs.i32(i32 [[X:%.*]], i1 true) -// CHECK-NEXT: ret i32 [[ABS_I]] +// CHECK-NEXT: [[TMP0:%.*]] = tail call noundef i32 @llvm.abs.i32(i32 [[X:%.*]], i1 true) +// CHECK-NEXT: ret i32 [[TMP0]] // extern "C" __device__ int test_abs(int x) { return abs(x); @@ -240,8 +240,8 @@ extern "C" __device__ int test_abs(int x) { // CHECK-LABEL: @test_labs( // CHECK-NEXT: entry: -// CHECK-NEXT: [[ABS_I:%.*]] = tail call noundef i64 @llvm.abs.i64(i64 [[X:%.*]], i1 true) -// CHECK-NEXT: ret i64 [[ABS_I]] +// CHECK-NEXT: [[TMP0:%.*]] = tail call noundef i64 @llvm.abs.i64(i64 [[X:%.*]], i1 true) +// CHECK-NEXT: ret i64 [[TMP0]] // extern "C" __device__ long test_labs(long x) { return labs(x); @@ -249,8 +249,8 @@ extern "C" __device__ long test_labs(long x) { // CHECK-LABEL: @test_llabs( // CHECK-NEXT: entry: -// CHECK-NEXT: [[ABS_I:%.*]] = tail call noundef i64 @llvm.abs.i64(i64 [[X:%.*]], i1 true) -// CHECK-NEXT: ret i64 [[ABS_I]] +// CHECK-NEXT: [[TMP0:%.*]] = tail call noundef i64 @llvm.abs.i64(i64 [[X:%.*]], i1 true) +// CHECK-NEXT: ret i64 [[TMP0]] // extern "C" __device__ long long test_llabs(long x) { return llabs(x); @@ -2557,33 +2557,65 @@ extern "C" __device__ double test_nan(const char *tag) { return nan(tag); } -// CHECK-LABEL: @test_nanf_emptystr( -// CHECK-NEXT: entry: -// CHECK-NEXT: ret float 0x7FF8000000000000 +// DEFAULT-LABEL: @test_nanf_emptystr( +// DEFAULT-NEXT: entry: +// DEFAULT-NEXT: ret float 0x7FF8000000000000 +// +// FINITEONLY-LABEL: @test_nanf_emptystr( +// FINITEONLY-NEXT: entry: +// FINITEONLY-NEXT: ret float poison +// +// APPROX-LABEL: @test_nanf_emptystr( +// APPROX-NEXT: entry: +// APPROX-NEXT: ret float 0x7FF8000000000000 // extern "C" __device__ float test_nanf_emptystr() { return nanf(""); } -// CHECK-LABEL: @test_nan_emptystr( -// CHECK-NEXT: entry: -// CHECK-NEXT: ret double 0x7FF8000000000000 +// DEFAULT-LABEL: @test_nan_emptystr( +// DEFAULT-NEXT: entry: +// DEFAULT-NEXT: ret double 0x7FF8000000000000 +// +// FINITEONLY-LABEL: @test_nan_emptystr( +// FINITEONLY-NEXT: entry: +// FINITEONLY-NEXT: ret double poison +// +// APPROX-LABEL: @test_nan_emptystr( +// APPROX-NEXT: entry: +// APPROX-NEXT: ret double 0x7FF8000000000000 // extern "C" __device__ double test_nan_emptystr() { return nan(""); } -// CHECK-LABEL: @test_nanf_fill( -// CHECK-NEXT: entry: -// CHECK-NEXT: ret float 0x7FF8000000000000 +// DEFAULT-LABEL: @test_nanf_fill( +// DEFAULT-NEXT: entry: +// DEFAULT-NEXT: ret float 0x7FF8000000000000 +// +// FINITEONLY-LABEL: @test_nanf_fill( +// FINITEONLY-NEXT: entry: +// FINITEONLY-NEXT: ret float poison +// +// APPROX-LABEL: @test_nanf_fill( +// APPROX-NEXT: entry: +// APPROX-NEXT: ret float 0x7FF8000000000000 // extern "C" __device__ float test_nanf_fill() { return nanf("0x456"); } -// CHECK-LABEL: @test_nan_fill( -// CHECK-NEXT: entry: -// CHECK-NEXT: ret double 0x7FF8000000000000 +// DEFAULT-LABEL: @test_nan_fill( +// DEFAULT-NEXT: entry: +// DEFAULT-NEXT: ret double 0x7FF8000000000000 +// +// FINITEONLY-LABEL: @test_nan_fill( +// FINITEONLY-NEXT: entry: +// FINITEONLY-NEXT: ret double poison +// +// APPROX-LABEL: @test_nan_fill( +// APPROX-NEXT: entry: +// APPROX-NEXT: ret double 0x7FF8000000000000 // extern "C" __device__ double test_nan_fill() { return nan("0x123"); diff --git a/clang/test/Misc/misc-source-ranges.cpp b/clang/test/Misc/misc-source-ranges.cpp new file mode 100644 index 0000000000000..7a9d9d057dac4 --- /dev/null +++ b/clang/test/Misc/misc-source-ranges.cpp @@ -0,0 +1,7 @@ +// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-print-source-range-info %s 2>&1 | FileCheck %s + +struct S { + char a : 12 - 12; +}; +// CHECK: misc-source-ranges.cpp:[[@LINE-2]]:8:{[[@LINE-2]]:12-[[@LINE-2]]:19} + diff --git a/clang/test/Modules/Inputs/System/usr/include/inttypes.h b/clang/test/Modules/Inputs/System/usr/include/inttypes.h deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/clang/test/Modules/Inputs/System/usr/include/math.h b/clang/test/Modules/Inputs/System/usr/include/math.h deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/clang/test/Modules/Inputs/System/usr/include/module.map b/clang/test/Modules/Inputs/System/usr/include/module.map index 5a15c70a394d2..1d88ca380f49a 100644 --- a/clang/test/Modules/Inputs/System/usr/include/module.map +++ b/clang/test/Modules/Inputs/System/usr/include/module.map @@ -1,24 +1,9 @@ module cstd [system] { - // Only in system headers directory - module complex { - header "complex.h" - } - // Only in compiler support directory module float_constants { header "float.h" } - // In both directories (compiler support version wins, forwards) - module inttypes { - header "inttypes.h" - } - - // Only in system headers directory - module math { - header "math.h" - } - // Only in system headers directory module stdio { header "stdio.h" diff --git a/clang/test/Modules/Inputs/System/usr/include/stdint.h b/clang/test/Modules/Inputs/System/usr/include/stdint.h index 209d54cd411ad..e8e50f90290ce 100644 --- a/clang/test/Modules/Inputs/System/usr/include/stdint.h +++ b/clang/test/Modules/Inputs/System/usr/include/stdint.h @@ -1,36 +1 @@ -#ifndef STDINT_H -#define STDINT_H - typedef int my_awesome_nonstandard_integer_type; - -// types needed by stdatomic.h - -typedef char int_least8_t; -typedef short int_least16_t; -typedef int int_least32_t; -typedef long long int int_least64_t; -typedef unsigned char uint_least8_t; -typedef unsigned short uint_least16_t; -typedef unsigned int uint_least32_t; -typedef unsigned long long uint_least64_t; - -typedef char int_fast8_t; -typedef short int_fast16_t; -typedef int int_fast32_t; -typedef long long int int_fast64_t; -typedef unsigned char uint_fast8_t; -typedef unsigned short uint_fast16_t; -typedef unsigned int uint_fast32_t; -typedef unsigned long long uint_fast64_t; - -typedef int intptr_t; -typedef unsigned int uintptr_t; -typedef int intmax_t; -typedef unsigned int uintmax_t; - -// additional types for unwind.h - -typedef unsigned int uint32_t; -typedef unsigned long long uint64_t; - -#endif /* STDINT_H */ diff --git a/clang/test/Modules/Inputs/builtin-headers/builtin-modules.modulemap b/clang/test/Modules/Inputs/builtin-headers/builtin-modules.modulemap new file mode 100644 index 0000000000000..0fbb454dbb022 --- /dev/null +++ b/clang/test/Modules/Inputs/builtin-headers/builtin-modules.modulemap @@ -0,0 +1,29 @@ +module c_complex [system] { + header "complex.h" + export * +} + +module c_float [system] { + header "float.h" + export * +} + +module c_inttypes [system] { + header "inttypes.h" + export * +} + +module c_limits [system] { + header "limits.h" + export * +} + +module c_math [system] { + header "math.h" + export * +} + +module c_stdint [system] { + header "stdint.h" + export * +} diff --git a/clang/test/Modules/Inputs/builtin-headers/c++/module.modulemap b/clang/test/Modules/Inputs/builtin-headers/c++/module.modulemap new file mode 100644 index 0000000000000..c969f067a234f --- /dev/null +++ b/clang/test/Modules/Inputs/builtin-headers/c++/module.modulemap @@ -0,0 +1,4 @@ +module cpp_stdint [system] { + header "stdint.h" + export * +} diff --git a/clang/test/Modules/Inputs/builtin-headers/c++/stdint.h b/clang/test/Modules/Inputs/builtin-headers/c++/stdint.h new file mode 100644 index 0000000000000..22cebacfdb64e --- /dev/null +++ b/clang/test/Modules/Inputs/builtin-headers/c++/stdint.h @@ -0,0 +1,6 @@ +#ifndef CPP_STDINT_H +#define CPP_STDINT_H + +#include_next + +#endif diff --git a/clang/test/Modules/Inputs/builtin-headers/complex.h b/clang/test/Modules/Inputs/builtin-headers/complex.h new file mode 100644 index 0000000000000..b6ef3c5a35b45 --- /dev/null +++ b/clang/test/Modules/Inputs/builtin-headers/complex.h @@ -0,0 +1 @@ +// Required by tgmath.h diff --git a/clang/test/Modules/Inputs/System/usr/include/complex.h b/clang/test/Modules/Inputs/builtin-headers/float.h similarity index 100% rename from clang/test/Modules/Inputs/System/usr/include/complex.h rename to clang/test/Modules/Inputs/builtin-headers/float.h diff --git a/clang/test/Modules/Inputs/builtin-headers/inttypes.h b/clang/test/Modules/Inputs/builtin-headers/inttypes.h new file mode 100644 index 0000000000000..ddb6bb83b5723 --- /dev/null +++ b/clang/test/Modules/Inputs/builtin-headers/inttypes.h @@ -0,0 +1,12 @@ +#ifndef INTTYPES_H +#define INTTYPES_H + +// This creates an include cycle when inttypes.h and stdint.h +// are both part of the cstd module. This include will resolve +// to the C++ stdint.h, which will #include_next eventually to +// the stdint.h in this directory, and thus create the cycle +// cstd (inttypes.h) -> cpp_stdint (stdint.h) -> cstd (stdint.h). +// This cycle is worked around by cstd using [no_undeclared_includes]. +#include + +#endif diff --git a/clang/test/Modules/Inputs/builtin-headers/limits.h b/clang/test/Modules/Inputs/builtin-headers/limits.h new file mode 100644 index 0000000000000..8b137891791fe --- /dev/null +++ b/clang/test/Modules/Inputs/builtin-headers/limits.h @@ -0,0 +1 @@ + diff --git a/clang/test/Modules/Inputs/builtin-headers/math.h b/clang/test/Modules/Inputs/builtin-headers/math.h new file mode 100644 index 0000000000000..b6ef3c5a35b45 --- /dev/null +++ b/clang/test/Modules/Inputs/builtin-headers/math.h @@ -0,0 +1 @@ +// Required by tgmath.h diff --git a/clang/test/Modules/Inputs/builtin-headers/stdint.h b/clang/test/Modules/Inputs/builtin-headers/stdint.h new file mode 100644 index 0000000000000..8f233fd7f45d6 --- /dev/null +++ b/clang/test/Modules/Inputs/builtin-headers/stdint.h @@ -0,0 +1,34 @@ +#ifndef STDINT_H +#define STDINT_H + +// types needed by stdatomic.h + +typedef char int_least8_t; +typedef short int_least16_t; +typedef int int_least32_t; +typedef long long int int_least64_t; +typedef unsigned char uint_least8_t; +typedef unsigned short uint_least16_t; +typedef unsigned int uint_least32_t; +typedef unsigned long long uint_least64_t; + +typedef char int_fast8_t; +typedef short int_fast16_t; +typedef int int_fast32_t; +typedef long long int int_fast64_t; +typedef unsigned char uint_fast8_t; +typedef unsigned short uint_fast16_t; +typedef unsigned int uint_fast32_t; +typedef unsigned long long uint_fast64_t; + +typedef int intptr_t; +typedef unsigned int uintptr_t; +typedef int intmax_t; +typedef unsigned int uintmax_t; + +// additional types for unwind.h + +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +#endif diff --git a/clang/test/Modules/Inputs/builtin-headers/system-modules.modulemap b/clang/test/Modules/Inputs/builtin-headers/system-modules.modulemap new file mode 100644 index 0000000000000..0161ff80fe618 --- /dev/null +++ b/clang/test/Modules/Inputs/builtin-headers/system-modules.modulemap @@ -0,0 +1,71 @@ +module cstd [system] [no_undeclared_includes] { + module complex { + header "complex.h" + export * + } + + module float { + header "float.h" + export * + } + + module inttypes { + header "inttypes.h" + export * + } + + module iso646 { + header "iso646.h" + export * + } + + module limits { + header "limits.h" + export * + } + + module math { + header "math.h" + export * + } + + module stdalign { + header "stdalign.h" + export * + } + + module stdarg { + header "stdarg.h" + export * + } + + module stdatomic { + header "stdatomic.h" + export * + } + + module stdbool { + header "stdbool.h" + export * + } + + module stddef { + header "stddef.h" + export * + } + + module stdint { + header "stdint.h" + export * + } + + module tgmath { + header "tgmath.h" + export * + } + + module unwind { + header "unwind.h" + export * + } +} diff --git a/clang/test/Modules/builtin-headers.mm b/clang/test/Modules/builtin-headers.mm new file mode 100644 index 0000000000000..4c9ddec4e99c2 --- /dev/null +++ b/clang/test/Modules/builtin-headers.mm @@ -0,0 +1,41 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -cxx-isystem %S/Inputs/builtin-headers/c++ -internal-isystem %S/Inputs/builtin-headers -fsyntax-only -fmodules -fmodules-cache-path=%t -fmodule-map-file=%S/Inputs/builtin-headers/c++/module.modulemap -fmodule-map-file=%resource_dir/module.modulemap -fmodule-map-file=%S/Inputs/builtin-headers/system-modules.modulemap -fbuiltin-headers-in-system-modules -DSYSTEM_MODULES %s -verify +// RUN: rm -rf %t +// RUN: %clang_cc1 -cxx-isystem %S/Inputs/builtin-headers/c++ -internal-isystem %S/Inputs/builtin-headers -fsyntax-only -fmodules -fmodules-cache-path=%t -fmodule-map-file=%S/Inputs/builtin-headers/c++/module.modulemap -fmodule-map-file=%resource_dir/module.modulemap -fmodule-map-file=%S/Inputs/builtin-headers/builtin-modules.modulemap %s -verify + +// expected-no-diagnostics + +@import cpp_stdint; + +// The builtin modules are always available, though they're mostly +// empty if -fbuiltin-headers-in-system-modules is used. +@import _Builtin_float; +@import _Builtin_inttypes; +@import _Builtin_iso646; +@import _Builtin_limits; +@import _Builtin_stdalign; +@import _Builtin_stdarg; +@import _Builtin_stdatomic; +@import _Builtin_stdbool; +@import _Builtin_stddef; +@import _Builtin_stdint; +@import _Builtin_stdnoreturn; +@import _Builtin_tgmath; +@import _Builtin_unwind; + +#ifdef SYSTEM_MODULES +// system-modules.modulemap uses the "mega module" style with +// -fbuiltin-headers-in-system-modules, and its modules cover +// the clang builtin headers. +@import cstd; +#else +// builtin-modules.modulemap uses top level modules for each +// of its headers, which allows interleaving with the builtin +// modules and libc++ modules. +@import c_complex; +@import c_float; +@import c_inttypes; +@import c_limits; +@import c_math; +@import c_stdint; +#endif diff --git a/clang/test/Modules/compiler_builtins.m b/clang/test/Modules/compiler_builtins.m index 8eeb65daa9e88..a5e6315cedc8e 100644 --- a/clang/test/Modules/compiler_builtins.m +++ b/clang/test/Modules/compiler_builtins.m @@ -1,7 +1,7 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -fsyntax-only -fmodules -fimplicit-module-maps -fmodules-cache-path=%t %s -internal-isystem %S/Inputs/System/usr/include -verify -// RUN: %clang_cc1 -fsyntax-only -std=c99 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t %s -internal-isystem %S/Inputs/System/usr/include -verify -// RUN: %clang_cc1 -fsyntax-only -fmodules -fmodule-map-file=%resource_dir/module.modulemap -fmodules-cache-path=%t %s -I%S/Inputs/System/usr/include -DNO_SYSTEM_MODULES -verify +// RUN: %clang_cc1 -fsyntax-only -fmodules -fimplicit-module-maps -fmodules-cache-path=%t %s -I%S/Inputs/System/usr/include -verify +// RUN: %clang_cc1 -fsyntax-only -std=c99 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t %s -I%S/Inputs/System/usr/include -verify +// RUN: %clang_cc1 -fsyntax-only -fmodules -fmodule-map-file=%resource_dir/module.modulemap -fmodules-cache-path=%t %s -I%S/Inputs/System/usr/include -verify // expected-no-diagnostics #ifdef __SSE__ @@ -11,19 +11,3 @@ #ifdef __AVX2__ @import _Builtin_intrinsics.intel.avx2; #endif - -#ifndef NO_SYSTEM_MODULES -@import _Builtin_float; -@import _Builtin_inttypes; -@import _Builtin_iso646; -@import _Builtin_limits; -@import _Builtin_stdalign; -@import _Builtin_stdarg; -@import _Builtin_stdatomic; -@import _Builtin_stdbool; -@import _Builtin_stddef; -@import _Builtin_stdint; -@import _Builtin_stdnoreturn; -@import _Builtin_tgmath; -@import _Builtin_unwind; -#endif diff --git a/clang/test/Modules/explicit-build-missing-files.cpp b/clang/test/Modules/explicit-build-missing-files.cpp index e36b5051e8319..3ea881d34c6b2 100644 --- a/clang/test/Modules/explicit-build-missing-files.cpp +++ b/clang/test/Modules/explicit-build-missing-files.cpp @@ -50,6 +50,7 @@ int y = a2; // CHECK: In module 'a': // CHECK-NEXT: a.h:1:45: error: +int z = b; // MISSING-B: could not find file '{{.*}}b.h' // MISSING-B-NOT: please delete the module cache #endif diff --git a/clang/test/Modules/no-import-func-body.cppm b/clang/test/Modules/no-import-func-body.cppm new file mode 100644 index 0000000000000..9a111dca9855c --- /dev/null +++ b/clang/test/Modules/no-import-func-body.cppm @@ -0,0 +1,45 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: cd %t +// +// RUN: %clang_cc1 -std=c++20 -O1 -triple %itanium_abi_triple %t/a.cppm \ +// RUN: -emit-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 -O1 -triple %itanium_abi_triple %t/b.cppm \ +// RUN: -emit-module-interface -fprebuilt-module-path=%t -o %t/b.pcm +// RUN: %clang_cc1 -std=c++20 -O1 -triple %itanium_abi_triple %t/c.cppm \ +// RUN: -emit-module-interface -fprebuilt-module-path=%t -o %t/c.pcm +// RUN: %clang_cc1 -std=c++20 -O1 -triple %itanium_abi_triple %t/c.pcm -S \ +// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %t/c.cppm + +//--- a.cppm +export module a; +export int a() { + return 43; +} +export __attribute__((noinline)) int a_noinline() { + return 44; +} + +//--- b.cppm +export module b; +export import a; +export int b() { + return 43 + a(); +} + +export __attribute__((noinline)) int b_noinline() { + return 43 + a(); +} + +//--- c.cppm +export module c; +export import b; +export int c() { + return 43 + b() + a() + b_noinline() + a_noinline(); +} + +// CHECK: define{{.*}}available_externally{{.*}}@_ZW1b1bv( +// CHECK: define{{.*}}available_externally{{.*}}@_ZW1a1av( + +// CHECK: declare{{.*}}@_ZW1b10b_noinlinev() +// CHECK: declare{{.*}}@_ZW1a10a_noinlinev() diff --git a/clang/test/Modules/preprocess-module.cpp b/clang/test/Modules/preprocess-module.cpp index ee909a811836f..7000a58adf01d 100644 --- a/clang/test/Modules/preprocess-module.cpp +++ b/clang/test/Modules/preprocess-module.cpp @@ -71,9 +71,9 @@ // == file.h // CHECK: # 1 "" -// REWRITE: #if 0 +// REWRITE: #if defined(__CLANG_REWRITTEN_INCLUDES) // REWRITE: #include "file.h" -// REWRITE: #endif +// REWRITE: #else /* file.h expanded by -frewrite-includes // // FIXME: It would be preferable to consistently put the module begin/end in // the same file, but the relative ordering of PP callbacks and module @@ -96,18 +96,18 @@ // NO-REWRITE: #pragma clang module end // == file2.h -// REWRITE: #if 0 +// REWRITE: #if defined(__CLANG_REWRITTEN_INCLUDES) // REWRITE: #include "file2.h" -// REWRITE: #endif +// REWRITE: #else /* file2.h expanded // // REWRITE: #pragma clang module begin file // CHECK: # 1 "{{.*}}file2.h" 1 // NO-REWRITE: #pragma clang module begin file // // ==== recursively re-enter file.h -// REWRITE: #if 0 +// REWRITE: #if defined(__CLANG_REWRITTEN_INCLUDES) // REWRITE: #include "file.h" -// REWRITE: #endif +// REWRITE: #else /* file.h expanded // // REWRITE: #pragma clang module begin file // CHECK: # 1 "{{.*}}file.h" 1 diff --git a/clang/test/OpenMP/nvptx_target_teams_ompx_bare_codegen.cpp b/clang/test/OpenMP/nvptx_target_teams_ompx_bare_codegen.cpp new file mode 100644 index 0000000000000..e0fe9eb76a6f1 --- /dev/null +++ b/clang/test/OpenMP/nvptx_target_teams_ompx_bare_codegen.cpp @@ -0,0 +1,56 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs --replace-value-regex "__omp_offloading_[0-9a-z]+_[0-9a-z]+" "reduction_size[.].+[.]" "pl_cond[.].+[.|,]" --prefix-filecheck-ir-name _ +// Test target codegen - host bc file has to be created first. +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple nvptx64-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-target-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s +// expected-no-diagnostics +#ifndef HEADER +#define HEADER + +template +tx ftemplate(int n) { + tx a = 0; + + #pragma omp target teams ompx_bare + { + a = 2; + } + + return a; +} + +int bar(int n){ + int a = 0; + + a += ftemplate(n); + + return a; +} + +#endif +// CHECK-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIcET_i_l13 +// CHECK-SAME: (i64 noundef [[A:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[A_CASTED:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i64 [[A]], ptr [[A_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[A_ADDR]], align 1 +// CHECK-NEXT: store i8 [[TMP0]], ptr [[A_CASTED]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[A_CASTED]], align 8 +// CHECK-NEXT: store i32 0, ptr [[DOTZERO_ADDR]], align 4 +// CHECK-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIcET_i_l13_omp_outlined(ptr null, ptr [[DOTZERO_ADDR]], i64 [[TMP1]]) #[[ATTR2:[0-9]+]] +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIcET_i_l13_omp_outlined +// CHECK-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[A:%.*]]) #[[ATTR1:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 +// CHECK-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8 +// CHECK-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8 +// CHECK-NEXT: store i64 [[A]], ptr [[A_ADDR]], align 8 +// CHECK-NEXT: store i8 2, ptr [[A_ADDR]], align 1 +// CHECK-NEXT: ret void +// diff --git a/clang/test/OpenMP/ompx_bare_messages.c b/clang/test/OpenMP/ompx_bare_messages.c new file mode 100644 index 0000000000000..a1b3c38028528 --- /dev/null +++ b/clang/test/OpenMP/ompx_bare_messages.c @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -verify -fopenmp -triple x86_64-unknown-unknown %s + // RUN: %clang_cc1 -verify -fopenmp-simd -triple x86_64-unknown-unknown %s + // RUN: %clang_cc1 -verify -fopenmp -triple x86_64-unknown-unknown -fopenmp-targets=nvptx64 %s + +void foo() { +} + +void bar() { +#pragma omp target ompx_bare // expected-error {{unexpected OpenMP clause 'ompx_bare' in directive '#pragma omp target'}} expected-note {{OpenMP extension clause 'ompx_bare' only allowed with '#pragma omp target teams'}} + foo(); + +#pragma omp target teams distribute ompx_bare // expected-error {{unexpected OpenMP clause 'ompx_bare' in directive '#pragma omp target teams distribute'}} expected-note {{OpenMP extension clause 'ompx_bare' only allowed with '#pragma omp target teams'}} + for (int i = 0; i < 10; ++i) {} + +#pragma omp target teams distribute parallel for ompx_bare // expected-error {{unexpected OpenMP clause 'ompx_bare' in directive '#pragma omp target teams distribute parallel for'}} expected-note {{OpenMP extension clause 'ompx_bare' only allowed with '#pragma omp target teams'}} + for (int i = 0; i < 10; ++i) {} + +#pragma omp target +#pragma omp teams ompx_bare // expected-error {{unexpected OpenMP clause 'ompx_bare' in directive '#pragma omp teams'}} expected-note {{OpenMP extension clause 'ompx_bare' only allowed with '#pragma omp target teams'}} + foo(); +} diff --git a/clang/test/OpenMP/target_teams_ast_print.cpp b/clang/test/OpenMP/target_teams_ast_print.cpp index 19943a81eab8e..5f1040be01a25 100644 --- a/clang/test/OpenMP/target_teams_ast_print.cpp +++ b/clang/test/OpenMP/target_teams_ast_print.cpp @@ -111,6 +111,10 @@ int main (int argc, char **argv) { // CHECK-NEXT: #pragma omp target teams a=2; // CHECK-NEXT: a = 2; +#pragma omp target teams ompx_bare +// CHECK-NEXT: #pragma omp target teams ompx_bare + a=3; +// CHECK-NEXT: a = 3; #pragma omp target teams default(none), private(argc,b) num_teams(f) firstprivate(argv) reduction(| : c, d) reduction(* : e) thread_limit(f+g) // CHECK-NEXT: #pragma omp target teams default(none) private(argc,b) num_teams(f) firstprivate(argv) reduction(|: c,d) reduction(*: e) thread_limit(f + g) foo(); diff --git a/clang/test/OpenMP/target_teams_codegen.cpp b/clang/test/OpenMP/target_teams_codegen.cpp index 5c32a79bb64b0..3185d90b5ef14 100644 --- a/clang/test/OpenMP/target_teams_codegen.cpp +++ b/clang/test/OpenMP/target_teams_codegen.cpp @@ -121,6 +121,12 @@ int foo(int n) { aa += 1; } + #pragma omp target teams ompx_bare + { + a += 1; + aa += 1; + } + // We capture 3 VLA sizes in this target region @@ -336,22 +342,28 @@ int bar(int n){ // CHECK1-NEXT: [[DOTOFFLOAD_MAPPERS12:%.*]] = alloca [2 x ptr], align 8 // CHECK1-NEXT: [[KERNEL_ARGS13:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 // CHECK1-NEXT: [[A_CASTED16:%.*]] = alloca i64, align 8 -// CHECK1-NEXT: [[DOTOFFLOAD_BASEPTRS19:%.*]] = alloca [9 x ptr], align 8 -// CHECK1-NEXT: [[DOTOFFLOAD_PTRS20:%.*]] = alloca [9 x ptr], align 8 -// CHECK1-NEXT: [[DOTOFFLOAD_MAPPERS21:%.*]] = alloca [9 x ptr], align 8 +// CHECK1-NEXT: [[AA_CASTED17:%.*]] = alloca i64, align 8 +// CHECK1-NEXT: [[DOTOFFLOAD_BASEPTRS18:%.*]] = alloca [2 x ptr], align 8 +// CHECK1-NEXT: [[DOTOFFLOAD_PTRS19:%.*]] = alloca [2 x ptr], align 8 +// CHECK1-NEXT: [[DOTOFFLOAD_MAPPERS20:%.*]] = alloca [2 x ptr], align 8 +// CHECK1-NEXT: [[KERNEL_ARGS21:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 +// CHECK1-NEXT: [[A_CASTED24:%.*]] = alloca i64, align 8 +// CHECK1-NEXT: [[DOTOFFLOAD_BASEPTRS27:%.*]] = alloca [9 x ptr], align 8 +// CHECK1-NEXT: [[DOTOFFLOAD_PTRS28:%.*]] = alloca [9 x ptr], align 8 +// CHECK1-NEXT: [[DOTOFFLOAD_MAPPERS29:%.*]] = alloca [9 x ptr], align 8 // CHECK1-NEXT: [[DOTOFFLOAD_SIZES:%.*]] = alloca [9 x i64], align 8 -// CHECK1-NEXT: [[KERNEL_ARGS22:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 +// CHECK1-NEXT: [[KERNEL_ARGS30:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 // CHECK1-NEXT: [[NN:%.*]] = alloca i32, align 4 // CHECK1-NEXT: [[NN_CASTED:%.*]] = alloca i64, align 8 -// CHECK1-NEXT: [[DOTOFFLOAD_BASEPTRS27:%.*]] = alloca [1 x ptr], align 8 -// CHECK1-NEXT: [[DOTOFFLOAD_PTRS28:%.*]] = alloca [1 x ptr], align 8 -// CHECK1-NEXT: [[DOTOFFLOAD_MAPPERS29:%.*]] = alloca [1 x ptr], align 8 -// CHECK1-NEXT: [[KERNEL_ARGS30:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 -// CHECK1-NEXT: [[NN_CASTED33:%.*]] = alloca i64, align 8 -// CHECK1-NEXT: [[DOTOFFLOAD_BASEPTRS34:%.*]] = alloca [1 x ptr], align 8 -// CHECK1-NEXT: [[DOTOFFLOAD_PTRS35:%.*]] = alloca [1 x ptr], align 8 -// CHECK1-NEXT: [[DOTOFFLOAD_MAPPERS36:%.*]] = alloca [1 x ptr], align 8 -// CHECK1-NEXT: [[KERNEL_ARGS37:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 +// CHECK1-NEXT: [[DOTOFFLOAD_BASEPTRS35:%.*]] = alloca [1 x ptr], align 8 +// CHECK1-NEXT: [[DOTOFFLOAD_PTRS36:%.*]] = alloca [1 x ptr], align 8 +// CHECK1-NEXT: [[DOTOFFLOAD_MAPPERS37:%.*]] = alloca [1 x ptr], align 8 +// CHECK1-NEXT: [[KERNEL_ARGS38:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 +// CHECK1-NEXT: [[NN_CASTED41:%.*]] = alloca i64, align 8 +// CHECK1-NEXT: [[DOTOFFLOAD_BASEPTRS42:%.*]] = alloca [1 x ptr], align 8 +// CHECK1-NEXT: [[DOTOFFLOAD_PTRS43:%.*]] = alloca [1 x ptr], align 8 +// CHECK1-NEXT: [[DOTOFFLOAD_MAPPERS44:%.*]] = alloca [1 x ptr], align 8 +// CHECK1-NEXT: [[KERNEL_ARGS45:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 // CHECK1-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1:[0-9]+]]) // CHECK1-NEXT: store i32 [[N]], ptr [[N_ADDR]], align 4 // CHECK1-NEXT: store i32 0, ptr [[A]], align 4 @@ -538,206 +550,259 @@ int bar(int n){ // CHECK1-NEXT: [[TMP95:%.*]] = load i32, ptr [[A]], align 4 // CHECK1-NEXT: store i32 [[TMP95]], ptr [[A_CASTED16]], align 4 // CHECK1-NEXT: [[TMP96:%.*]] = load i64, ptr [[A_CASTED16]], align 8 -// CHECK1-NEXT: [[TMP97:%.*]] = load i32, ptr [[N_ADDR]], align 4 -// CHECK1-NEXT: [[CMP17:%.*]] = icmp sgt i32 [[TMP97]], 20 -// CHECK1-NEXT: br i1 [[CMP17]], label [[OMP_IF_THEN18:%.*]], label [[OMP_IF_ELSE25:%.*]] -// CHECK1: omp_if.then18: -// CHECK1-NEXT: [[TMP98:%.*]] = mul nuw i64 [[TMP2]], 4 -// CHECK1-NEXT: [[TMP99:%.*]] = mul nuw i64 5, [[TMP5]] -// CHECK1-NEXT: [[TMP100:%.*]] = mul nuw i64 [[TMP99]], 8 -// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[DOTOFFLOAD_SIZES]], ptr align 8 @.offload_sizes.5, i64 72, i1 false) -// CHECK1-NEXT: [[TMP101:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 0 -// CHECK1-NEXT: store i64 [[TMP96]], ptr [[TMP101]], align 8 -// CHECK1-NEXT: [[TMP102:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 0 -// CHECK1-NEXT: store i64 [[TMP96]], ptr [[TMP102]], align 8 -// CHECK1-NEXT: [[TMP103:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i64 0, i64 0 -// CHECK1-NEXT: store ptr null, ptr [[TMP103]], align 8 -// CHECK1-NEXT: [[TMP104:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 1 -// CHECK1-NEXT: store ptr [[B]], ptr [[TMP104]], align 8 -// CHECK1-NEXT: [[TMP105:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 1 -// CHECK1-NEXT: store ptr [[B]], ptr [[TMP105]], align 8 -// CHECK1-NEXT: [[TMP106:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i64 0, i64 1 -// CHECK1-NEXT: store ptr null, ptr [[TMP106]], align 8 -// CHECK1-NEXT: [[TMP107:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 2 -// CHECK1-NEXT: store i64 [[TMP2]], ptr [[TMP107]], align 8 -// CHECK1-NEXT: [[TMP108:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 2 -// CHECK1-NEXT: store i64 [[TMP2]], ptr [[TMP108]], align 8 -// CHECK1-NEXT: [[TMP109:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i64 0, i64 2 -// CHECK1-NEXT: store ptr null, ptr [[TMP109]], align 8 -// CHECK1-NEXT: [[TMP110:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 3 -// CHECK1-NEXT: store ptr [[VLA]], ptr [[TMP110]], align 8 -// CHECK1-NEXT: [[TMP111:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 3 -// CHECK1-NEXT: store ptr [[VLA]], ptr [[TMP111]], align 8 -// CHECK1-NEXT: [[TMP112:%.*]] = getelementptr inbounds [9 x i64], ptr [[DOTOFFLOAD_SIZES]], i32 0, i32 3 -// CHECK1-NEXT: store i64 [[TMP98]], ptr [[TMP112]], align 8 -// CHECK1-NEXT: [[TMP113:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i64 0, i64 3 +// CHECK1-NEXT: [[TMP97:%.*]] = load i16, ptr [[AA]], align 2 +// CHECK1-NEXT: store i16 [[TMP97]], ptr [[AA_CASTED17]], align 2 +// CHECK1-NEXT: [[TMP98:%.*]] = load i64, ptr [[AA_CASTED17]], align 8 +// CHECK1-NEXT: [[TMP99:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_BASEPTRS18]], i32 0, i32 0 +// CHECK1-NEXT: store i64 [[TMP96]], ptr [[TMP99]], align 8 +// CHECK1-NEXT: [[TMP100:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_PTRS19]], i32 0, i32 0 +// CHECK1-NEXT: store i64 [[TMP96]], ptr [[TMP100]], align 8 +// CHECK1-NEXT: [[TMP101:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_MAPPERS20]], i64 0, i64 0 +// CHECK1-NEXT: store ptr null, ptr [[TMP101]], align 8 +// CHECK1-NEXT: [[TMP102:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_BASEPTRS18]], i32 0, i32 1 +// CHECK1-NEXT: store i64 [[TMP98]], ptr [[TMP102]], align 8 +// CHECK1-NEXT: [[TMP103:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_PTRS19]], i32 0, i32 1 +// CHECK1-NEXT: store i64 [[TMP98]], ptr [[TMP103]], align 8 +// CHECK1-NEXT: [[TMP104:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_MAPPERS20]], i64 0, i64 1 +// CHECK1-NEXT: store ptr null, ptr [[TMP104]], align 8 +// CHECK1-NEXT: [[TMP105:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_BASEPTRS18]], i32 0, i32 0 +// CHECK1-NEXT: [[TMP106:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_PTRS19]], i32 0, i32 0 +// CHECK1-NEXT: [[TMP107:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 0 +// CHECK1-NEXT: store i32 2, ptr [[TMP107]], align 4 +// CHECK1-NEXT: [[TMP108:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 1 +// CHECK1-NEXT: store i32 2, ptr [[TMP108]], align 4 +// CHECK1-NEXT: [[TMP109:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 2 +// CHECK1-NEXT: store ptr [[TMP105]], ptr [[TMP109]], align 8 +// CHECK1-NEXT: [[TMP110:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 3 +// CHECK1-NEXT: store ptr [[TMP106]], ptr [[TMP110]], align 8 +// CHECK1-NEXT: [[TMP111:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 4 +// CHECK1-NEXT: store ptr @.offload_sizes.5, ptr [[TMP111]], align 8 +// CHECK1-NEXT: [[TMP112:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 5 +// CHECK1-NEXT: store ptr @.offload_maptypes.6, ptr [[TMP112]], align 8 +// CHECK1-NEXT: [[TMP113:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 6 // CHECK1-NEXT: store ptr null, ptr [[TMP113]], align 8 -// CHECK1-NEXT: [[TMP114:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 4 -// CHECK1-NEXT: store ptr [[C]], ptr [[TMP114]], align 8 -// CHECK1-NEXT: [[TMP115:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 4 -// CHECK1-NEXT: store ptr [[C]], ptr [[TMP115]], align 8 -// CHECK1-NEXT: [[TMP116:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i64 0, i64 4 -// CHECK1-NEXT: store ptr null, ptr [[TMP116]], align 8 -// CHECK1-NEXT: [[TMP117:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 5 -// CHECK1-NEXT: store i64 5, ptr [[TMP117]], align 8 -// CHECK1-NEXT: [[TMP118:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 5 -// CHECK1-NEXT: store i64 5, ptr [[TMP118]], align 8 -// CHECK1-NEXT: [[TMP119:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i64 0, i64 5 -// CHECK1-NEXT: store ptr null, ptr [[TMP119]], align 8 -// CHECK1-NEXT: [[TMP120:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 6 -// CHECK1-NEXT: store i64 [[TMP5]], ptr [[TMP120]], align 8 -// CHECK1-NEXT: [[TMP121:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 6 -// CHECK1-NEXT: store i64 [[TMP5]], ptr [[TMP121]], align 8 -// CHECK1-NEXT: [[TMP122:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i64 0, i64 6 -// CHECK1-NEXT: store ptr null, ptr [[TMP122]], align 8 -// CHECK1-NEXT: [[TMP123:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 7 -// CHECK1-NEXT: store ptr [[VLA1]], ptr [[TMP123]], align 8 -// CHECK1-NEXT: [[TMP124:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 7 -// CHECK1-NEXT: store ptr [[VLA1]], ptr [[TMP124]], align 8 -// CHECK1-NEXT: [[TMP125:%.*]] = getelementptr inbounds [9 x i64], ptr [[DOTOFFLOAD_SIZES]], i32 0, i32 7 -// CHECK1-NEXT: store i64 [[TMP100]], ptr [[TMP125]], align 8 -// CHECK1-NEXT: [[TMP126:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i64 0, i64 7 -// CHECK1-NEXT: store ptr null, ptr [[TMP126]], align 8 -// CHECK1-NEXT: [[TMP127:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 8 -// CHECK1-NEXT: store ptr [[D]], ptr [[TMP127]], align 8 -// CHECK1-NEXT: [[TMP128:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 8 -// CHECK1-NEXT: store ptr [[D]], ptr [[TMP128]], align 8 -// CHECK1-NEXT: [[TMP129:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i64 0, i64 8 -// CHECK1-NEXT: store ptr null, ptr [[TMP129]], align 8 -// CHECK1-NEXT: [[TMP130:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP131:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP132:%.*]] = getelementptr inbounds [9 x i64], ptr [[DOTOFFLOAD_SIZES]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP133:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 0 -// CHECK1-NEXT: store i32 2, ptr [[TMP133]], align 4 -// CHECK1-NEXT: [[TMP134:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 1 -// CHECK1-NEXT: store i32 9, ptr [[TMP134]], align 4 -// CHECK1-NEXT: [[TMP135:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 2 -// CHECK1-NEXT: store ptr [[TMP130]], ptr [[TMP135]], align 8 -// CHECK1-NEXT: [[TMP136:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 3 -// CHECK1-NEXT: store ptr [[TMP131]], ptr [[TMP136]], align 8 -// CHECK1-NEXT: [[TMP137:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 4 -// CHECK1-NEXT: store ptr [[TMP132]], ptr [[TMP137]], align 8 -// CHECK1-NEXT: [[TMP138:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 5 -// CHECK1-NEXT: store ptr @.offload_maptypes.6, ptr [[TMP138]], align 8 -// CHECK1-NEXT: [[TMP139:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 6 -// CHECK1-NEXT: store ptr null, ptr [[TMP139]], align 8 -// CHECK1-NEXT: [[TMP140:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 7 +// CHECK1-NEXT: [[TMP114:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 7 +// CHECK1-NEXT: store ptr null, ptr [[TMP114]], align 8 +// CHECK1-NEXT: [[TMP115:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 8 +// CHECK1-NEXT: store i64 0, ptr [[TMP115]], align 8 +// CHECK1-NEXT: [[TMP116:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 9 +// CHECK1-NEXT: store i64 0, ptr [[TMP116]], align 8 +// CHECK1-NEXT: [[TMP117:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 10 +// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP117]], align 4 +// CHECK1-NEXT: [[TMP118:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 11 +// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP118]], align 4 +// CHECK1-NEXT: [[TMP119:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 12 +// CHECK1-NEXT: store i32 0, ptr [[TMP119]], align 4 +// CHECK1-NEXT: [[TMP120:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124.region_id, ptr [[KERNEL_ARGS21]]) +// CHECK1-NEXT: [[TMP121:%.*]] = icmp ne i32 [[TMP120]], 0 +// CHECK1-NEXT: br i1 [[TMP121]], label [[OMP_OFFLOAD_FAILED22:%.*]], label [[OMP_OFFLOAD_CONT23:%.*]] +// CHECK1: omp_offload.failed22: +// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124(i64 [[TMP96]], i64 [[TMP98]]) #[[ATTR3]] +// CHECK1-NEXT: br label [[OMP_OFFLOAD_CONT23]] +// CHECK1: omp_offload.cont23: +// CHECK1-NEXT: [[TMP122:%.*]] = load i32, ptr [[A]], align 4 +// CHECK1-NEXT: store i32 [[TMP122]], ptr [[A_CASTED24]], align 4 +// CHECK1-NEXT: [[TMP123:%.*]] = load i64, ptr [[A_CASTED24]], align 8 +// CHECK1-NEXT: [[TMP124:%.*]] = load i32, ptr [[N_ADDR]], align 4 +// CHECK1-NEXT: [[CMP25:%.*]] = icmp sgt i32 [[TMP124]], 20 +// CHECK1-NEXT: br i1 [[CMP25]], label [[OMP_IF_THEN26:%.*]], label [[OMP_IF_ELSE33:%.*]] +// CHECK1: omp_if.then26: +// CHECK1-NEXT: [[TMP125:%.*]] = mul nuw i64 [[TMP2]], 4 +// CHECK1-NEXT: [[TMP126:%.*]] = mul nuw i64 5, [[TMP5]] +// CHECK1-NEXT: [[TMP127:%.*]] = mul nuw i64 [[TMP126]], 8 +// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[DOTOFFLOAD_SIZES]], ptr align 8 @.offload_sizes.7, i64 72, i1 false) +// CHECK1-NEXT: [[TMP128:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 0 +// CHECK1-NEXT: store i64 [[TMP123]], ptr [[TMP128]], align 8 +// CHECK1-NEXT: [[TMP129:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 0 +// CHECK1-NEXT: store i64 [[TMP123]], ptr [[TMP129]], align 8 +// CHECK1-NEXT: [[TMP130:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i64 0, i64 0 +// CHECK1-NEXT: store ptr null, ptr [[TMP130]], align 8 +// CHECK1-NEXT: [[TMP131:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 1 +// CHECK1-NEXT: store ptr [[B]], ptr [[TMP131]], align 8 +// CHECK1-NEXT: [[TMP132:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 1 +// CHECK1-NEXT: store ptr [[B]], ptr [[TMP132]], align 8 +// CHECK1-NEXT: [[TMP133:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i64 0, i64 1 +// CHECK1-NEXT: store ptr null, ptr [[TMP133]], align 8 +// CHECK1-NEXT: [[TMP134:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 2 +// CHECK1-NEXT: store i64 [[TMP2]], ptr [[TMP134]], align 8 +// CHECK1-NEXT: [[TMP135:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 2 +// CHECK1-NEXT: store i64 [[TMP2]], ptr [[TMP135]], align 8 +// CHECK1-NEXT: [[TMP136:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i64 0, i64 2 +// CHECK1-NEXT: store ptr null, ptr [[TMP136]], align 8 +// CHECK1-NEXT: [[TMP137:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 3 +// CHECK1-NEXT: store ptr [[VLA]], ptr [[TMP137]], align 8 +// CHECK1-NEXT: [[TMP138:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 3 +// CHECK1-NEXT: store ptr [[VLA]], ptr [[TMP138]], align 8 +// CHECK1-NEXT: [[TMP139:%.*]] = getelementptr inbounds [9 x i64], ptr [[DOTOFFLOAD_SIZES]], i32 0, i32 3 +// CHECK1-NEXT: store i64 [[TMP125]], ptr [[TMP139]], align 8 +// CHECK1-NEXT: [[TMP140:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i64 0, i64 3 // CHECK1-NEXT: store ptr null, ptr [[TMP140]], align 8 -// CHECK1-NEXT: [[TMP141:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 8 -// CHECK1-NEXT: store i64 0, ptr [[TMP141]], align 8 -// CHECK1-NEXT: [[TMP142:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 9 -// CHECK1-NEXT: store i64 0, ptr [[TMP142]], align 8 -// CHECK1-NEXT: [[TMP143:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 10 -// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP143]], align 4 -// CHECK1-NEXT: [[TMP144:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 11 -// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP144]], align 4 -// CHECK1-NEXT: [[TMP145:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 12 -// CHECK1-NEXT: store i32 0, ptr [[TMP145]], align 4 -// CHECK1-NEXT: [[TMP146:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142.region_id, ptr [[KERNEL_ARGS22]]) -// CHECK1-NEXT: [[TMP147:%.*]] = icmp ne i32 [[TMP146]], 0 -// CHECK1-NEXT: br i1 [[TMP147]], label [[OMP_OFFLOAD_FAILED23:%.*]], label [[OMP_OFFLOAD_CONT24:%.*]] -// CHECK1: omp_offload.failed23: -// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142(i64 [[TMP96]], ptr [[B]], i64 [[TMP2]], ptr [[VLA]], ptr [[C]], i64 5, i64 [[TMP5]], ptr [[VLA1]], ptr [[D]]) #[[ATTR3]] -// CHECK1-NEXT: br label [[OMP_OFFLOAD_CONT24]] -// CHECK1: omp_offload.cont24: -// CHECK1-NEXT: br label [[OMP_IF_END26:%.*]] -// CHECK1: omp_if.else25: -// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142(i64 [[TMP96]], ptr [[B]], i64 [[TMP2]], ptr [[VLA]], ptr [[C]], i64 5, i64 [[TMP5]], ptr [[VLA1]], ptr [[D]]) #[[ATTR3]] -// CHECK1-NEXT: br label [[OMP_IF_END26]] -// CHECK1: omp_if.end26: -// CHECK1-NEXT: store i32 0, ptr [[NN]], align 4 -// CHECK1-NEXT: [[TMP148:%.*]] = load i32, ptr [[NN]], align 4 -// CHECK1-NEXT: store i32 [[TMP148]], ptr [[NN_CASTED]], align 4 -// CHECK1-NEXT: [[TMP149:%.*]] = load i64, ptr [[NN_CASTED]], align 8 -// CHECK1-NEXT: [[TMP150:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 0 -// CHECK1-NEXT: store i64 [[TMP149]], ptr [[TMP150]], align 8 -// CHECK1-NEXT: [[TMP151:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 0 -// CHECK1-NEXT: store i64 [[TMP149]], ptr [[TMP151]], align 8 -// CHECK1-NEXT: [[TMP152:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i64 0, i64 0 -// CHECK1-NEXT: store ptr null, ptr [[TMP152]], align 8 -// CHECK1-NEXT: [[TMP153:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP154:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP155:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 0 -// CHECK1-NEXT: store i32 2, ptr [[TMP155]], align 4 -// CHECK1-NEXT: [[TMP156:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 1 -// CHECK1-NEXT: store i32 1, ptr [[TMP156]], align 4 -// CHECK1-NEXT: [[TMP157:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 2 -// CHECK1-NEXT: store ptr [[TMP153]], ptr [[TMP157]], align 8 -// CHECK1-NEXT: [[TMP158:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 3 -// CHECK1-NEXT: store ptr [[TMP154]], ptr [[TMP158]], align 8 -// CHECK1-NEXT: [[TMP159:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 4 -// CHECK1-NEXT: store ptr @.offload_sizes.7, ptr [[TMP159]], align 8 -// CHECK1-NEXT: [[TMP160:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 5 -// CHECK1-NEXT: store ptr @.offload_maptypes.8, ptr [[TMP160]], align 8 -// CHECK1-NEXT: [[TMP161:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 6 -// CHECK1-NEXT: store ptr null, ptr [[TMP161]], align 8 -// CHECK1-NEXT: [[TMP162:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 7 -// CHECK1-NEXT: store ptr null, ptr [[TMP162]], align 8 -// CHECK1-NEXT: [[TMP163:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 8 -// CHECK1-NEXT: store i64 0, ptr [[TMP163]], align 8 -// CHECK1-NEXT: [[TMP164:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 9 -// CHECK1-NEXT: store i64 0, ptr [[TMP164]], align 8 -// CHECK1-NEXT: [[TMP165:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 10 -// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP165]], align 4 -// CHECK1-NEXT: [[TMP166:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 11 -// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP166]], align 4 -// CHECK1-NEXT: [[TMP167:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 12 -// CHECK1-NEXT: store i32 0, ptr [[TMP167]], align 4 -// CHECK1-NEXT: [[TMP168:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.region_id, ptr [[KERNEL_ARGS30]]) -// CHECK1-NEXT: [[TMP169:%.*]] = icmp ne i32 [[TMP168]], 0 -// CHECK1-NEXT: br i1 [[TMP169]], label [[OMP_OFFLOAD_FAILED31:%.*]], label [[OMP_OFFLOAD_CONT32:%.*]] +// CHECK1-NEXT: [[TMP141:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 4 +// CHECK1-NEXT: store ptr [[C]], ptr [[TMP141]], align 8 +// CHECK1-NEXT: [[TMP142:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 4 +// CHECK1-NEXT: store ptr [[C]], ptr [[TMP142]], align 8 +// CHECK1-NEXT: [[TMP143:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i64 0, i64 4 +// CHECK1-NEXT: store ptr null, ptr [[TMP143]], align 8 +// CHECK1-NEXT: [[TMP144:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 5 +// CHECK1-NEXT: store i64 5, ptr [[TMP144]], align 8 +// CHECK1-NEXT: [[TMP145:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 5 +// CHECK1-NEXT: store i64 5, ptr [[TMP145]], align 8 +// CHECK1-NEXT: [[TMP146:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i64 0, i64 5 +// CHECK1-NEXT: store ptr null, ptr [[TMP146]], align 8 +// CHECK1-NEXT: [[TMP147:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 6 +// CHECK1-NEXT: store i64 [[TMP5]], ptr [[TMP147]], align 8 +// CHECK1-NEXT: [[TMP148:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 6 +// CHECK1-NEXT: store i64 [[TMP5]], ptr [[TMP148]], align 8 +// CHECK1-NEXT: [[TMP149:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i64 0, i64 6 +// CHECK1-NEXT: store ptr null, ptr [[TMP149]], align 8 +// CHECK1-NEXT: [[TMP150:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 7 +// CHECK1-NEXT: store ptr [[VLA1]], ptr [[TMP150]], align 8 +// CHECK1-NEXT: [[TMP151:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 7 +// CHECK1-NEXT: store ptr [[VLA1]], ptr [[TMP151]], align 8 +// CHECK1-NEXT: [[TMP152:%.*]] = getelementptr inbounds [9 x i64], ptr [[DOTOFFLOAD_SIZES]], i32 0, i32 7 +// CHECK1-NEXT: store i64 [[TMP127]], ptr [[TMP152]], align 8 +// CHECK1-NEXT: [[TMP153:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i64 0, i64 7 +// CHECK1-NEXT: store ptr null, ptr [[TMP153]], align 8 +// CHECK1-NEXT: [[TMP154:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 8 +// CHECK1-NEXT: store ptr [[D]], ptr [[TMP154]], align 8 +// CHECK1-NEXT: [[TMP155:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 8 +// CHECK1-NEXT: store ptr [[D]], ptr [[TMP155]], align 8 +// CHECK1-NEXT: [[TMP156:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i64 0, i64 8 +// CHECK1-NEXT: store ptr null, ptr [[TMP156]], align 8 +// CHECK1-NEXT: [[TMP157:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 0 +// CHECK1-NEXT: [[TMP158:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 0 +// CHECK1-NEXT: [[TMP159:%.*]] = getelementptr inbounds [9 x i64], ptr [[DOTOFFLOAD_SIZES]], i32 0, i32 0 +// CHECK1-NEXT: [[TMP160:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 0 +// CHECK1-NEXT: store i32 2, ptr [[TMP160]], align 4 +// CHECK1-NEXT: [[TMP161:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 1 +// CHECK1-NEXT: store i32 9, ptr [[TMP161]], align 4 +// CHECK1-NEXT: [[TMP162:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 2 +// CHECK1-NEXT: store ptr [[TMP157]], ptr [[TMP162]], align 8 +// CHECK1-NEXT: [[TMP163:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 3 +// CHECK1-NEXT: store ptr [[TMP158]], ptr [[TMP163]], align 8 +// CHECK1-NEXT: [[TMP164:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 4 +// CHECK1-NEXT: store ptr [[TMP159]], ptr [[TMP164]], align 8 +// CHECK1-NEXT: [[TMP165:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 5 +// CHECK1-NEXT: store ptr @.offload_maptypes.8, ptr [[TMP165]], align 8 +// CHECK1-NEXT: [[TMP166:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 6 +// CHECK1-NEXT: store ptr null, ptr [[TMP166]], align 8 +// CHECK1-NEXT: [[TMP167:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 7 +// CHECK1-NEXT: store ptr null, ptr [[TMP167]], align 8 +// CHECK1-NEXT: [[TMP168:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 8 +// CHECK1-NEXT: store i64 0, ptr [[TMP168]], align 8 +// CHECK1-NEXT: [[TMP169:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 9 +// CHECK1-NEXT: store i64 0, ptr [[TMP169]], align 8 +// CHECK1-NEXT: [[TMP170:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 10 +// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP170]], align 4 +// CHECK1-NEXT: [[TMP171:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 11 +// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP171]], align 4 +// CHECK1-NEXT: [[TMP172:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 12 +// CHECK1-NEXT: store i32 0, ptr [[TMP172]], align 4 +// CHECK1-NEXT: [[TMP173:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148.region_id, ptr [[KERNEL_ARGS30]]) +// CHECK1-NEXT: [[TMP174:%.*]] = icmp ne i32 [[TMP173]], 0 +// CHECK1-NEXT: br i1 [[TMP174]], label [[OMP_OFFLOAD_FAILED31:%.*]], label [[OMP_OFFLOAD_CONT32:%.*]] // CHECK1: omp_offload.failed31: -// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154(i64 [[TMP149]]) #[[ATTR3]] +// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148(i64 [[TMP123]], ptr [[B]], i64 [[TMP2]], ptr [[VLA]], ptr [[C]], i64 5, i64 [[TMP5]], ptr [[VLA1]], ptr [[D]]) #[[ATTR3]] // CHECK1-NEXT: br label [[OMP_OFFLOAD_CONT32]] // CHECK1: omp_offload.cont32: -// CHECK1-NEXT: [[TMP170:%.*]] = load i32, ptr [[NN]], align 4 -// CHECK1-NEXT: store i32 [[TMP170]], ptr [[NN_CASTED33]], align 4 -// CHECK1-NEXT: [[TMP171:%.*]] = load i64, ptr [[NN_CASTED33]], align 8 -// CHECK1-NEXT: [[TMP172:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS34]], i32 0, i32 0 -// CHECK1-NEXT: store i64 [[TMP171]], ptr [[TMP172]], align 8 -// CHECK1-NEXT: [[TMP173:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS35]], i32 0, i32 0 -// CHECK1-NEXT: store i64 [[TMP171]], ptr [[TMP173]], align 8 -// CHECK1-NEXT: [[TMP174:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_MAPPERS36]], i64 0, i64 0 -// CHECK1-NEXT: store ptr null, ptr [[TMP174]], align 8 -// CHECK1-NEXT: [[TMP175:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS34]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP176:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS35]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP177:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 0 -// CHECK1-NEXT: store i32 2, ptr [[TMP177]], align 4 -// CHECK1-NEXT: [[TMP178:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 1 -// CHECK1-NEXT: store i32 1, ptr [[TMP178]], align 4 -// CHECK1-NEXT: [[TMP179:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 2 -// CHECK1-NEXT: store ptr [[TMP175]], ptr [[TMP179]], align 8 -// CHECK1-NEXT: [[TMP180:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 3 -// CHECK1-NEXT: store ptr [[TMP176]], ptr [[TMP180]], align 8 -// CHECK1-NEXT: [[TMP181:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 4 -// CHECK1-NEXT: store ptr @.offload_sizes.9, ptr [[TMP181]], align 8 -// CHECK1-NEXT: [[TMP182:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 5 -// CHECK1-NEXT: store ptr @.offload_maptypes.10, ptr [[TMP182]], align 8 -// CHECK1-NEXT: [[TMP183:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 6 -// CHECK1-NEXT: store ptr null, ptr [[TMP183]], align 8 -// CHECK1-NEXT: [[TMP184:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 7 -// CHECK1-NEXT: store ptr null, ptr [[TMP184]], align 8 -// CHECK1-NEXT: [[TMP185:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 8 -// CHECK1-NEXT: store i64 0, ptr [[TMP185]], align 8 -// CHECK1-NEXT: [[TMP186:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 9 -// CHECK1-NEXT: store i64 0, ptr [[TMP186]], align 8 -// CHECK1-NEXT: [[TMP187:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 10 -// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP187]], align 4 -// CHECK1-NEXT: [[TMP188:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 11 -// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP188]], align 4 -// CHECK1-NEXT: [[TMP189:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 12 -// CHECK1-NEXT: store i32 0, ptr [[TMP189]], align 4 -// CHECK1-NEXT: [[TMP190:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.region_id, ptr [[KERNEL_ARGS37]]) -// CHECK1-NEXT: [[TMP191:%.*]] = icmp ne i32 [[TMP190]], 0 -// CHECK1-NEXT: br i1 [[TMP191]], label [[OMP_OFFLOAD_FAILED38:%.*]], label [[OMP_OFFLOAD_CONT39:%.*]] -// CHECK1: omp_offload.failed38: -// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157(i64 [[TMP171]]) #[[ATTR3]] -// CHECK1-NEXT: br label [[OMP_OFFLOAD_CONT39]] -// CHECK1: omp_offload.cont39: -// CHECK1-NEXT: [[TMP192:%.*]] = load i32, ptr [[A]], align 4 -// CHECK1-NEXT: [[TMP193:%.*]] = load ptr, ptr [[SAVED_STACK]], align 8 -// CHECK1-NEXT: call void @llvm.stackrestore.p0(ptr [[TMP193]]) -// CHECK1-NEXT: ret i32 [[TMP192]] +// CHECK1-NEXT: br label [[OMP_IF_END34:%.*]] +// CHECK1: omp_if.else33: +// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148(i64 [[TMP123]], ptr [[B]], i64 [[TMP2]], ptr [[VLA]], ptr [[C]], i64 5, i64 [[TMP5]], ptr [[VLA1]], ptr [[D]]) #[[ATTR3]] +// CHECK1-NEXT: br label [[OMP_IF_END34]] +// CHECK1: omp_if.end34: +// CHECK1-NEXT: store i32 0, ptr [[NN]], align 4 +// CHECK1-NEXT: [[TMP175:%.*]] = load i32, ptr [[NN]], align 4 +// CHECK1-NEXT: store i32 [[TMP175]], ptr [[NN_CASTED]], align 4 +// CHECK1-NEXT: [[TMP176:%.*]] = load i64, ptr [[NN_CASTED]], align 8 +// CHECK1-NEXT: [[TMP177:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS35]], i32 0, i32 0 +// CHECK1-NEXT: store i64 [[TMP176]], ptr [[TMP177]], align 8 +// CHECK1-NEXT: [[TMP178:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS36]], i32 0, i32 0 +// CHECK1-NEXT: store i64 [[TMP176]], ptr [[TMP178]], align 8 +// CHECK1-NEXT: [[TMP179:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_MAPPERS37]], i64 0, i64 0 +// CHECK1-NEXT: store ptr null, ptr [[TMP179]], align 8 +// CHECK1-NEXT: [[TMP180:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS35]], i32 0, i32 0 +// CHECK1-NEXT: [[TMP181:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS36]], i32 0, i32 0 +// CHECK1-NEXT: [[TMP182:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 0 +// CHECK1-NEXT: store i32 2, ptr [[TMP182]], align 4 +// CHECK1-NEXT: [[TMP183:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 1 +// CHECK1-NEXT: store i32 1, ptr [[TMP183]], align 4 +// CHECK1-NEXT: [[TMP184:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 2 +// CHECK1-NEXT: store ptr [[TMP180]], ptr [[TMP184]], align 8 +// CHECK1-NEXT: [[TMP185:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 3 +// CHECK1-NEXT: store ptr [[TMP181]], ptr [[TMP185]], align 8 +// CHECK1-NEXT: [[TMP186:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 4 +// CHECK1-NEXT: store ptr @.offload_sizes.9, ptr [[TMP186]], align 8 +// CHECK1-NEXT: [[TMP187:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 5 +// CHECK1-NEXT: store ptr @.offload_maptypes.10, ptr [[TMP187]], align 8 +// CHECK1-NEXT: [[TMP188:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 6 +// CHECK1-NEXT: store ptr null, ptr [[TMP188]], align 8 +// CHECK1-NEXT: [[TMP189:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 7 +// CHECK1-NEXT: store ptr null, ptr [[TMP189]], align 8 +// CHECK1-NEXT: [[TMP190:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 8 +// CHECK1-NEXT: store i64 0, ptr [[TMP190]], align 8 +// CHECK1-NEXT: [[TMP191:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 9 +// CHECK1-NEXT: store i64 0, ptr [[TMP191]], align 8 +// CHECK1-NEXT: [[TMP192:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 10 +// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP192]], align 4 +// CHECK1-NEXT: [[TMP193:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 11 +// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP193]], align 4 +// CHECK1-NEXT: [[TMP194:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 12 +// CHECK1-NEXT: store i32 0, ptr [[TMP194]], align 4 +// CHECK1-NEXT: [[TMP195:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.region_id, ptr [[KERNEL_ARGS38]]) +// CHECK1-NEXT: [[TMP196:%.*]] = icmp ne i32 [[TMP195]], 0 +// CHECK1-NEXT: br i1 [[TMP196]], label [[OMP_OFFLOAD_FAILED39:%.*]], label [[OMP_OFFLOAD_CONT40:%.*]] +// CHECK1: omp_offload.failed39: +// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160(i64 [[TMP176]]) #[[ATTR3]] +// CHECK1-NEXT: br label [[OMP_OFFLOAD_CONT40]] +// CHECK1: omp_offload.cont40: +// CHECK1-NEXT: [[TMP197:%.*]] = load i32, ptr [[NN]], align 4 +// CHECK1-NEXT: store i32 [[TMP197]], ptr [[NN_CASTED41]], align 4 +// CHECK1-NEXT: [[TMP198:%.*]] = load i64, ptr [[NN_CASTED41]], align 8 +// CHECK1-NEXT: [[TMP199:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS42]], i32 0, i32 0 +// CHECK1-NEXT: store i64 [[TMP198]], ptr [[TMP199]], align 8 +// CHECK1-NEXT: [[TMP200:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS43]], i32 0, i32 0 +// CHECK1-NEXT: store i64 [[TMP198]], ptr [[TMP200]], align 8 +// CHECK1-NEXT: [[TMP201:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_MAPPERS44]], i64 0, i64 0 +// CHECK1-NEXT: store ptr null, ptr [[TMP201]], align 8 +// CHECK1-NEXT: [[TMP202:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS42]], i32 0, i32 0 +// CHECK1-NEXT: [[TMP203:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS43]], i32 0, i32 0 +// CHECK1-NEXT: [[TMP204:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 0 +// CHECK1-NEXT: store i32 2, ptr [[TMP204]], align 4 +// CHECK1-NEXT: [[TMP205:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 1 +// CHECK1-NEXT: store i32 1, ptr [[TMP205]], align 4 +// CHECK1-NEXT: [[TMP206:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 2 +// CHECK1-NEXT: store ptr [[TMP202]], ptr [[TMP206]], align 8 +// CHECK1-NEXT: [[TMP207:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 3 +// CHECK1-NEXT: store ptr [[TMP203]], ptr [[TMP207]], align 8 +// CHECK1-NEXT: [[TMP208:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 4 +// CHECK1-NEXT: store ptr @.offload_sizes.11, ptr [[TMP208]], align 8 +// CHECK1-NEXT: [[TMP209:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 5 +// CHECK1-NEXT: store ptr @.offload_maptypes.12, ptr [[TMP209]], align 8 +// CHECK1-NEXT: [[TMP210:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 6 +// CHECK1-NEXT: store ptr null, ptr [[TMP210]], align 8 +// CHECK1-NEXT: [[TMP211:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 7 +// CHECK1-NEXT: store ptr null, ptr [[TMP211]], align 8 +// CHECK1-NEXT: [[TMP212:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 8 +// CHECK1-NEXT: store i64 0, ptr [[TMP212]], align 8 +// CHECK1-NEXT: [[TMP213:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 9 +// CHECK1-NEXT: store i64 0, ptr [[TMP213]], align 8 +// CHECK1-NEXT: [[TMP214:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 10 +// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP214]], align 4 +// CHECK1-NEXT: [[TMP215:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 11 +// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP215]], align 4 +// CHECK1-NEXT: [[TMP216:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 12 +// CHECK1-NEXT: store i32 0, ptr [[TMP216]], align 4 +// CHECK1-NEXT: [[TMP217:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.region_id, ptr [[KERNEL_ARGS45]]) +// CHECK1-NEXT: [[TMP218:%.*]] = icmp ne i32 [[TMP217]], 0 +// CHECK1-NEXT: br i1 [[TMP218]], label [[OMP_OFFLOAD_FAILED46:%.*]], label [[OMP_OFFLOAD_CONT47:%.*]] +// CHECK1: omp_offload.failed46: +// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163(i64 [[TMP198]]) #[[ATTR3]] +// CHECK1-NEXT: br label [[OMP_OFFLOAD_CONT47]] +// CHECK1: omp_offload.cont47: +// CHECK1-NEXT: [[TMP219:%.*]] = load i32, ptr [[A]], align 4 +// CHECK1-NEXT: [[TMP220:%.*]] = load ptr, ptr [[SAVED_STACK]], align 8 +// CHECK1-NEXT: call void @llvm.stackrestore.p0(ptr [[TMP220]]) +// CHECK1-NEXT: ret i32 [[TMP219]] // // // CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l101 @@ -830,68 +895,68 @@ int bar(int n){ // CHECK1-NEXT: [[TMP6:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T]], ptr [[TMP4]], i32 0, i32 0 // CHECK1-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 8 // CHECK1-NEXT: [[TMP8:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T_WITH_PRIVATES]], ptr [[TMP3]], i32 0, i32 1 -// CHECK1-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META15:![0-9]+]]) -// CHECK1-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META18:![0-9]+]]) -// CHECK1-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META20:![0-9]+]]) -// CHECK1-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META22:![0-9]+]]) -// CHECK1-NEXT: store i32 [[TMP2]], ptr [[DOTGLOBAL_TID__ADDR_I]], align 4, !noalias !24 -// CHECK1-NEXT: store ptr [[TMP5]], ptr [[DOTPART_ID__ADDR_I]], align 8, !noalias !24 -// CHECK1-NEXT: store ptr [[TMP8]], ptr [[DOTPRIVATES__ADDR_I]], align 8, !noalias !24 -// CHECK1-NEXT: store ptr @.omp_task_privates_map., ptr [[DOTCOPY_FN__ADDR_I]], align 8, !noalias !24 -// CHECK1-NEXT: store ptr [[TMP3]], ptr [[DOTTASK_T__ADDR_I]], align 8, !noalias !24 -// CHECK1-NEXT: store ptr [[TMP7]], ptr [[__CONTEXT_ADDR_I]], align 8, !noalias !24 -// CHECK1-NEXT: [[TMP9:%.*]] = load ptr, ptr [[__CONTEXT_ADDR_I]], align 8, !noalias !24 -// CHECK1-NEXT: [[TMP10:%.*]] = load ptr, ptr [[DOTCOPY_FN__ADDR_I]], align 8, !noalias !24 -// CHECK1-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTPRIVATES__ADDR_I]], align 8, !noalias !24 +// CHECK1-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META16:![0-9]+]]) +// CHECK1-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META19:![0-9]+]]) +// CHECK1-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META21:![0-9]+]]) +// CHECK1-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META23:![0-9]+]]) +// CHECK1-NEXT: store i32 [[TMP2]], ptr [[DOTGLOBAL_TID__ADDR_I]], align 4, !noalias !25 +// CHECK1-NEXT: store ptr [[TMP5]], ptr [[DOTPART_ID__ADDR_I]], align 8, !noalias !25 +// CHECK1-NEXT: store ptr [[TMP8]], ptr [[DOTPRIVATES__ADDR_I]], align 8, !noalias !25 +// CHECK1-NEXT: store ptr @.omp_task_privates_map., ptr [[DOTCOPY_FN__ADDR_I]], align 8, !noalias !25 +// CHECK1-NEXT: store ptr [[TMP3]], ptr [[DOTTASK_T__ADDR_I]], align 8, !noalias !25 +// CHECK1-NEXT: store ptr [[TMP7]], ptr [[__CONTEXT_ADDR_I]], align 8, !noalias !25 +// CHECK1-NEXT: [[TMP9:%.*]] = load ptr, ptr [[__CONTEXT_ADDR_I]], align 8, !noalias !25 +// CHECK1-NEXT: [[TMP10:%.*]] = load ptr, ptr [[DOTCOPY_FN__ADDR_I]], align 8, !noalias !25 +// CHECK1-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTPRIVATES__ADDR_I]], align 8, !noalias !25 // CHECK1-NEXT: call void [[TMP10]](ptr [[TMP11]], ptr [[DOTFIRSTPRIV_PTR_ADDR_I]], ptr [[DOTFIRSTPRIV_PTR_ADDR1_I]], ptr [[DOTFIRSTPRIV_PTR_ADDR2_I]], ptr [[DOTFIRSTPRIV_PTR_ADDR3_I]]) #[[ATTR3]] -// CHECK1-NEXT: [[TMP12:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR_I]], align 8, !noalias !24 -// CHECK1-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR1_I]], align 8, !noalias !24 -// CHECK1-NEXT: [[TMP14:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR2_I]], align 8, !noalias !24 -// CHECK1-NEXT: [[TMP15:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR3_I]], align 8, !noalias !24 +// CHECK1-NEXT: [[TMP12:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR_I]], align 8, !noalias !25 +// CHECK1-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR1_I]], align 8, !noalias !25 +// CHECK1-NEXT: [[TMP14:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR2_I]], align 8, !noalias !25 +// CHECK1-NEXT: [[TMP15:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR3_I]], align 8, !noalias !25 // CHECK1-NEXT: [[TMP16:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], ptr [[TMP9]], i32 0, i32 1 // CHECK1-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT_ANON]], ptr [[TMP9]], i32 0, i32 2 // CHECK1-NEXT: [[TMP18:%.*]] = load i32, ptr [[TMP16]], align 4 // CHECK1-NEXT: [[TMP19:%.*]] = load i32, ptr [[TMP17]], align 4 // CHECK1-NEXT: [[TMP20:%.*]] = insertvalue [3 x i32] zeroinitializer, i32 [[TMP18]], 0 // CHECK1-NEXT: [[TMP21:%.*]] = insertvalue [3 x i32] zeroinitializer, i32 [[TMP19]], 0 -// CHECK1-NEXT: store i32 2, ptr [[KERNEL_ARGS_I]], align 4, !noalias !24 +// CHECK1-NEXT: store i32 2, ptr [[KERNEL_ARGS_I]], align 4, !noalias !25 // CHECK1-NEXT: [[TMP22:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 1 -// CHECK1-NEXT: store i32 3, ptr [[TMP22]], align 4, !noalias !24 +// CHECK1-NEXT: store i32 3, ptr [[TMP22]], align 4, !noalias !25 // CHECK1-NEXT: [[TMP23:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 2 -// CHECK1-NEXT: store ptr [[TMP13]], ptr [[TMP23]], align 8, !noalias !24 +// CHECK1-NEXT: store ptr [[TMP13]], ptr [[TMP23]], align 8, !noalias !25 // CHECK1-NEXT: [[TMP24:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 3 -// CHECK1-NEXT: store ptr [[TMP14]], ptr [[TMP24]], align 8, !noalias !24 +// CHECK1-NEXT: store ptr [[TMP14]], ptr [[TMP24]], align 8, !noalias !25 // CHECK1-NEXT: [[TMP25:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 4 -// CHECK1-NEXT: store ptr [[TMP15]], ptr [[TMP25]], align 8, !noalias !24 +// CHECK1-NEXT: store ptr [[TMP15]], ptr [[TMP25]], align 8, !noalias !25 // CHECK1-NEXT: [[TMP26:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 5 -// CHECK1-NEXT: store ptr @.offload_maptypes, ptr [[TMP26]], align 8, !noalias !24 +// CHECK1-NEXT: store ptr @.offload_maptypes, ptr [[TMP26]], align 8, !noalias !25 // CHECK1-NEXT: [[TMP27:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 6 -// CHECK1-NEXT: store ptr null, ptr [[TMP27]], align 8, !noalias !24 +// CHECK1-NEXT: store ptr null, ptr [[TMP27]], align 8, !noalias !25 // CHECK1-NEXT: [[TMP28:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 7 -// CHECK1-NEXT: store ptr null, ptr [[TMP28]], align 8, !noalias !24 +// CHECK1-NEXT: store ptr null, ptr [[TMP28]], align 8, !noalias !25 // CHECK1-NEXT: [[TMP29:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 8 -// CHECK1-NEXT: store i64 0, ptr [[TMP29]], align 8, !noalias !24 +// CHECK1-NEXT: store i64 0, ptr [[TMP29]], align 8, !noalias !25 // CHECK1-NEXT: [[TMP30:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 9 -// CHECK1-NEXT: store i64 1, ptr [[TMP30]], align 8, !noalias !24 +// CHECK1-NEXT: store i64 1, ptr [[TMP30]], align 8, !noalias !25 // CHECK1-NEXT: [[TMP31:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 10 -// CHECK1-NEXT: store [3 x i32] [[TMP20]], ptr [[TMP31]], align 4, !noalias !24 +// CHECK1-NEXT: store [3 x i32] [[TMP20]], ptr [[TMP31]], align 4, !noalias !25 // CHECK1-NEXT: [[TMP32:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 11 -// CHECK1-NEXT: store [3 x i32] [[TMP21]], ptr [[TMP32]], align 4, !noalias !24 +// CHECK1-NEXT: store [3 x i32] [[TMP21]], ptr [[TMP32]], align 4, !noalias !25 // CHECK1-NEXT: [[TMP33:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 12 -// CHECK1-NEXT: store i32 0, ptr [[TMP33]], align 4, !noalias !24 +// CHECK1-NEXT: store i32 0, ptr [[TMP33]], align 4, !noalias !25 // CHECK1-NEXT: [[TMP34:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 [[TMP18]], i32 [[TMP19]], ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l101.region_id, ptr [[KERNEL_ARGS_I]]) // CHECK1-NEXT: [[TMP35:%.*]] = icmp ne i32 [[TMP34]], 0 // CHECK1-NEXT: br i1 [[TMP35]], label [[OMP_OFFLOAD_FAILED_I:%.*]], label [[DOTOMP_OUTLINED__EXIT:%.*]] // CHECK1: omp_offload.failed.i: // CHECK1-NEXT: [[TMP36:%.*]] = load i16, ptr [[TMP12]], align 2 -// CHECK1-NEXT: store i16 [[TMP36]], ptr [[AA_CASTED_I]], align 2, !noalias !24 -// CHECK1-NEXT: [[TMP37:%.*]] = load i64, ptr [[AA_CASTED_I]], align 8, !noalias !24 +// CHECK1-NEXT: store i16 [[TMP36]], ptr [[AA_CASTED_I]], align 2, !noalias !25 +// CHECK1-NEXT: [[TMP37:%.*]] = load i64, ptr [[AA_CASTED_I]], align 8, !noalias !25 // CHECK1-NEXT: [[TMP38:%.*]] = load i32, ptr [[TMP16]], align 4 -// CHECK1-NEXT: store i32 [[TMP38]], ptr [[DOTCAPTURE_EXPR__CASTED_I]], align 4, !noalias !24 -// CHECK1-NEXT: [[TMP39:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR__CASTED_I]], align 8, !noalias !24 +// CHECK1-NEXT: store i32 [[TMP38]], ptr [[DOTCAPTURE_EXPR__CASTED_I]], align 4, !noalias !25 +// CHECK1-NEXT: [[TMP39:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR__CASTED_I]], align 8, !noalias !25 // CHECK1-NEXT: [[TMP40:%.*]] = load i32, ptr [[TMP17]], align 4 -// CHECK1-NEXT: store i32 [[TMP40]], ptr [[DOTCAPTURE_EXPR__CASTED4_I]], align 4, !noalias !24 -// CHECK1-NEXT: [[TMP41:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR__CASTED4_I]], align 8, !noalias !24 +// CHECK1-NEXT: store i32 [[TMP40]], ptr [[DOTCAPTURE_EXPR__CASTED4_I]], align 4, !noalias !25 +// CHECK1-NEXT: [[TMP41:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR__CASTED4_I]], align 8, !noalias !25 // CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l101(i64 [[TMP37]], i64 [[TMP39]], i64 [[TMP41]]) #[[ATTR3]] // CHECK1-NEXT: br label [[DOTOMP_OUTLINED__EXIT]] // CHECK1: .omp_outlined..exit: @@ -997,7 +1062,48 @@ int bar(int n){ // CHECK1-NEXT: ret void // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142 +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124 +// CHECK1-SAME: (i64 noundef [[A:%.*]], i64 noundef [[AA:%.*]]) #[[ATTR2]] { +// CHECK1-NEXT: entry: +// CHECK1-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 +// CHECK1-NEXT: [[AA_ADDR:%.*]] = alloca i64, align 8 +// CHECK1-NEXT: [[A_CASTED:%.*]] = alloca i64, align 8 +// CHECK1-NEXT: [[AA_CASTED:%.*]] = alloca i64, align 8 +// CHECK1-NEXT: store i64 [[A]], ptr [[A_ADDR]], align 8 +// CHECK1-NEXT: store i64 [[AA]], ptr [[AA_ADDR]], align 8 +// CHECK1-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK1-NEXT: store i32 [[TMP0]], ptr [[A_CASTED]], align 4 +// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[A_CASTED]], align 8 +// CHECK1-NEXT: [[TMP2:%.*]] = load i16, ptr [[AA_ADDR]], align 2 +// CHECK1-NEXT: store i16 [[TMP2]], ptr [[AA_CASTED]], align 2 +// CHECK1-NEXT: [[TMP3:%.*]] = load i64, ptr [[AA_CASTED]], align 8 +// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124.omp_outlined, i64 [[TMP1]], i64 [[TMP3]]) +// CHECK1-NEXT: ret void +// +// +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124.omp_outlined +// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[A:%.*]], i64 noundef [[AA:%.*]]) #[[ATTR2]] { +// CHECK1-NEXT: entry: +// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 +// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8 +// CHECK1-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 +// CHECK1-NEXT: [[AA_ADDR:%.*]] = alloca i64, align 8 +// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8 +// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8 +// CHECK1-NEXT: store i64 [[A]], ptr [[A_ADDR]], align 8 +// CHECK1-NEXT: store i64 [[AA]], ptr [[AA_ADDR]], align 8 +// CHECK1-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], 1 +// CHECK1-NEXT: store i32 [[ADD]], ptr [[A_ADDR]], align 4 +// CHECK1-NEXT: [[TMP1:%.*]] = load i16, ptr [[AA_ADDR]], align 2 +// CHECK1-NEXT: [[CONV:%.*]] = sext i16 [[TMP1]] to i32 +// CHECK1-NEXT: [[ADD1:%.*]] = add nsw i32 [[CONV]], 1 +// CHECK1-NEXT: [[CONV2:%.*]] = trunc i32 [[ADD1]] to i16 +// CHECK1-NEXT: store i16 [[CONV2]], ptr [[AA_ADDR]], align 2 +// CHECK1-NEXT: ret void +// +// +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148 // CHECK1-SAME: (i64 noundef [[A:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[BN:%.*]], ptr noundef nonnull align 8 dereferenceable(400) [[C:%.*]], i64 noundef [[VLA1:%.*]], i64 noundef [[VLA3:%.*]], ptr noundef nonnull align 8 dereferenceable(8) [[CN:%.*]], ptr noundef nonnull align 8 dereferenceable(16) [[D:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 @@ -1030,11 +1136,11 @@ int bar(int n){ // CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[A_ADDR]], align 4 // CHECK1-NEXT: store i32 [[TMP8]], ptr [[A_CASTED]], align 4 // CHECK1-NEXT: [[TMP9:%.*]] = load i64, ptr [[A_CASTED]], align 8 -// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 9, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142.omp_outlined, i64 [[TMP9]], ptr [[TMP0]], i64 [[TMP1]], ptr [[TMP2]], ptr [[TMP3]], i64 [[TMP4]], i64 [[TMP5]], ptr [[TMP6]], ptr [[TMP7]]) +// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 9, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148.omp_outlined, i64 [[TMP9]], ptr [[TMP0]], i64 [[TMP1]], ptr [[TMP2]], ptr [[TMP3]], i64 [[TMP4]], i64 [[TMP5]], ptr [[TMP6]], ptr [[TMP7]]) // CHECK1-NEXT: ret void // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142.omp_outlined +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148.omp_outlined // CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[A:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[BN:%.*]], ptr noundef nonnull align 8 dereferenceable(400) [[C:%.*]], i64 noundef [[VLA1:%.*]], i64 noundef [[VLA3:%.*]], ptr noundef nonnull align 8 dereferenceable(8) [[CN:%.*]], ptr noundef nonnull align 8 dereferenceable(16) [[D:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -1106,7 +1212,7 @@ int bar(int n){ // CHECK1-NEXT: ret void // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154 +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160 // CHECK1-SAME: (i64 noundef [[NN:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[NN_ADDR:%.*]] = alloca i64, align 8 @@ -1115,11 +1221,11 @@ int bar(int n){ // CHECK1-NEXT: [[TMP0:%.*]] = load i32, ptr [[NN_ADDR]], align 4 // CHECK1-NEXT: store i32 [[TMP0]], ptr [[NN_CASTED]], align 4 // CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[NN_CASTED]], align 8 -// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined, i64 [[TMP1]]) +// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined, i64 [[TMP1]]) // CHECK1-NEXT: ret void // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined // CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[NN:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -1132,11 +1238,11 @@ int bar(int n){ // CHECK1-NEXT: [[TMP0:%.*]] = load i32, ptr [[NN_ADDR]], align 4 // CHECK1-NEXT: store i32 [[TMP0]], ptr [[NN_CASTED]], align 4 // CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[NN_CASTED]], align 8 -// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined.omp_outlined, i64 [[TMP1]]) +// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined.omp_outlined, i64 [[TMP1]]) // CHECK1-NEXT: ret void // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined.omp_outlined +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined.omp_outlined // CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[NN:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -1148,7 +1254,7 @@ int bar(int n){ // CHECK1-NEXT: ret void // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157 +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163 // CHECK1-SAME: (i64 noundef [[NN:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[NN_ADDR:%.*]] = alloca i64, align 8 @@ -1157,11 +1263,11 @@ int bar(int n){ // CHECK1-NEXT: [[TMP0:%.*]] = load i32, ptr [[NN_ADDR]], align 4 // CHECK1-NEXT: store i32 [[TMP0]], ptr [[NN_CASTED]], align 4 // CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[NN_CASTED]], align 8 -// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined, i64 [[TMP1]]) +// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined, i64 [[TMP1]]) // CHECK1-NEXT: ret void // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined // CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[NN:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -1170,11 +1276,11 @@ int bar(int n){ // CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8 // CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8 // CHECK1-NEXT: store i64 [[NN]], ptr [[NN_ADDR]], align 8 -// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined.omp_outlined, ptr [[NN_ADDR]]) +// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined.omp_outlined, ptr [[NN_ADDR]]) // CHECK1-NEXT: ret void // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined.omp_outlined +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined.omp_outlined // CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[NN:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -1217,9 +1323,9 @@ int bar(int n){ // CHECK1-NEXT: [[TMP10:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 3 // CHECK1-NEXT: store ptr [[TMP6]], ptr [[TMP10]], align 8 // CHECK1-NEXT: [[TMP11:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 4 -// CHECK1-NEXT: store ptr @.offload_sizes.11, ptr [[TMP11]], align 8 +// CHECK1-NEXT: store ptr @.offload_sizes.13, ptr [[TMP11]], align 8 // CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 5 -// CHECK1-NEXT: store ptr @.offload_maptypes.12, ptr [[TMP12]], align 8 +// CHECK1-NEXT: store ptr @.offload_maptypes.14, ptr [[TMP12]], align 8 // CHECK1-NEXT: [[TMP13:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 6 // CHECK1-NEXT: store ptr null, ptr [[TMP13]], align 8 // CHECK1-NEXT: [[TMP14:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 7 @@ -1234,27 +1340,27 @@ int bar(int n){ // CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP18]], align 4 // CHECK1-NEXT: [[TMP19:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12 // CHECK1-NEXT: store i32 0, ptr [[TMP19]], align 4 -// CHECK1-NEXT: [[TMP20:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182.region_id, ptr [[KERNEL_ARGS]]) +// CHECK1-NEXT: [[TMP20:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188.region_id, ptr [[KERNEL_ARGS]]) // CHECK1-NEXT: [[TMP21:%.*]] = icmp ne i32 [[TMP20]], 0 // CHECK1-NEXT: br i1 [[TMP21]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]] // CHECK1: omp_offload.failed: -// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182(i64 [[TMP1]]) #[[ATTR3]] +// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188(i64 [[TMP1]]) #[[ATTR3]] // CHECK1-NEXT: br label [[OMP_OFFLOAD_CONT]] // CHECK1: omp_offload.cont: // CHECK1-NEXT: ret void // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182 +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188 // CHECK1-SAME: (i64 noundef [[VLA:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8 // CHECK1-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8 // CHECK1-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8 -// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182.omp_outlined, i64 [[TMP0]]) +// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188.omp_outlined, i64 [[TMP0]]) // CHECK1-NEXT: ret void // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182.omp_outlined +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188.omp_outlined // CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[VLA:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -1337,7 +1443,7 @@ int bar(int n){ // CHECK1-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_S1:%.*]], ptr [[THIS1]], i32 0, i32 0 // CHECK1-NEXT: [[TMP8:%.*]] = mul nuw i64 2, [[TMP2]] // CHECK1-NEXT: [[TMP9:%.*]] = mul nuw i64 [[TMP8]], 2 -// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[DOTOFFLOAD_SIZES]], ptr align 8 @.offload_sizes.13, i64 40, i1 false) +// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[DOTOFFLOAD_SIZES]], ptr align 8 @.offload_sizes.15, i64 40, i1 false) // CHECK1-NEXT: [[TMP10:%.*]] = getelementptr inbounds [5 x ptr], ptr [[DOTOFFLOAD_BASEPTRS]], i32 0, i32 0 // CHECK1-NEXT: store ptr [[THIS1]], ptr [[TMP10]], align 8 // CHECK1-NEXT: [[TMP11:%.*]] = getelementptr inbounds [5 x ptr], ptr [[DOTOFFLOAD_PTRS]], i32 0, i32 0 @@ -1384,7 +1490,7 @@ int bar(int n){ // CHECK1-NEXT: [[TMP33:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 4 // CHECK1-NEXT: store ptr [[TMP28]], ptr [[TMP33]], align 8 // CHECK1-NEXT: [[TMP34:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 5 -// CHECK1-NEXT: store ptr @.offload_maptypes.14, ptr [[TMP34]], align 8 +// CHECK1-NEXT: store ptr @.offload_maptypes.16, ptr [[TMP34]], align 8 // CHECK1-NEXT: [[TMP35:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 6 // CHECK1-NEXT: store ptr null, ptr [[TMP35]], align 8 // CHECK1-NEXT: [[TMP36:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 7 @@ -1399,16 +1505,16 @@ int bar(int n){ // CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP40]], align 4 // CHECK1-NEXT: [[TMP41:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12 // CHECK1-NEXT: store i32 0, ptr [[TMP41]], align 4 -// CHECK1-NEXT: [[TMP42:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227.region_id, ptr [[KERNEL_ARGS]]) +// CHECK1-NEXT: [[TMP42:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233.region_id, ptr [[KERNEL_ARGS]]) // CHECK1-NEXT: [[TMP43:%.*]] = icmp ne i32 [[TMP42]], 0 // CHECK1-NEXT: br i1 [[TMP43]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]] // CHECK1: omp_offload.failed: -// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227(ptr [[THIS1]], i64 [[TMP6]], i64 2, i64 [[TMP2]], ptr [[VLA]]) #[[ATTR3]] +// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233(ptr [[THIS1]], i64 [[TMP6]], i64 2, i64 [[TMP2]], ptr [[VLA]]) #[[ATTR3]] // CHECK1-NEXT: br label [[OMP_OFFLOAD_CONT]] // CHECK1: omp_offload.cont: // CHECK1-NEXT: br label [[OMP_IF_END:%.*]] // CHECK1: omp_if.else: -// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227(ptr [[THIS1]], i64 [[TMP6]], i64 2, i64 [[TMP2]], ptr [[VLA]]) #[[ATTR3]] +// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233(ptr [[THIS1]], i64 [[TMP6]], i64 2, i64 [[TMP2]], ptr [[VLA]]) #[[ATTR3]] // CHECK1-NEXT: br label [[OMP_IF_END]] // CHECK1: omp_if.end: // CHECK1-NEXT: [[TMP44:%.*]] = mul nsw i64 1, [[TMP2]] @@ -1490,9 +1596,9 @@ int bar(int n){ // CHECK1-NEXT: [[TMP24:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 3 // CHECK1-NEXT: store ptr [[TMP20]], ptr [[TMP24]], align 8 // CHECK1-NEXT: [[TMP25:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 4 -// CHECK1-NEXT: store ptr @.offload_sizes.15, ptr [[TMP25]], align 8 +// CHECK1-NEXT: store ptr @.offload_sizes.17, ptr [[TMP25]], align 8 // CHECK1-NEXT: [[TMP26:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 5 -// CHECK1-NEXT: store ptr @.offload_maptypes.16, ptr [[TMP26]], align 8 +// CHECK1-NEXT: store ptr @.offload_maptypes.18, ptr [[TMP26]], align 8 // CHECK1-NEXT: [[TMP27:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 6 // CHECK1-NEXT: store ptr null, ptr [[TMP27]], align 8 // CHECK1-NEXT: [[TMP28:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 7 @@ -1507,16 +1613,16 @@ int bar(int n){ // CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP32]], align 4 // CHECK1-NEXT: [[TMP33:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12 // CHECK1-NEXT: store i32 0, ptr [[TMP33]], align 4 -// CHECK1-NEXT: [[TMP34:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209.region_id, ptr [[KERNEL_ARGS]]) +// CHECK1-NEXT: [[TMP34:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215.region_id, ptr [[KERNEL_ARGS]]) // CHECK1-NEXT: [[TMP35:%.*]] = icmp ne i32 [[TMP34]], 0 // CHECK1-NEXT: br i1 [[TMP35]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]] // CHECK1: omp_offload.failed: -// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209(i64 [[TMP1]], i64 [[TMP3]], i64 [[TMP5]], ptr [[B]]) #[[ATTR3]] +// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215(i64 [[TMP1]], i64 [[TMP3]], i64 [[TMP5]], ptr [[B]]) #[[ATTR3]] // CHECK1-NEXT: br label [[OMP_OFFLOAD_CONT]] // CHECK1: omp_offload.cont: // CHECK1-NEXT: br label [[OMP_IF_END:%.*]] // CHECK1: omp_if.else: -// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209(i64 [[TMP1]], i64 [[TMP3]], i64 [[TMP5]], ptr [[B]]) #[[ATTR3]] +// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215(i64 [[TMP1]], i64 [[TMP3]], i64 [[TMP5]], ptr [[B]]) #[[ATTR3]] // CHECK1-NEXT: br label [[OMP_IF_END]] // CHECK1: omp_if.end: // CHECK1-NEXT: [[TMP36:%.*]] = load i32, ptr [[A]], align 4 @@ -1578,9 +1684,9 @@ int bar(int n){ // CHECK1-NEXT: [[TMP19:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 3 // CHECK1-NEXT: store ptr [[TMP15]], ptr [[TMP19]], align 8 // CHECK1-NEXT: [[TMP20:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 4 -// CHECK1-NEXT: store ptr @.offload_sizes.17, ptr [[TMP20]], align 8 +// CHECK1-NEXT: store ptr @.offload_sizes.19, ptr [[TMP20]], align 8 // CHECK1-NEXT: [[TMP21:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 5 -// CHECK1-NEXT: store ptr @.offload_maptypes.18, ptr [[TMP21]], align 8 +// CHECK1-NEXT: store ptr @.offload_maptypes.20, ptr [[TMP21]], align 8 // CHECK1-NEXT: [[TMP22:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 6 // CHECK1-NEXT: store ptr null, ptr [[TMP22]], align 8 // CHECK1-NEXT: [[TMP23:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 7 @@ -1595,23 +1701,23 @@ int bar(int n){ // CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP27]], align 4 // CHECK1-NEXT: [[TMP28:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12 // CHECK1-NEXT: store i32 0, ptr [[TMP28]], align 4 -// CHECK1-NEXT: [[TMP29:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192.region_id, ptr [[KERNEL_ARGS]]) +// CHECK1-NEXT: [[TMP29:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198.region_id, ptr [[KERNEL_ARGS]]) // CHECK1-NEXT: [[TMP30:%.*]] = icmp ne i32 [[TMP29]], 0 // CHECK1-NEXT: br i1 [[TMP30]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]] // CHECK1: omp_offload.failed: -// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192(i64 [[TMP1]], i64 [[TMP3]], ptr [[B]]) #[[ATTR3]] +// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198(i64 [[TMP1]], i64 [[TMP3]], ptr [[B]]) #[[ATTR3]] // CHECK1-NEXT: br label [[OMP_OFFLOAD_CONT]] // CHECK1: omp_offload.cont: // CHECK1-NEXT: br label [[OMP_IF_END:%.*]] // CHECK1: omp_if.else: -// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192(i64 [[TMP1]], i64 [[TMP3]], ptr [[B]]) #[[ATTR3]] +// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198(i64 [[TMP1]], i64 [[TMP3]], ptr [[B]]) #[[ATTR3]] // CHECK1-NEXT: br label [[OMP_IF_END]] // CHECK1: omp_if.end: // CHECK1-NEXT: [[TMP31:%.*]] = load i32, ptr [[A]], align 4 // CHECK1-NEXT: ret i32 [[TMP31]] // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227 +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233 // CHECK1-SAME: (ptr noundef [[THIS:%.*]], i64 noundef [[B:%.*]], i64 noundef [[VLA:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 2 dereferenceable(2) [[C:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 @@ -1632,11 +1738,11 @@ int bar(int n){ // CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[B_ADDR]], align 4 // CHECK1-NEXT: store i32 [[TMP4]], ptr [[B_CASTED]], align 4 // CHECK1-NEXT: [[TMP5:%.*]] = load i64, ptr [[B_CASTED]], align 8 -// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227.omp_outlined, ptr [[TMP0]], i64 [[TMP5]], i64 [[TMP1]], i64 [[TMP2]], ptr [[TMP3]]) +// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233.omp_outlined, ptr [[TMP0]], i64 [[TMP5]], i64 [[TMP1]], i64 [[TMP2]], ptr [[TMP3]]) // CHECK1-NEXT: ret void // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227.omp_outlined +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233.omp_outlined // CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], ptr noundef [[THIS:%.*]], i64 noundef [[B:%.*]], i64 noundef [[VLA:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 2 dereferenceable(2) [[C:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -1674,7 +1780,7 @@ int bar(int n){ // CHECK1-NEXT: ret void // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209 +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215 // CHECK1-SAME: (i64 noundef [[A:%.*]], i64 noundef [[AA:%.*]], i64 noundef [[AAA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 @@ -1698,11 +1804,11 @@ int bar(int n){ // CHECK1-NEXT: [[TMP5:%.*]] = load i8, ptr [[AAA_ADDR]], align 1 // CHECK1-NEXT: store i8 [[TMP5]], ptr [[AAA_CASTED]], align 1 // CHECK1-NEXT: [[TMP6:%.*]] = load i64, ptr [[AAA_CASTED]], align 8 -// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 4, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209.omp_outlined, i64 [[TMP2]], i64 [[TMP4]], i64 [[TMP6]], ptr [[TMP0]]) +// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 4, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215.omp_outlined, i64 [[TMP2]], i64 [[TMP4]], i64 [[TMP6]], ptr [[TMP0]]) // CHECK1-NEXT: ret void // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209.omp_outlined +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215.omp_outlined // CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[A:%.*]], i64 noundef [[AA:%.*]], i64 noundef [[AAA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -1738,7 +1844,7 @@ int bar(int n){ // CHECK1-NEXT: ret void // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192 +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198 // CHECK1-SAME: (i64 noundef [[A:%.*]], i64 noundef [[AA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 @@ -1756,11 +1862,11 @@ int bar(int n){ // CHECK1-NEXT: [[TMP3:%.*]] = load i16, ptr [[AA_ADDR]], align 2 // CHECK1-NEXT: store i16 [[TMP3]], ptr [[AA_CASTED]], align 2 // CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[AA_CASTED]], align 8 -// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192.omp_outlined, i64 [[TMP2]], i64 [[TMP4]], ptr [[TMP0]]) +// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198.omp_outlined, i64 [[TMP2]], i64 [[TMP4]], ptr [[TMP0]]) // CHECK1-NEXT: ret void // // -// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192.omp_outlined +// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198.omp_outlined // CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[A:%.*]], i64 noundef [[AA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR2]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -1830,22 +1936,28 @@ int bar(int n){ // CHECK3-NEXT: [[DOTOFFLOAD_MAPPERS12:%.*]] = alloca [2 x ptr], align 4 // CHECK3-NEXT: [[KERNEL_ARGS13:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 // CHECK3-NEXT: [[A_CASTED16:%.*]] = alloca i32, align 4 -// CHECK3-NEXT: [[DOTOFFLOAD_BASEPTRS19:%.*]] = alloca [9 x ptr], align 4 -// CHECK3-NEXT: [[DOTOFFLOAD_PTRS20:%.*]] = alloca [9 x ptr], align 4 -// CHECK3-NEXT: [[DOTOFFLOAD_MAPPERS21:%.*]] = alloca [9 x ptr], align 4 +// CHECK3-NEXT: [[AA_CASTED17:%.*]] = alloca i32, align 4 +// CHECK3-NEXT: [[DOTOFFLOAD_BASEPTRS18:%.*]] = alloca [2 x ptr], align 4 +// CHECK3-NEXT: [[DOTOFFLOAD_PTRS19:%.*]] = alloca [2 x ptr], align 4 +// CHECK3-NEXT: [[DOTOFFLOAD_MAPPERS20:%.*]] = alloca [2 x ptr], align 4 +// CHECK3-NEXT: [[KERNEL_ARGS21:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 +// CHECK3-NEXT: [[A_CASTED24:%.*]] = alloca i32, align 4 +// CHECK3-NEXT: [[DOTOFFLOAD_BASEPTRS27:%.*]] = alloca [9 x ptr], align 4 +// CHECK3-NEXT: [[DOTOFFLOAD_PTRS28:%.*]] = alloca [9 x ptr], align 4 +// CHECK3-NEXT: [[DOTOFFLOAD_MAPPERS29:%.*]] = alloca [9 x ptr], align 4 // CHECK3-NEXT: [[DOTOFFLOAD_SIZES:%.*]] = alloca [9 x i64], align 4 -// CHECK3-NEXT: [[KERNEL_ARGS22:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 +// CHECK3-NEXT: [[KERNEL_ARGS30:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 // CHECK3-NEXT: [[NN:%.*]] = alloca i32, align 4 // CHECK3-NEXT: [[NN_CASTED:%.*]] = alloca i32, align 4 -// CHECK3-NEXT: [[DOTOFFLOAD_BASEPTRS27:%.*]] = alloca [1 x ptr], align 4 -// CHECK3-NEXT: [[DOTOFFLOAD_PTRS28:%.*]] = alloca [1 x ptr], align 4 -// CHECK3-NEXT: [[DOTOFFLOAD_MAPPERS29:%.*]] = alloca [1 x ptr], align 4 -// CHECK3-NEXT: [[KERNEL_ARGS30:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 -// CHECK3-NEXT: [[NN_CASTED33:%.*]] = alloca i32, align 4 -// CHECK3-NEXT: [[DOTOFFLOAD_BASEPTRS34:%.*]] = alloca [1 x ptr], align 4 -// CHECK3-NEXT: [[DOTOFFLOAD_PTRS35:%.*]] = alloca [1 x ptr], align 4 -// CHECK3-NEXT: [[DOTOFFLOAD_MAPPERS36:%.*]] = alloca [1 x ptr], align 4 -// CHECK3-NEXT: [[KERNEL_ARGS37:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 +// CHECK3-NEXT: [[DOTOFFLOAD_BASEPTRS35:%.*]] = alloca [1 x ptr], align 4 +// CHECK3-NEXT: [[DOTOFFLOAD_PTRS36:%.*]] = alloca [1 x ptr], align 4 +// CHECK3-NEXT: [[DOTOFFLOAD_MAPPERS37:%.*]] = alloca [1 x ptr], align 4 +// CHECK3-NEXT: [[KERNEL_ARGS38:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 +// CHECK3-NEXT: [[NN_CASTED41:%.*]] = alloca i32, align 4 +// CHECK3-NEXT: [[DOTOFFLOAD_BASEPTRS42:%.*]] = alloca [1 x ptr], align 4 +// CHECK3-NEXT: [[DOTOFFLOAD_PTRS43:%.*]] = alloca [1 x ptr], align 4 +// CHECK3-NEXT: [[DOTOFFLOAD_MAPPERS44:%.*]] = alloca [1 x ptr], align 4 +// CHECK3-NEXT: [[KERNEL_ARGS45:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 // CHECK3-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1:[0-9]+]]) // CHECK3-NEXT: store i32 [[N]], ptr [[N_ADDR]], align 4 // CHECK3-NEXT: store i32 0, ptr [[A]], align 4 @@ -2030,208 +2142,261 @@ int bar(int n){ // CHECK3-NEXT: [[TMP93:%.*]] = load i32, ptr [[A]], align 4 // CHECK3-NEXT: store i32 [[TMP93]], ptr [[A_CASTED16]], align 4 // CHECK3-NEXT: [[TMP94:%.*]] = load i32, ptr [[A_CASTED16]], align 4 -// CHECK3-NEXT: [[TMP95:%.*]] = load i32, ptr [[N_ADDR]], align 4 -// CHECK3-NEXT: [[CMP17:%.*]] = icmp sgt i32 [[TMP95]], 20 -// CHECK3-NEXT: br i1 [[CMP17]], label [[OMP_IF_THEN18:%.*]], label [[OMP_IF_ELSE25:%.*]] -// CHECK3: omp_if.then18: -// CHECK3-NEXT: [[TMP96:%.*]] = mul nuw i32 [[TMP1]], 4 -// CHECK3-NEXT: [[TMP97:%.*]] = sext i32 [[TMP96]] to i64 -// CHECK3-NEXT: [[TMP98:%.*]] = mul nuw i32 5, [[TMP3]] -// CHECK3-NEXT: [[TMP99:%.*]] = mul nuw i32 [[TMP98]], 8 -// CHECK3-NEXT: [[TMP100:%.*]] = sext i32 [[TMP99]] to i64 -// CHECK3-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[DOTOFFLOAD_SIZES]], ptr align 4 @.offload_sizes.5, i32 72, i1 false) -// CHECK3-NEXT: [[TMP101:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 0 -// CHECK3-NEXT: store i32 [[TMP94]], ptr [[TMP101]], align 4 -// CHECK3-NEXT: [[TMP102:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 0 -// CHECK3-NEXT: store i32 [[TMP94]], ptr [[TMP102]], align 4 -// CHECK3-NEXT: [[TMP103:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i32 0, i32 0 -// CHECK3-NEXT: store ptr null, ptr [[TMP103]], align 4 -// CHECK3-NEXT: [[TMP104:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 1 -// CHECK3-NEXT: store ptr [[B]], ptr [[TMP104]], align 4 -// CHECK3-NEXT: [[TMP105:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 1 -// CHECK3-NEXT: store ptr [[B]], ptr [[TMP105]], align 4 -// CHECK3-NEXT: [[TMP106:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i32 0, i32 1 -// CHECK3-NEXT: store ptr null, ptr [[TMP106]], align 4 -// CHECK3-NEXT: [[TMP107:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 2 -// CHECK3-NEXT: store i32 [[TMP1]], ptr [[TMP107]], align 4 -// CHECK3-NEXT: [[TMP108:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 2 -// CHECK3-NEXT: store i32 [[TMP1]], ptr [[TMP108]], align 4 -// CHECK3-NEXT: [[TMP109:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i32 0, i32 2 -// CHECK3-NEXT: store ptr null, ptr [[TMP109]], align 4 -// CHECK3-NEXT: [[TMP110:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 3 -// CHECK3-NEXT: store ptr [[VLA]], ptr [[TMP110]], align 4 -// CHECK3-NEXT: [[TMP111:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 3 -// CHECK3-NEXT: store ptr [[VLA]], ptr [[TMP111]], align 4 -// CHECK3-NEXT: [[TMP112:%.*]] = getelementptr inbounds [9 x i64], ptr [[DOTOFFLOAD_SIZES]], i32 0, i32 3 -// CHECK3-NEXT: store i64 [[TMP97]], ptr [[TMP112]], align 4 -// CHECK3-NEXT: [[TMP113:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i32 0, i32 3 -// CHECK3-NEXT: store ptr null, ptr [[TMP113]], align 4 -// CHECK3-NEXT: [[TMP114:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 4 -// CHECK3-NEXT: store ptr [[C]], ptr [[TMP114]], align 4 -// CHECK3-NEXT: [[TMP115:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 4 -// CHECK3-NEXT: store ptr [[C]], ptr [[TMP115]], align 4 -// CHECK3-NEXT: [[TMP116:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i32 0, i32 4 -// CHECK3-NEXT: store ptr null, ptr [[TMP116]], align 4 -// CHECK3-NEXT: [[TMP117:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 5 -// CHECK3-NEXT: store i32 5, ptr [[TMP117]], align 4 -// CHECK3-NEXT: [[TMP118:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 5 -// CHECK3-NEXT: store i32 5, ptr [[TMP118]], align 4 -// CHECK3-NEXT: [[TMP119:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i32 0, i32 5 -// CHECK3-NEXT: store ptr null, ptr [[TMP119]], align 4 -// CHECK3-NEXT: [[TMP120:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 6 -// CHECK3-NEXT: store i32 [[TMP3]], ptr [[TMP120]], align 4 -// CHECK3-NEXT: [[TMP121:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 6 -// CHECK3-NEXT: store i32 [[TMP3]], ptr [[TMP121]], align 4 -// CHECK3-NEXT: [[TMP122:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i32 0, i32 6 -// CHECK3-NEXT: store ptr null, ptr [[TMP122]], align 4 -// CHECK3-NEXT: [[TMP123:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 7 -// CHECK3-NEXT: store ptr [[VLA1]], ptr [[TMP123]], align 4 -// CHECK3-NEXT: [[TMP124:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 7 -// CHECK3-NEXT: store ptr [[VLA1]], ptr [[TMP124]], align 4 -// CHECK3-NEXT: [[TMP125:%.*]] = getelementptr inbounds [9 x i64], ptr [[DOTOFFLOAD_SIZES]], i32 0, i32 7 -// CHECK3-NEXT: store i64 [[TMP100]], ptr [[TMP125]], align 4 -// CHECK3-NEXT: [[TMP126:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i32 0, i32 7 -// CHECK3-NEXT: store ptr null, ptr [[TMP126]], align 4 -// CHECK3-NEXT: [[TMP127:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 8 -// CHECK3-NEXT: store ptr [[D]], ptr [[TMP127]], align 4 -// CHECK3-NEXT: [[TMP128:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 8 -// CHECK3-NEXT: store ptr [[D]], ptr [[TMP128]], align 4 -// CHECK3-NEXT: [[TMP129:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS21]], i32 0, i32 8 -// CHECK3-NEXT: store ptr null, ptr [[TMP129]], align 4 -// CHECK3-NEXT: [[TMP130:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS19]], i32 0, i32 0 -// CHECK3-NEXT: [[TMP131:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS20]], i32 0, i32 0 -// CHECK3-NEXT: [[TMP132:%.*]] = getelementptr inbounds [9 x i64], ptr [[DOTOFFLOAD_SIZES]], i32 0, i32 0 -// CHECK3-NEXT: [[TMP133:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 0 -// CHECK3-NEXT: store i32 2, ptr [[TMP133]], align 4 -// CHECK3-NEXT: [[TMP134:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 1 -// CHECK3-NEXT: store i32 9, ptr [[TMP134]], align 4 -// CHECK3-NEXT: [[TMP135:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 2 -// CHECK3-NEXT: store ptr [[TMP130]], ptr [[TMP135]], align 4 -// CHECK3-NEXT: [[TMP136:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 3 -// CHECK3-NEXT: store ptr [[TMP131]], ptr [[TMP136]], align 4 -// CHECK3-NEXT: [[TMP137:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 4 -// CHECK3-NEXT: store ptr [[TMP132]], ptr [[TMP137]], align 4 -// CHECK3-NEXT: [[TMP138:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 5 -// CHECK3-NEXT: store ptr @.offload_maptypes.6, ptr [[TMP138]], align 4 -// CHECK3-NEXT: [[TMP139:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 6 -// CHECK3-NEXT: store ptr null, ptr [[TMP139]], align 4 -// CHECK3-NEXT: [[TMP140:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 7 +// CHECK3-NEXT: [[TMP95:%.*]] = load i16, ptr [[AA]], align 2 +// CHECK3-NEXT: store i16 [[TMP95]], ptr [[AA_CASTED17]], align 2 +// CHECK3-NEXT: [[TMP96:%.*]] = load i32, ptr [[AA_CASTED17]], align 4 +// CHECK3-NEXT: [[TMP97:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_BASEPTRS18]], i32 0, i32 0 +// CHECK3-NEXT: store i32 [[TMP94]], ptr [[TMP97]], align 4 +// CHECK3-NEXT: [[TMP98:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_PTRS19]], i32 0, i32 0 +// CHECK3-NEXT: store i32 [[TMP94]], ptr [[TMP98]], align 4 +// CHECK3-NEXT: [[TMP99:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_MAPPERS20]], i32 0, i32 0 +// CHECK3-NEXT: store ptr null, ptr [[TMP99]], align 4 +// CHECK3-NEXT: [[TMP100:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_BASEPTRS18]], i32 0, i32 1 +// CHECK3-NEXT: store i32 [[TMP96]], ptr [[TMP100]], align 4 +// CHECK3-NEXT: [[TMP101:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_PTRS19]], i32 0, i32 1 +// CHECK3-NEXT: store i32 [[TMP96]], ptr [[TMP101]], align 4 +// CHECK3-NEXT: [[TMP102:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_MAPPERS20]], i32 0, i32 1 +// CHECK3-NEXT: store ptr null, ptr [[TMP102]], align 4 +// CHECK3-NEXT: [[TMP103:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_BASEPTRS18]], i32 0, i32 0 +// CHECK3-NEXT: [[TMP104:%.*]] = getelementptr inbounds [2 x ptr], ptr [[DOTOFFLOAD_PTRS19]], i32 0, i32 0 +// CHECK3-NEXT: [[TMP105:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 0 +// CHECK3-NEXT: store i32 2, ptr [[TMP105]], align 4 +// CHECK3-NEXT: [[TMP106:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 1 +// CHECK3-NEXT: store i32 2, ptr [[TMP106]], align 4 +// CHECK3-NEXT: [[TMP107:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 2 +// CHECK3-NEXT: store ptr [[TMP103]], ptr [[TMP107]], align 4 +// CHECK3-NEXT: [[TMP108:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 3 +// CHECK3-NEXT: store ptr [[TMP104]], ptr [[TMP108]], align 4 +// CHECK3-NEXT: [[TMP109:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 4 +// CHECK3-NEXT: store ptr @.offload_sizes.5, ptr [[TMP109]], align 4 +// CHECK3-NEXT: [[TMP110:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 5 +// CHECK3-NEXT: store ptr @.offload_maptypes.6, ptr [[TMP110]], align 4 +// CHECK3-NEXT: [[TMP111:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 6 +// CHECK3-NEXT: store ptr null, ptr [[TMP111]], align 4 +// CHECK3-NEXT: [[TMP112:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 7 +// CHECK3-NEXT: store ptr null, ptr [[TMP112]], align 4 +// CHECK3-NEXT: [[TMP113:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 8 +// CHECK3-NEXT: store i64 0, ptr [[TMP113]], align 8 +// CHECK3-NEXT: [[TMP114:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 9 +// CHECK3-NEXT: store i64 0, ptr [[TMP114]], align 8 +// CHECK3-NEXT: [[TMP115:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 10 +// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP115]], align 4 +// CHECK3-NEXT: [[TMP116:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 11 +// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP116]], align 4 +// CHECK3-NEXT: [[TMP117:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS21]], i32 0, i32 12 +// CHECK3-NEXT: store i32 0, ptr [[TMP117]], align 4 +// CHECK3-NEXT: [[TMP118:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124.region_id, ptr [[KERNEL_ARGS21]]) +// CHECK3-NEXT: [[TMP119:%.*]] = icmp ne i32 [[TMP118]], 0 +// CHECK3-NEXT: br i1 [[TMP119]], label [[OMP_OFFLOAD_FAILED22:%.*]], label [[OMP_OFFLOAD_CONT23:%.*]] +// CHECK3: omp_offload.failed22: +// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124(i32 [[TMP94]], i32 [[TMP96]]) #[[ATTR3]] +// CHECK3-NEXT: br label [[OMP_OFFLOAD_CONT23]] +// CHECK3: omp_offload.cont23: +// CHECK3-NEXT: [[TMP120:%.*]] = load i32, ptr [[A]], align 4 +// CHECK3-NEXT: store i32 [[TMP120]], ptr [[A_CASTED24]], align 4 +// CHECK3-NEXT: [[TMP121:%.*]] = load i32, ptr [[A_CASTED24]], align 4 +// CHECK3-NEXT: [[TMP122:%.*]] = load i32, ptr [[N_ADDR]], align 4 +// CHECK3-NEXT: [[CMP25:%.*]] = icmp sgt i32 [[TMP122]], 20 +// CHECK3-NEXT: br i1 [[CMP25]], label [[OMP_IF_THEN26:%.*]], label [[OMP_IF_ELSE33:%.*]] +// CHECK3: omp_if.then26: +// CHECK3-NEXT: [[TMP123:%.*]] = mul nuw i32 [[TMP1]], 4 +// CHECK3-NEXT: [[TMP124:%.*]] = sext i32 [[TMP123]] to i64 +// CHECK3-NEXT: [[TMP125:%.*]] = mul nuw i32 5, [[TMP3]] +// CHECK3-NEXT: [[TMP126:%.*]] = mul nuw i32 [[TMP125]], 8 +// CHECK3-NEXT: [[TMP127:%.*]] = sext i32 [[TMP126]] to i64 +// CHECK3-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[DOTOFFLOAD_SIZES]], ptr align 4 @.offload_sizes.7, i32 72, i1 false) +// CHECK3-NEXT: [[TMP128:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 0 +// CHECK3-NEXT: store i32 [[TMP121]], ptr [[TMP128]], align 4 +// CHECK3-NEXT: [[TMP129:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 0 +// CHECK3-NEXT: store i32 [[TMP121]], ptr [[TMP129]], align 4 +// CHECK3-NEXT: [[TMP130:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i32 0, i32 0 +// CHECK3-NEXT: store ptr null, ptr [[TMP130]], align 4 +// CHECK3-NEXT: [[TMP131:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 1 +// CHECK3-NEXT: store ptr [[B]], ptr [[TMP131]], align 4 +// CHECK3-NEXT: [[TMP132:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 1 +// CHECK3-NEXT: store ptr [[B]], ptr [[TMP132]], align 4 +// CHECK3-NEXT: [[TMP133:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i32 0, i32 1 +// CHECK3-NEXT: store ptr null, ptr [[TMP133]], align 4 +// CHECK3-NEXT: [[TMP134:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 2 +// CHECK3-NEXT: store i32 [[TMP1]], ptr [[TMP134]], align 4 +// CHECK3-NEXT: [[TMP135:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 2 +// CHECK3-NEXT: store i32 [[TMP1]], ptr [[TMP135]], align 4 +// CHECK3-NEXT: [[TMP136:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i32 0, i32 2 +// CHECK3-NEXT: store ptr null, ptr [[TMP136]], align 4 +// CHECK3-NEXT: [[TMP137:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 3 +// CHECK3-NEXT: store ptr [[VLA]], ptr [[TMP137]], align 4 +// CHECK3-NEXT: [[TMP138:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 3 +// CHECK3-NEXT: store ptr [[VLA]], ptr [[TMP138]], align 4 +// CHECK3-NEXT: [[TMP139:%.*]] = getelementptr inbounds [9 x i64], ptr [[DOTOFFLOAD_SIZES]], i32 0, i32 3 +// CHECK3-NEXT: store i64 [[TMP124]], ptr [[TMP139]], align 4 +// CHECK3-NEXT: [[TMP140:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i32 0, i32 3 // CHECK3-NEXT: store ptr null, ptr [[TMP140]], align 4 -// CHECK3-NEXT: [[TMP141:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 8 -// CHECK3-NEXT: store i64 0, ptr [[TMP141]], align 8 -// CHECK3-NEXT: [[TMP142:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 9 -// CHECK3-NEXT: store i64 0, ptr [[TMP142]], align 8 -// CHECK3-NEXT: [[TMP143:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 10 -// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP143]], align 4 -// CHECK3-NEXT: [[TMP144:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 11 -// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP144]], align 4 -// CHECK3-NEXT: [[TMP145:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS22]], i32 0, i32 12 -// CHECK3-NEXT: store i32 0, ptr [[TMP145]], align 4 -// CHECK3-NEXT: [[TMP146:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142.region_id, ptr [[KERNEL_ARGS22]]) -// CHECK3-NEXT: [[TMP147:%.*]] = icmp ne i32 [[TMP146]], 0 -// CHECK3-NEXT: br i1 [[TMP147]], label [[OMP_OFFLOAD_FAILED23:%.*]], label [[OMP_OFFLOAD_CONT24:%.*]] -// CHECK3: omp_offload.failed23: -// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142(i32 [[TMP94]], ptr [[B]], i32 [[TMP1]], ptr [[VLA]], ptr [[C]], i32 5, i32 [[TMP3]], ptr [[VLA1]], ptr [[D]]) #[[ATTR3]] -// CHECK3-NEXT: br label [[OMP_OFFLOAD_CONT24]] -// CHECK3: omp_offload.cont24: -// CHECK3-NEXT: br label [[OMP_IF_END26:%.*]] -// CHECK3: omp_if.else25: -// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142(i32 [[TMP94]], ptr [[B]], i32 [[TMP1]], ptr [[VLA]], ptr [[C]], i32 5, i32 [[TMP3]], ptr [[VLA1]], ptr [[D]]) #[[ATTR3]] -// CHECK3-NEXT: br label [[OMP_IF_END26]] -// CHECK3: omp_if.end26: -// CHECK3-NEXT: store i32 0, ptr [[NN]], align 4 -// CHECK3-NEXT: [[TMP148:%.*]] = load i32, ptr [[NN]], align 4 -// CHECK3-NEXT: store i32 [[TMP148]], ptr [[NN_CASTED]], align 4 -// CHECK3-NEXT: [[TMP149:%.*]] = load i32, ptr [[NN_CASTED]], align 4 -// CHECK3-NEXT: [[TMP150:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 0 -// CHECK3-NEXT: store i32 [[TMP149]], ptr [[TMP150]], align 4 -// CHECK3-NEXT: [[TMP151:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 0 -// CHECK3-NEXT: store i32 [[TMP149]], ptr [[TMP151]], align 4 -// CHECK3-NEXT: [[TMP152:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i32 0, i32 0 -// CHECK3-NEXT: store ptr null, ptr [[TMP152]], align 4 -// CHECK3-NEXT: [[TMP153:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 0 -// CHECK3-NEXT: [[TMP154:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 0 -// CHECK3-NEXT: [[TMP155:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 0 -// CHECK3-NEXT: store i32 2, ptr [[TMP155]], align 4 -// CHECK3-NEXT: [[TMP156:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 1 -// CHECK3-NEXT: store i32 1, ptr [[TMP156]], align 4 -// CHECK3-NEXT: [[TMP157:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 2 -// CHECK3-NEXT: store ptr [[TMP153]], ptr [[TMP157]], align 4 -// CHECK3-NEXT: [[TMP158:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 3 -// CHECK3-NEXT: store ptr [[TMP154]], ptr [[TMP158]], align 4 -// CHECK3-NEXT: [[TMP159:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 4 -// CHECK3-NEXT: store ptr @.offload_sizes.7, ptr [[TMP159]], align 4 -// CHECK3-NEXT: [[TMP160:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 5 -// CHECK3-NEXT: store ptr @.offload_maptypes.8, ptr [[TMP160]], align 4 -// CHECK3-NEXT: [[TMP161:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 6 -// CHECK3-NEXT: store ptr null, ptr [[TMP161]], align 4 -// CHECK3-NEXT: [[TMP162:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 7 -// CHECK3-NEXT: store ptr null, ptr [[TMP162]], align 4 -// CHECK3-NEXT: [[TMP163:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 8 -// CHECK3-NEXT: store i64 0, ptr [[TMP163]], align 8 -// CHECK3-NEXT: [[TMP164:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 9 -// CHECK3-NEXT: store i64 0, ptr [[TMP164]], align 8 -// CHECK3-NEXT: [[TMP165:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 10 -// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP165]], align 4 -// CHECK3-NEXT: [[TMP166:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 11 -// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP166]], align 4 -// CHECK3-NEXT: [[TMP167:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 12 -// CHECK3-NEXT: store i32 0, ptr [[TMP167]], align 4 -// CHECK3-NEXT: [[TMP168:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.region_id, ptr [[KERNEL_ARGS30]]) -// CHECK3-NEXT: [[TMP169:%.*]] = icmp ne i32 [[TMP168]], 0 -// CHECK3-NEXT: br i1 [[TMP169]], label [[OMP_OFFLOAD_FAILED31:%.*]], label [[OMP_OFFLOAD_CONT32:%.*]] +// CHECK3-NEXT: [[TMP141:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 4 +// CHECK3-NEXT: store ptr [[C]], ptr [[TMP141]], align 4 +// CHECK3-NEXT: [[TMP142:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 4 +// CHECK3-NEXT: store ptr [[C]], ptr [[TMP142]], align 4 +// CHECK3-NEXT: [[TMP143:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i32 0, i32 4 +// CHECK3-NEXT: store ptr null, ptr [[TMP143]], align 4 +// CHECK3-NEXT: [[TMP144:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 5 +// CHECK3-NEXT: store i32 5, ptr [[TMP144]], align 4 +// CHECK3-NEXT: [[TMP145:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 5 +// CHECK3-NEXT: store i32 5, ptr [[TMP145]], align 4 +// CHECK3-NEXT: [[TMP146:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i32 0, i32 5 +// CHECK3-NEXT: store ptr null, ptr [[TMP146]], align 4 +// CHECK3-NEXT: [[TMP147:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 6 +// CHECK3-NEXT: store i32 [[TMP3]], ptr [[TMP147]], align 4 +// CHECK3-NEXT: [[TMP148:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 6 +// CHECK3-NEXT: store i32 [[TMP3]], ptr [[TMP148]], align 4 +// CHECK3-NEXT: [[TMP149:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i32 0, i32 6 +// CHECK3-NEXT: store ptr null, ptr [[TMP149]], align 4 +// CHECK3-NEXT: [[TMP150:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 7 +// CHECK3-NEXT: store ptr [[VLA1]], ptr [[TMP150]], align 4 +// CHECK3-NEXT: [[TMP151:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 7 +// CHECK3-NEXT: store ptr [[VLA1]], ptr [[TMP151]], align 4 +// CHECK3-NEXT: [[TMP152:%.*]] = getelementptr inbounds [9 x i64], ptr [[DOTOFFLOAD_SIZES]], i32 0, i32 7 +// CHECK3-NEXT: store i64 [[TMP127]], ptr [[TMP152]], align 4 +// CHECK3-NEXT: [[TMP153:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i32 0, i32 7 +// CHECK3-NEXT: store ptr null, ptr [[TMP153]], align 4 +// CHECK3-NEXT: [[TMP154:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 8 +// CHECK3-NEXT: store ptr [[D]], ptr [[TMP154]], align 4 +// CHECK3-NEXT: [[TMP155:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 8 +// CHECK3-NEXT: store ptr [[D]], ptr [[TMP155]], align 4 +// CHECK3-NEXT: [[TMP156:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_MAPPERS29]], i32 0, i32 8 +// CHECK3-NEXT: store ptr null, ptr [[TMP156]], align 4 +// CHECK3-NEXT: [[TMP157:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_BASEPTRS27]], i32 0, i32 0 +// CHECK3-NEXT: [[TMP158:%.*]] = getelementptr inbounds [9 x ptr], ptr [[DOTOFFLOAD_PTRS28]], i32 0, i32 0 +// CHECK3-NEXT: [[TMP159:%.*]] = getelementptr inbounds [9 x i64], ptr [[DOTOFFLOAD_SIZES]], i32 0, i32 0 +// CHECK3-NEXT: [[TMP160:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 0 +// CHECK3-NEXT: store i32 2, ptr [[TMP160]], align 4 +// CHECK3-NEXT: [[TMP161:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 1 +// CHECK3-NEXT: store i32 9, ptr [[TMP161]], align 4 +// CHECK3-NEXT: [[TMP162:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 2 +// CHECK3-NEXT: store ptr [[TMP157]], ptr [[TMP162]], align 4 +// CHECK3-NEXT: [[TMP163:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 3 +// CHECK3-NEXT: store ptr [[TMP158]], ptr [[TMP163]], align 4 +// CHECK3-NEXT: [[TMP164:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 4 +// CHECK3-NEXT: store ptr [[TMP159]], ptr [[TMP164]], align 4 +// CHECK3-NEXT: [[TMP165:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 5 +// CHECK3-NEXT: store ptr @.offload_maptypes.8, ptr [[TMP165]], align 4 +// CHECK3-NEXT: [[TMP166:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 6 +// CHECK3-NEXT: store ptr null, ptr [[TMP166]], align 4 +// CHECK3-NEXT: [[TMP167:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 7 +// CHECK3-NEXT: store ptr null, ptr [[TMP167]], align 4 +// CHECK3-NEXT: [[TMP168:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 8 +// CHECK3-NEXT: store i64 0, ptr [[TMP168]], align 8 +// CHECK3-NEXT: [[TMP169:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 9 +// CHECK3-NEXT: store i64 0, ptr [[TMP169]], align 8 +// CHECK3-NEXT: [[TMP170:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 10 +// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP170]], align 4 +// CHECK3-NEXT: [[TMP171:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 11 +// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP171]], align 4 +// CHECK3-NEXT: [[TMP172:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS30]], i32 0, i32 12 +// CHECK3-NEXT: store i32 0, ptr [[TMP172]], align 4 +// CHECK3-NEXT: [[TMP173:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148.region_id, ptr [[KERNEL_ARGS30]]) +// CHECK3-NEXT: [[TMP174:%.*]] = icmp ne i32 [[TMP173]], 0 +// CHECK3-NEXT: br i1 [[TMP174]], label [[OMP_OFFLOAD_FAILED31:%.*]], label [[OMP_OFFLOAD_CONT32:%.*]] // CHECK3: omp_offload.failed31: -// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154(i32 [[TMP149]]) #[[ATTR3]] +// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148(i32 [[TMP121]], ptr [[B]], i32 [[TMP1]], ptr [[VLA]], ptr [[C]], i32 5, i32 [[TMP3]], ptr [[VLA1]], ptr [[D]]) #[[ATTR3]] // CHECK3-NEXT: br label [[OMP_OFFLOAD_CONT32]] // CHECK3: omp_offload.cont32: -// CHECK3-NEXT: [[TMP170:%.*]] = load i32, ptr [[NN]], align 4 -// CHECK3-NEXT: store i32 [[TMP170]], ptr [[NN_CASTED33]], align 4 -// CHECK3-NEXT: [[TMP171:%.*]] = load i32, ptr [[NN_CASTED33]], align 4 -// CHECK3-NEXT: [[TMP172:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS34]], i32 0, i32 0 -// CHECK3-NEXT: store i32 [[TMP171]], ptr [[TMP172]], align 4 -// CHECK3-NEXT: [[TMP173:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS35]], i32 0, i32 0 -// CHECK3-NEXT: store i32 [[TMP171]], ptr [[TMP173]], align 4 -// CHECK3-NEXT: [[TMP174:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_MAPPERS36]], i32 0, i32 0 -// CHECK3-NEXT: store ptr null, ptr [[TMP174]], align 4 -// CHECK3-NEXT: [[TMP175:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS34]], i32 0, i32 0 -// CHECK3-NEXT: [[TMP176:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS35]], i32 0, i32 0 -// CHECK3-NEXT: [[TMP177:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 0 -// CHECK3-NEXT: store i32 2, ptr [[TMP177]], align 4 -// CHECK3-NEXT: [[TMP178:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 1 -// CHECK3-NEXT: store i32 1, ptr [[TMP178]], align 4 -// CHECK3-NEXT: [[TMP179:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 2 -// CHECK3-NEXT: store ptr [[TMP175]], ptr [[TMP179]], align 4 -// CHECK3-NEXT: [[TMP180:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 3 -// CHECK3-NEXT: store ptr [[TMP176]], ptr [[TMP180]], align 4 -// CHECK3-NEXT: [[TMP181:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 4 -// CHECK3-NEXT: store ptr @.offload_sizes.9, ptr [[TMP181]], align 4 -// CHECK3-NEXT: [[TMP182:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 5 -// CHECK3-NEXT: store ptr @.offload_maptypes.10, ptr [[TMP182]], align 4 -// CHECK3-NEXT: [[TMP183:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 6 -// CHECK3-NEXT: store ptr null, ptr [[TMP183]], align 4 -// CHECK3-NEXT: [[TMP184:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 7 -// CHECK3-NEXT: store ptr null, ptr [[TMP184]], align 4 -// CHECK3-NEXT: [[TMP185:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 8 -// CHECK3-NEXT: store i64 0, ptr [[TMP185]], align 8 -// CHECK3-NEXT: [[TMP186:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 9 -// CHECK3-NEXT: store i64 0, ptr [[TMP186]], align 8 -// CHECK3-NEXT: [[TMP187:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 10 -// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP187]], align 4 -// CHECK3-NEXT: [[TMP188:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 11 -// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP188]], align 4 -// CHECK3-NEXT: [[TMP189:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS37]], i32 0, i32 12 -// CHECK3-NEXT: store i32 0, ptr [[TMP189]], align 4 -// CHECK3-NEXT: [[TMP190:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.region_id, ptr [[KERNEL_ARGS37]]) -// CHECK3-NEXT: [[TMP191:%.*]] = icmp ne i32 [[TMP190]], 0 -// CHECK3-NEXT: br i1 [[TMP191]], label [[OMP_OFFLOAD_FAILED38:%.*]], label [[OMP_OFFLOAD_CONT39:%.*]] -// CHECK3: omp_offload.failed38: -// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157(i32 [[TMP171]]) #[[ATTR3]] -// CHECK3-NEXT: br label [[OMP_OFFLOAD_CONT39]] -// CHECK3: omp_offload.cont39: -// CHECK3-NEXT: [[TMP192:%.*]] = load i32, ptr [[A]], align 4 -// CHECK3-NEXT: [[TMP193:%.*]] = load ptr, ptr [[SAVED_STACK]], align 4 -// CHECK3-NEXT: call void @llvm.stackrestore.p0(ptr [[TMP193]]) -// CHECK3-NEXT: ret i32 [[TMP192]] +// CHECK3-NEXT: br label [[OMP_IF_END34:%.*]] +// CHECK3: omp_if.else33: +// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148(i32 [[TMP121]], ptr [[B]], i32 [[TMP1]], ptr [[VLA]], ptr [[C]], i32 5, i32 [[TMP3]], ptr [[VLA1]], ptr [[D]]) #[[ATTR3]] +// CHECK3-NEXT: br label [[OMP_IF_END34]] +// CHECK3: omp_if.end34: +// CHECK3-NEXT: store i32 0, ptr [[NN]], align 4 +// CHECK3-NEXT: [[TMP175:%.*]] = load i32, ptr [[NN]], align 4 +// CHECK3-NEXT: store i32 [[TMP175]], ptr [[NN_CASTED]], align 4 +// CHECK3-NEXT: [[TMP176:%.*]] = load i32, ptr [[NN_CASTED]], align 4 +// CHECK3-NEXT: [[TMP177:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS35]], i32 0, i32 0 +// CHECK3-NEXT: store i32 [[TMP176]], ptr [[TMP177]], align 4 +// CHECK3-NEXT: [[TMP178:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS36]], i32 0, i32 0 +// CHECK3-NEXT: store i32 [[TMP176]], ptr [[TMP178]], align 4 +// CHECK3-NEXT: [[TMP179:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_MAPPERS37]], i32 0, i32 0 +// CHECK3-NEXT: store ptr null, ptr [[TMP179]], align 4 +// CHECK3-NEXT: [[TMP180:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS35]], i32 0, i32 0 +// CHECK3-NEXT: [[TMP181:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS36]], i32 0, i32 0 +// CHECK3-NEXT: [[TMP182:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 0 +// CHECK3-NEXT: store i32 2, ptr [[TMP182]], align 4 +// CHECK3-NEXT: [[TMP183:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 1 +// CHECK3-NEXT: store i32 1, ptr [[TMP183]], align 4 +// CHECK3-NEXT: [[TMP184:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 2 +// CHECK3-NEXT: store ptr [[TMP180]], ptr [[TMP184]], align 4 +// CHECK3-NEXT: [[TMP185:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 3 +// CHECK3-NEXT: store ptr [[TMP181]], ptr [[TMP185]], align 4 +// CHECK3-NEXT: [[TMP186:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 4 +// CHECK3-NEXT: store ptr @.offload_sizes.9, ptr [[TMP186]], align 4 +// CHECK3-NEXT: [[TMP187:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 5 +// CHECK3-NEXT: store ptr @.offload_maptypes.10, ptr [[TMP187]], align 4 +// CHECK3-NEXT: [[TMP188:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 6 +// CHECK3-NEXT: store ptr null, ptr [[TMP188]], align 4 +// CHECK3-NEXT: [[TMP189:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 7 +// CHECK3-NEXT: store ptr null, ptr [[TMP189]], align 4 +// CHECK3-NEXT: [[TMP190:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 8 +// CHECK3-NEXT: store i64 0, ptr [[TMP190]], align 8 +// CHECK3-NEXT: [[TMP191:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 9 +// CHECK3-NEXT: store i64 0, ptr [[TMP191]], align 8 +// CHECK3-NEXT: [[TMP192:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 10 +// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP192]], align 4 +// CHECK3-NEXT: [[TMP193:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 11 +// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP193]], align 4 +// CHECK3-NEXT: [[TMP194:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS38]], i32 0, i32 12 +// CHECK3-NEXT: store i32 0, ptr [[TMP194]], align 4 +// CHECK3-NEXT: [[TMP195:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.region_id, ptr [[KERNEL_ARGS38]]) +// CHECK3-NEXT: [[TMP196:%.*]] = icmp ne i32 [[TMP195]], 0 +// CHECK3-NEXT: br i1 [[TMP196]], label [[OMP_OFFLOAD_FAILED39:%.*]], label [[OMP_OFFLOAD_CONT40:%.*]] +// CHECK3: omp_offload.failed39: +// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160(i32 [[TMP176]]) #[[ATTR3]] +// CHECK3-NEXT: br label [[OMP_OFFLOAD_CONT40]] +// CHECK3: omp_offload.cont40: +// CHECK3-NEXT: [[TMP197:%.*]] = load i32, ptr [[NN]], align 4 +// CHECK3-NEXT: store i32 [[TMP197]], ptr [[NN_CASTED41]], align 4 +// CHECK3-NEXT: [[TMP198:%.*]] = load i32, ptr [[NN_CASTED41]], align 4 +// CHECK3-NEXT: [[TMP199:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS42]], i32 0, i32 0 +// CHECK3-NEXT: store i32 [[TMP198]], ptr [[TMP199]], align 4 +// CHECK3-NEXT: [[TMP200:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS43]], i32 0, i32 0 +// CHECK3-NEXT: store i32 [[TMP198]], ptr [[TMP200]], align 4 +// CHECK3-NEXT: [[TMP201:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_MAPPERS44]], i32 0, i32 0 +// CHECK3-NEXT: store ptr null, ptr [[TMP201]], align 4 +// CHECK3-NEXT: [[TMP202:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS42]], i32 0, i32 0 +// CHECK3-NEXT: [[TMP203:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS43]], i32 0, i32 0 +// CHECK3-NEXT: [[TMP204:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 0 +// CHECK3-NEXT: store i32 2, ptr [[TMP204]], align 4 +// CHECK3-NEXT: [[TMP205:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 1 +// CHECK3-NEXT: store i32 1, ptr [[TMP205]], align 4 +// CHECK3-NEXT: [[TMP206:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 2 +// CHECK3-NEXT: store ptr [[TMP202]], ptr [[TMP206]], align 4 +// CHECK3-NEXT: [[TMP207:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 3 +// CHECK3-NEXT: store ptr [[TMP203]], ptr [[TMP207]], align 4 +// CHECK3-NEXT: [[TMP208:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 4 +// CHECK3-NEXT: store ptr @.offload_sizes.11, ptr [[TMP208]], align 4 +// CHECK3-NEXT: [[TMP209:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 5 +// CHECK3-NEXT: store ptr @.offload_maptypes.12, ptr [[TMP209]], align 4 +// CHECK3-NEXT: [[TMP210:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 6 +// CHECK3-NEXT: store ptr null, ptr [[TMP210]], align 4 +// CHECK3-NEXT: [[TMP211:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 7 +// CHECK3-NEXT: store ptr null, ptr [[TMP211]], align 4 +// CHECK3-NEXT: [[TMP212:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 8 +// CHECK3-NEXT: store i64 0, ptr [[TMP212]], align 8 +// CHECK3-NEXT: [[TMP213:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 9 +// CHECK3-NEXT: store i64 0, ptr [[TMP213]], align 8 +// CHECK3-NEXT: [[TMP214:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 10 +// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP214]], align 4 +// CHECK3-NEXT: [[TMP215:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 11 +// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP215]], align 4 +// CHECK3-NEXT: [[TMP216:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS45]], i32 0, i32 12 +// CHECK3-NEXT: store i32 0, ptr [[TMP216]], align 4 +// CHECK3-NEXT: [[TMP217:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.region_id, ptr [[KERNEL_ARGS45]]) +// CHECK3-NEXT: [[TMP218:%.*]] = icmp ne i32 [[TMP217]], 0 +// CHECK3-NEXT: br i1 [[TMP218]], label [[OMP_OFFLOAD_FAILED46:%.*]], label [[OMP_OFFLOAD_CONT47:%.*]] +// CHECK3: omp_offload.failed46: +// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163(i32 [[TMP198]]) #[[ATTR3]] +// CHECK3-NEXT: br label [[OMP_OFFLOAD_CONT47]] +// CHECK3: omp_offload.cont47: +// CHECK3-NEXT: [[TMP219:%.*]] = load i32, ptr [[A]], align 4 +// CHECK3-NEXT: [[TMP220:%.*]] = load ptr, ptr [[SAVED_STACK]], align 4 +// CHECK3-NEXT: call void @llvm.stackrestore.p0(ptr [[TMP220]]) +// CHECK3-NEXT: ret i32 [[TMP219]] // // // CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l101 @@ -2324,68 +2489,68 @@ int bar(int n){ // CHECK3-NEXT: [[TMP6:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T]], ptr [[TMP4]], i32 0, i32 0 // CHECK3-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 4 // CHECK3-NEXT: [[TMP8:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T_WITH_PRIVATES]], ptr [[TMP3]], i32 0, i32 1 -// CHECK3-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META16:![0-9]+]]) -// CHECK3-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META19:![0-9]+]]) -// CHECK3-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META21:![0-9]+]]) -// CHECK3-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META23:![0-9]+]]) -// CHECK3-NEXT: store i32 [[TMP2]], ptr [[DOTGLOBAL_TID__ADDR_I]], align 4, !noalias !25 -// CHECK3-NEXT: store ptr [[TMP5]], ptr [[DOTPART_ID__ADDR_I]], align 4, !noalias !25 -// CHECK3-NEXT: store ptr [[TMP8]], ptr [[DOTPRIVATES__ADDR_I]], align 4, !noalias !25 -// CHECK3-NEXT: store ptr @.omp_task_privates_map., ptr [[DOTCOPY_FN__ADDR_I]], align 4, !noalias !25 -// CHECK3-NEXT: store ptr [[TMP3]], ptr [[DOTTASK_T__ADDR_I]], align 4, !noalias !25 -// CHECK3-NEXT: store ptr [[TMP7]], ptr [[__CONTEXT_ADDR_I]], align 4, !noalias !25 -// CHECK3-NEXT: [[TMP9:%.*]] = load ptr, ptr [[__CONTEXT_ADDR_I]], align 4, !noalias !25 -// CHECK3-NEXT: [[TMP10:%.*]] = load ptr, ptr [[DOTCOPY_FN__ADDR_I]], align 4, !noalias !25 -// CHECK3-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTPRIVATES__ADDR_I]], align 4, !noalias !25 +// CHECK3-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META17:![0-9]+]]) +// CHECK3-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META20:![0-9]+]]) +// CHECK3-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META22:![0-9]+]]) +// CHECK3-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META24:![0-9]+]]) +// CHECK3-NEXT: store i32 [[TMP2]], ptr [[DOTGLOBAL_TID__ADDR_I]], align 4, !noalias !26 +// CHECK3-NEXT: store ptr [[TMP5]], ptr [[DOTPART_ID__ADDR_I]], align 4, !noalias !26 +// CHECK3-NEXT: store ptr [[TMP8]], ptr [[DOTPRIVATES__ADDR_I]], align 4, !noalias !26 +// CHECK3-NEXT: store ptr @.omp_task_privates_map., ptr [[DOTCOPY_FN__ADDR_I]], align 4, !noalias !26 +// CHECK3-NEXT: store ptr [[TMP3]], ptr [[DOTTASK_T__ADDR_I]], align 4, !noalias !26 +// CHECK3-NEXT: store ptr [[TMP7]], ptr [[__CONTEXT_ADDR_I]], align 4, !noalias !26 +// CHECK3-NEXT: [[TMP9:%.*]] = load ptr, ptr [[__CONTEXT_ADDR_I]], align 4, !noalias !26 +// CHECK3-NEXT: [[TMP10:%.*]] = load ptr, ptr [[DOTCOPY_FN__ADDR_I]], align 4, !noalias !26 +// CHECK3-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTPRIVATES__ADDR_I]], align 4, !noalias !26 // CHECK3-NEXT: call void [[TMP10]](ptr [[TMP11]], ptr [[DOTFIRSTPRIV_PTR_ADDR_I]], ptr [[DOTFIRSTPRIV_PTR_ADDR1_I]], ptr [[DOTFIRSTPRIV_PTR_ADDR2_I]], ptr [[DOTFIRSTPRIV_PTR_ADDR3_I]]) #[[ATTR3]] -// CHECK3-NEXT: [[TMP12:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR_I]], align 4, !noalias !25 -// CHECK3-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR1_I]], align 4, !noalias !25 -// CHECK3-NEXT: [[TMP14:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR2_I]], align 4, !noalias !25 -// CHECK3-NEXT: [[TMP15:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR3_I]], align 4, !noalias !25 +// CHECK3-NEXT: [[TMP12:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR_I]], align 4, !noalias !26 +// CHECK3-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR1_I]], align 4, !noalias !26 +// CHECK3-NEXT: [[TMP14:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR2_I]], align 4, !noalias !26 +// CHECK3-NEXT: [[TMP15:%.*]] = load ptr, ptr [[DOTFIRSTPRIV_PTR_ADDR3_I]], align 4, !noalias !26 // CHECK3-NEXT: [[TMP16:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], ptr [[TMP9]], i32 0, i32 1 // CHECK3-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT_ANON]], ptr [[TMP9]], i32 0, i32 2 // CHECK3-NEXT: [[TMP18:%.*]] = load i32, ptr [[TMP16]], align 4 // CHECK3-NEXT: [[TMP19:%.*]] = load i32, ptr [[TMP17]], align 4 // CHECK3-NEXT: [[TMP20:%.*]] = insertvalue [3 x i32] zeroinitializer, i32 [[TMP18]], 0 // CHECK3-NEXT: [[TMP21:%.*]] = insertvalue [3 x i32] zeroinitializer, i32 [[TMP19]], 0 -// CHECK3-NEXT: store i32 2, ptr [[KERNEL_ARGS_I]], align 4, !noalias !25 +// CHECK3-NEXT: store i32 2, ptr [[KERNEL_ARGS_I]], align 4, !noalias !26 // CHECK3-NEXT: [[TMP22:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 1 -// CHECK3-NEXT: store i32 3, ptr [[TMP22]], align 4, !noalias !25 +// CHECK3-NEXT: store i32 3, ptr [[TMP22]], align 4, !noalias !26 // CHECK3-NEXT: [[TMP23:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 2 -// CHECK3-NEXT: store ptr [[TMP13]], ptr [[TMP23]], align 4, !noalias !25 +// CHECK3-NEXT: store ptr [[TMP13]], ptr [[TMP23]], align 4, !noalias !26 // CHECK3-NEXT: [[TMP24:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 3 -// CHECK3-NEXT: store ptr [[TMP14]], ptr [[TMP24]], align 4, !noalias !25 +// CHECK3-NEXT: store ptr [[TMP14]], ptr [[TMP24]], align 4, !noalias !26 // CHECK3-NEXT: [[TMP25:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 4 -// CHECK3-NEXT: store ptr [[TMP15]], ptr [[TMP25]], align 4, !noalias !25 +// CHECK3-NEXT: store ptr [[TMP15]], ptr [[TMP25]], align 4, !noalias !26 // CHECK3-NEXT: [[TMP26:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 5 -// CHECK3-NEXT: store ptr @.offload_maptypes, ptr [[TMP26]], align 4, !noalias !25 +// CHECK3-NEXT: store ptr @.offload_maptypes, ptr [[TMP26]], align 4, !noalias !26 // CHECK3-NEXT: [[TMP27:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 6 -// CHECK3-NEXT: store ptr null, ptr [[TMP27]], align 4, !noalias !25 +// CHECK3-NEXT: store ptr null, ptr [[TMP27]], align 4, !noalias !26 // CHECK3-NEXT: [[TMP28:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 7 -// CHECK3-NEXT: store ptr null, ptr [[TMP28]], align 4, !noalias !25 +// CHECK3-NEXT: store ptr null, ptr [[TMP28]], align 4, !noalias !26 // CHECK3-NEXT: [[TMP29:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 8 -// CHECK3-NEXT: store i64 0, ptr [[TMP29]], align 8, !noalias !25 +// CHECK3-NEXT: store i64 0, ptr [[TMP29]], align 8, !noalias !26 // CHECK3-NEXT: [[TMP30:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 9 -// CHECK3-NEXT: store i64 1, ptr [[TMP30]], align 8, !noalias !25 +// CHECK3-NEXT: store i64 1, ptr [[TMP30]], align 8, !noalias !26 // CHECK3-NEXT: [[TMP31:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 10 -// CHECK3-NEXT: store [3 x i32] [[TMP20]], ptr [[TMP31]], align 4, !noalias !25 +// CHECK3-NEXT: store [3 x i32] [[TMP20]], ptr [[TMP31]], align 4, !noalias !26 // CHECK3-NEXT: [[TMP32:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 11 -// CHECK3-NEXT: store [3 x i32] [[TMP21]], ptr [[TMP32]], align 4, !noalias !25 +// CHECK3-NEXT: store [3 x i32] [[TMP21]], ptr [[TMP32]], align 4, !noalias !26 // CHECK3-NEXT: [[TMP33:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS_I]], i32 0, i32 12 -// CHECK3-NEXT: store i32 0, ptr [[TMP33]], align 4, !noalias !25 +// CHECK3-NEXT: store i32 0, ptr [[TMP33]], align 4, !noalias !26 // CHECK3-NEXT: [[TMP34:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 [[TMP18]], i32 [[TMP19]], ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l101.region_id, ptr [[KERNEL_ARGS_I]]) // CHECK3-NEXT: [[TMP35:%.*]] = icmp ne i32 [[TMP34]], 0 // CHECK3-NEXT: br i1 [[TMP35]], label [[OMP_OFFLOAD_FAILED_I:%.*]], label [[DOTOMP_OUTLINED__EXIT:%.*]] // CHECK3: omp_offload.failed.i: // CHECK3-NEXT: [[TMP36:%.*]] = load i16, ptr [[TMP12]], align 2 -// CHECK3-NEXT: store i16 [[TMP36]], ptr [[AA_CASTED_I]], align 2, !noalias !25 -// CHECK3-NEXT: [[TMP37:%.*]] = load i32, ptr [[AA_CASTED_I]], align 4, !noalias !25 +// CHECK3-NEXT: store i16 [[TMP36]], ptr [[AA_CASTED_I]], align 2, !noalias !26 +// CHECK3-NEXT: [[TMP37:%.*]] = load i32, ptr [[AA_CASTED_I]], align 4, !noalias !26 // CHECK3-NEXT: [[TMP38:%.*]] = load i32, ptr [[TMP16]], align 4 -// CHECK3-NEXT: store i32 [[TMP38]], ptr [[DOTCAPTURE_EXPR__CASTED_I]], align 4, !noalias !25 -// CHECK3-NEXT: [[TMP39:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__CASTED_I]], align 4, !noalias !25 +// CHECK3-NEXT: store i32 [[TMP38]], ptr [[DOTCAPTURE_EXPR__CASTED_I]], align 4, !noalias !26 +// CHECK3-NEXT: [[TMP39:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__CASTED_I]], align 4, !noalias !26 // CHECK3-NEXT: [[TMP40:%.*]] = load i32, ptr [[TMP17]], align 4 -// CHECK3-NEXT: store i32 [[TMP40]], ptr [[DOTCAPTURE_EXPR__CASTED4_I]], align 4, !noalias !25 -// CHECK3-NEXT: [[TMP41:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__CASTED4_I]], align 4, !noalias !25 +// CHECK3-NEXT: store i32 [[TMP40]], ptr [[DOTCAPTURE_EXPR__CASTED4_I]], align 4, !noalias !26 +// CHECK3-NEXT: [[TMP41:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__CASTED4_I]], align 4, !noalias !26 // CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l101(i32 [[TMP37]], i32 [[TMP39]], i32 [[TMP41]]) #[[ATTR3]] // CHECK3-NEXT: br label [[DOTOMP_OUTLINED__EXIT]] // CHECK3: .omp_outlined..exit: @@ -2491,7 +2656,48 @@ int bar(int n){ // CHECK3-NEXT: ret void // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142 +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124 +// CHECK3-SAME: (i32 noundef [[A:%.*]], i32 noundef [[AA:%.*]]) #[[ATTR2]] { +// CHECK3-NEXT: entry: +// CHECK3-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK3-NEXT: [[AA_ADDR:%.*]] = alloca i32, align 4 +// CHECK3-NEXT: [[A_CASTED:%.*]] = alloca i32, align 4 +// CHECK3-NEXT: [[AA_CASTED:%.*]] = alloca i32, align 4 +// CHECK3-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4 +// CHECK3-NEXT: store i32 [[AA]], ptr [[AA_ADDR]], align 4 +// CHECK3-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK3-NEXT: store i32 [[TMP0]], ptr [[A_CASTED]], align 4 +// CHECK3-NEXT: [[TMP1:%.*]] = load i32, ptr [[A_CASTED]], align 4 +// CHECK3-NEXT: [[TMP2:%.*]] = load i16, ptr [[AA_ADDR]], align 2 +// CHECK3-NEXT: store i16 [[TMP2]], ptr [[AA_CASTED]], align 2 +// CHECK3-NEXT: [[TMP3:%.*]] = load i32, ptr [[AA_CASTED]], align 4 +// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124.omp_outlined, i32 [[TMP1]], i32 [[TMP3]]) +// CHECK3-NEXT: ret void +// +// +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124.omp_outlined +// CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[A:%.*]], i32 noundef [[AA:%.*]]) #[[ATTR2]] { +// CHECK3-NEXT: entry: +// CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 +// CHECK3-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4 +// CHECK3-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK3-NEXT: [[AA_ADDR:%.*]] = alloca i32, align 4 +// CHECK3-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4 +// CHECK3-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4 +// CHECK3-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4 +// CHECK3-NEXT: store i32 [[AA]], ptr [[AA_ADDR]], align 4 +// CHECK3-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], 1 +// CHECK3-NEXT: store i32 [[ADD]], ptr [[A_ADDR]], align 4 +// CHECK3-NEXT: [[TMP1:%.*]] = load i16, ptr [[AA_ADDR]], align 2 +// CHECK3-NEXT: [[CONV:%.*]] = sext i16 [[TMP1]] to i32 +// CHECK3-NEXT: [[ADD1:%.*]] = add nsw i32 [[CONV]], 1 +// CHECK3-NEXT: [[CONV2:%.*]] = trunc i32 [[ADD1]] to i16 +// CHECK3-NEXT: store i16 [[CONV2]], ptr [[AA_ADDR]], align 2 +// CHECK3-NEXT: ret void +// +// +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148 // CHECK3-SAME: (i32 noundef [[A:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]], i32 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[BN:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[C:%.*]], i32 noundef [[VLA1:%.*]], i32 noundef [[VLA3:%.*]], ptr noundef nonnull align 4 dereferenceable(8) [[CN:%.*]], ptr noundef nonnull align 4 dereferenceable(12) [[D:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 @@ -2524,11 +2730,11 @@ int bar(int n){ // CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[A_ADDR]], align 4 // CHECK3-NEXT: store i32 [[TMP8]], ptr [[A_CASTED]], align 4 // CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[A_CASTED]], align 4 -// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 9, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142.omp_outlined, i32 [[TMP9]], ptr [[TMP0]], i32 [[TMP1]], ptr [[TMP2]], ptr [[TMP3]], i32 [[TMP4]], i32 [[TMP5]], ptr [[TMP6]], ptr [[TMP7]]) +// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 9, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148.omp_outlined, i32 [[TMP9]], ptr [[TMP0]], i32 [[TMP1]], ptr [[TMP2]], ptr [[TMP3]], i32 [[TMP4]], i32 [[TMP5]], ptr [[TMP6]], ptr [[TMP7]]) // CHECK3-NEXT: ret void // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142.omp_outlined +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148.omp_outlined // CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[A:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]], i32 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[BN:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[C:%.*]], i32 noundef [[VLA1:%.*]], i32 noundef [[VLA3:%.*]], ptr noundef nonnull align 4 dereferenceable(8) [[CN:%.*]], ptr noundef nonnull align 4 dereferenceable(12) [[D:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -2600,7 +2806,7 @@ int bar(int n){ // CHECK3-NEXT: ret void // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154 +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160 // CHECK3-SAME: (i32 noundef [[NN:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[NN_ADDR:%.*]] = alloca i32, align 4 @@ -2609,11 +2815,11 @@ int bar(int n){ // CHECK3-NEXT: [[TMP0:%.*]] = load i32, ptr [[NN_ADDR]], align 4 // CHECK3-NEXT: store i32 [[TMP0]], ptr [[NN_CASTED]], align 4 // CHECK3-NEXT: [[TMP1:%.*]] = load i32, ptr [[NN_CASTED]], align 4 -// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined, i32 [[TMP1]]) +// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined, i32 [[TMP1]]) // CHECK3-NEXT: ret void // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined // CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[NN:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -2626,11 +2832,11 @@ int bar(int n){ // CHECK3-NEXT: [[TMP0:%.*]] = load i32, ptr [[NN_ADDR]], align 4 // CHECK3-NEXT: store i32 [[TMP0]], ptr [[NN_CASTED]], align 4 // CHECK3-NEXT: [[TMP1:%.*]] = load i32, ptr [[NN_CASTED]], align 4 -// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined.omp_outlined, i32 [[TMP1]]) +// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined.omp_outlined, i32 [[TMP1]]) // CHECK3-NEXT: ret void // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined.omp_outlined +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined.omp_outlined // CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[NN:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -2642,7 +2848,7 @@ int bar(int n){ // CHECK3-NEXT: ret void // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157 +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163 // CHECK3-SAME: (i32 noundef [[NN:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[NN_ADDR:%.*]] = alloca i32, align 4 @@ -2651,11 +2857,11 @@ int bar(int n){ // CHECK3-NEXT: [[TMP0:%.*]] = load i32, ptr [[NN_ADDR]], align 4 // CHECK3-NEXT: store i32 [[TMP0]], ptr [[NN_CASTED]], align 4 // CHECK3-NEXT: [[TMP1:%.*]] = load i32, ptr [[NN_CASTED]], align 4 -// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined, i32 [[TMP1]]) +// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined, i32 [[TMP1]]) // CHECK3-NEXT: ret void // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined // CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[NN:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -2664,11 +2870,11 @@ int bar(int n){ // CHECK3-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4 // CHECK3-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4 // CHECK3-NEXT: store i32 [[NN]], ptr [[NN_ADDR]], align 4 -// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined.omp_outlined, ptr [[NN_ADDR]]) +// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined.omp_outlined, ptr [[NN_ADDR]]) // CHECK3-NEXT: ret void // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined.omp_outlined +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined.omp_outlined // CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[NN:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -2710,9 +2916,9 @@ int bar(int n){ // CHECK3-NEXT: [[TMP9:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 3 // CHECK3-NEXT: store ptr [[TMP5]], ptr [[TMP9]], align 4 // CHECK3-NEXT: [[TMP10:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 4 -// CHECK3-NEXT: store ptr @.offload_sizes.11, ptr [[TMP10]], align 4 +// CHECK3-NEXT: store ptr @.offload_sizes.13, ptr [[TMP10]], align 4 // CHECK3-NEXT: [[TMP11:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 5 -// CHECK3-NEXT: store ptr @.offload_maptypes.12, ptr [[TMP11]], align 4 +// CHECK3-NEXT: store ptr @.offload_maptypes.14, ptr [[TMP11]], align 4 // CHECK3-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 6 // CHECK3-NEXT: store ptr null, ptr [[TMP12]], align 4 // CHECK3-NEXT: [[TMP13:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 7 @@ -2727,27 +2933,27 @@ int bar(int n){ // CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP17]], align 4 // CHECK3-NEXT: [[TMP18:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12 // CHECK3-NEXT: store i32 0, ptr [[TMP18]], align 4 -// CHECK3-NEXT: [[TMP19:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182.region_id, ptr [[KERNEL_ARGS]]) +// CHECK3-NEXT: [[TMP19:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188.region_id, ptr [[KERNEL_ARGS]]) // CHECK3-NEXT: [[TMP20:%.*]] = icmp ne i32 [[TMP19]], 0 // CHECK3-NEXT: br i1 [[TMP20]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]] // CHECK3: omp_offload.failed: -// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182(i32 [[TMP0]]) #[[ATTR3]] +// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188(i32 [[TMP0]]) #[[ATTR3]] // CHECK3-NEXT: br label [[OMP_OFFLOAD_CONT]] // CHECK3: omp_offload.cont: // CHECK3-NEXT: ret void // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182 +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188 // CHECK3-SAME: (i32 noundef [[VLA:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[VLA_ADDR:%.*]] = alloca i32, align 4 // CHECK3-NEXT: store i32 [[VLA]], ptr [[VLA_ADDR]], align 4 // CHECK3-NEXT: [[TMP0:%.*]] = load i32, ptr [[VLA_ADDR]], align 4 -// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182.omp_outlined, i32 [[TMP0]]) +// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188.omp_outlined, i32 [[TMP0]]) // CHECK3-NEXT: ret void // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182.omp_outlined +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188.omp_outlined // CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[VLA:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -2830,7 +3036,7 @@ int bar(int n){ // CHECK3-NEXT: [[TMP7:%.*]] = mul nuw i32 2, [[TMP1]] // CHECK3-NEXT: [[TMP8:%.*]] = mul nuw i32 [[TMP7]], 2 // CHECK3-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i64 -// CHECK3-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[DOTOFFLOAD_SIZES]], ptr align 4 @.offload_sizes.13, i32 40, i1 false) +// CHECK3-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[DOTOFFLOAD_SIZES]], ptr align 4 @.offload_sizes.15, i32 40, i1 false) // CHECK3-NEXT: [[TMP10:%.*]] = getelementptr inbounds [5 x ptr], ptr [[DOTOFFLOAD_BASEPTRS]], i32 0, i32 0 // CHECK3-NEXT: store ptr [[THIS1]], ptr [[TMP10]], align 4 // CHECK3-NEXT: [[TMP11:%.*]] = getelementptr inbounds [5 x ptr], ptr [[DOTOFFLOAD_PTRS]], i32 0, i32 0 @@ -2877,7 +3083,7 @@ int bar(int n){ // CHECK3-NEXT: [[TMP33:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 4 // CHECK3-NEXT: store ptr [[TMP28]], ptr [[TMP33]], align 4 // CHECK3-NEXT: [[TMP34:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 5 -// CHECK3-NEXT: store ptr @.offload_maptypes.14, ptr [[TMP34]], align 4 +// CHECK3-NEXT: store ptr @.offload_maptypes.16, ptr [[TMP34]], align 4 // CHECK3-NEXT: [[TMP35:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 6 // CHECK3-NEXT: store ptr null, ptr [[TMP35]], align 4 // CHECK3-NEXT: [[TMP36:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 7 @@ -2892,16 +3098,16 @@ int bar(int n){ // CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP40]], align 4 // CHECK3-NEXT: [[TMP41:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12 // CHECK3-NEXT: store i32 0, ptr [[TMP41]], align 4 -// CHECK3-NEXT: [[TMP42:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227.region_id, ptr [[KERNEL_ARGS]]) +// CHECK3-NEXT: [[TMP42:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233.region_id, ptr [[KERNEL_ARGS]]) // CHECK3-NEXT: [[TMP43:%.*]] = icmp ne i32 [[TMP42]], 0 // CHECK3-NEXT: br i1 [[TMP43]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]] // CHECK3: omp_offload.failed: -// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227(ptr [[THIS1]], i32 [[TMP5]], i32 2, i32 [[TMP1]], ptr [[VLA]]) #[[ATTR3]] +// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233(ptr [[THIS1]], i32 [[TMP5]], i32 2, i32 [[TMP1]], ptr [[VLA]]) #[[ATTR3]] // CHECK3-NEXT: br label [[OMP_OFFLOAD_CONT]] // CHECK3: omp_offload.cont: // CHECK3-NEXT: br label [[OMP_IF_END:%.*]] // CHECK3: omp_if.else: -// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227(ptr [[THIS1]], i32 [[TMP5]], i32 2, i32 [[TMP1]], ptr [[VLA]]) #[[ATTR3]] +// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233(ptr [[THIS1]], i32 [[TMP5]], i32 2, i32 [[TMP1]], ptr [[VLA]]) #[[ATTR3]] // CHECK3-NEXT: br label [[OMP_IF_END]] // CHECK3: omp_if.end: // CHECK3-NEXT: [[TMP44:%.*]] = mul nsw i32 1, [[TMP1]] @@ -2983,9 +3189,9 @@ int bar(int n){ // CHECK3-NEXT: [[TMP24:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 3 // CHECK3-NEXT: store ptr [[TMP20]], ptr [[TMP24]], align 4 // CHECK3-NEXT: [[TMP25:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 4 -// CHECK3-NEXT: store ptr @.offload_sizes.15, ptr [[TMP25]], align 4 +// CHECK3-NEXT: store ptr @.offload_sizes.17, ptr [[TMP25]], align 4 // CHECK3-NEXT: [[TMP26:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 5 -// CHECK3-NEXT: store ptr @.offload_maptypes.16, ptr [[TMP26]], align 4 +// CHECK3-NEXT: store ptr @.offload_maptypes.18, ptr [[TMP26]], align 4 // CHECK3-NEXT: [[TMP27:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 6 // CHECK3-NEXT: store ptr null, ptr [[TMP27]], align 4 // CHECK3-NEXT: [[TMP28:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 7 @@ -3000,16 +3206,16 @@ int bar(int n){ // CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP32]], align 4 // CHECK3-NEXT: [[TMP33:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12 // CHECK3-NEXT: store i32 0, ptr [[TMP33]], align 4 -// CHECK3-NEXT: [[TMP34:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209.region_id, ptr [[KERNEL_ARGS]]) +// CHECK3-NEXT: [[TMP34:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215.region_id, ptr [[KERNEL_ARGS]]) // CHECK3-NEXT: [[TMP35:%.*]] = icmp ne i32 [[TMP34]], 0 // CHECK3-NEXT: br i1 [[TMP35]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]] // CHECK3: omp_offload.failed: -// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209(i32 [[TMP1]], i32 [[TMP3]], i32 [[TMP5]], ptr [[B]]) #[[ATTR3]] +// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215(i32 [[TMP1]], i32 [[TMP3]], i32 [[TMP5]], ptr [[B]]) #[[ATTR3]] // CHECK3-NEXT: br label [[OMP_OFFLOAD_CONT]] // CHECK3: omp_offload.cont: // CHECK3-NEXT: br label [[OMP_IF_END:%.*]] // CHECK3: omp_if.else: -// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209(i32 [[TMP1]], i32 [[TMP3]], i32 [[TMP5]], ptr [[B]]) #[[ATTR3]] +// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215(i32 [[TMP1]], i32 [[TMP3]], i32 [[TMP5]], ptr [[B]]) #[[ATTR3]] // CHECK3-NEXT: br label [[OMP_IF_END]] // CHECK3: omp_if.end: // CHECK3-NEXT: [[TMP36:%.*]] = load i32, ptr [[A]], align 4 @@ -3071,9 +3277,9 @@ int bar(int n){ // CHECK3-NEXT: [[TMP19:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 3 // CHECK3-NEXT: store ptr [[TMP15]], ptr [[TMP19]], align 4 // CHECK3-NEXT: [[TMP20:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 4 -// CHECK3-NEXT: store ptr @.offload_sizes.17, ptr [[TMP20]], align 4 +// CHECK3-NEXT: store ptr @.offload_sizes.19, ptr [[TMP20]], align 4 // CHECK3-NEXT: [[TMP21:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 5 -// CHECK3-NEXT: store ptr @.offload_maptypes.18, ptr [[TMP21]], align 4 +// CHECK3-NEXT: store ptr @.offload_maptypes.20, ptr [[TMP21]], align 4 // CHECK3-NEXT: [[TMP22:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 6 // CHECK3-NEXT: store ptr null, ptr [[TMP22]], align 4 // CHECK3-NEXT: [[TMP23:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 7 @@ -3088,23 +3294,23 @@ int bar(int n){ // CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP27]], align 4 // CHECK3-NEXT: [[TMP28:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12 // CHECK3-NEXT: store i32 0, ptr [[TMP28]], align 4 -// CHECK3-NEXT: [[TMP29:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192.region_id, ptr [[KERNEL_ARGS]]) +// CHECK3-NEXT: [[TMP29:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198.region_id, ptr [[KERNEL_ARGS]]) // CHECK3-NEXT: [[TMP30:%.*]] = icmp ne i32 [[TMP29]], 0 // CHECK3-NEXT: br i1 [[TMP30]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]] // CHECK3: omp_offload.failed: -// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192(i32 [[TMP1]], i32 [[TMP3]], ptr [[B]]) #[[ATTR3]] +// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198(i32 [[TMP1]], i32 [[TMP3]], ptr [[B]]) #[[ATTR3]] // CHECK3-NEXT: br label [[OMP_OFFLOAD_CONT]] // CHECK3: omp_offload.cont: // CHECK3-NEXT: br label [[OMP_IF_END:%.*]] // CHECK3: omp_if.else: -// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192(i32 [[TMP1]], i32 [[TMP3]], ptr [[B]]) #[[ATTR3]] +// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198(i32 [[TMP1]], i32 [[TMP3]], ptr [[B]]) #[[ATTR3]] // CHECK3-NEXT: br label [[OMP_IF_END]] // CHECK3: omp_if.end: // CHECK3-NEXT: [[TMP31:%.*]] = load i32, ptr [[A]], align 4 // CHECK3-NEXT: ret i32 [[TMP31]] // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227 +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233 // CHECK3-SAME: (ptr noundef [[THIS:%.*]], i32 noundef [[B:%.*]], i32 noundef [[VLA:%.*]], i32 noundef [[VLA1:%.*]], ptr noundef nonnull align 2 dereferenceable(2) [[C:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 4 @@ -3125,11 +3331,11 @@ int bar(int n){ // CHECK3-NEXT: [[TMP4:%.*]] = load i32, ptr [[B_ADDR]], align 4 // CHECK3-NEXT: store i32 [[TMP4]], ptr [[B_CASTED]], align 4 // CHECK3-NEXT: [[TMP5:%.*]] = load i32, ptr [[B_CASTED]], align 4 -// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227.omp_outlined, ptr [[TMP0]], i32 [[TMP5]], i32 [[TMP1]], i32 [[TMP2]], ptr [[TMP3]]) +// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233.omp_outlined, ptr [[TMP0]], i32 [[TMP5]], i32 [[TMP1]], i32 [[TMP2]], ptr [[TMP3]]) // CHECK3-NEXT: ret void // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227.omp_outlined +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233.omp_outlined // CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], ptr noundef [[THIS:%.*]], i32 noundef [[B:%.*]], i32 noundef [[VLA:%.*]], i32 noundef [[VLA1:%.*]], ptr noundef nonnull align 2 dereferenceable(2) [[C:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -3167,7 +3373,7 @@ int bar(int n){ // CHECK3-NEXT: ret void // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209 +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215 // CHECK3-SAME: (i32 noundef [[A:%.*]], i32 noundef [[AA:%.*]], i32 noundef [[AAA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 @@ -3191,11 +3397,11 @@ int bar(int n){ // CHECK3-NEXT: [[TMP5:%.*]] = load i8, ptr [[AAA_ADDR]], align 1 // CHECK3-NEXT: store i8 [[TMP5]], ptr [[AAA_CASTED]], align 1 // CHECK3-NEXT: [[TMP6:%.*]] = load i32, ptr [[AAA_CASTED]], align 4 -// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 4, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209.omp_outlined, i32 [[TMP2]], i32 [[TMP4]], i32 [[TMP6]], ptr [[TMP0]]) +// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 4, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215.omp_outlined, i32 [[TMP2]], i32 [[TMP4]], i32 [[TMP6]], ptr [[TMP0]]) // CHECK3-NEXT: ret void // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209.omp_outlined +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215.omp_outlined // CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[A:%.*]], i32 noundef [[AA:%.*]], i32 noundef [[AAA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -3231,7 +3437,7 @@ int bar(int n){ // CHECK3-NEXT: ret void // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192 +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198 // CHECK3-SAME: (i32 noundef [[A:%.*]], i32 noundef [[AA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 @@ -3249,11 +3455,11 @@ int bar(int n){ // CHECK3-NEXT: [[TMP3:%.*]] = load i16, ptr [[AA_ADDR]], align 2 // CHECK3-NEXT: store i16 [[TMP3]], ptr [[AA_CASTED]], align 2 // CHECK3-NEXT: [[TMP4:%.*]] = load i32, ptr [[AA_CASTED]], align 4 -// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192.omp_outlined, i32 [[TMP2]], i32 [[TMP4]], ptr [[TMP0]]) +// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198.omp_outlined, i32 [[TMP2]], i32 [[TMP4]], ptr [[TMP0]]) // CHECK3-NEXT: ret void // // -// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192.omp_outlined +// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198.omp_outlined // CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[A:%.*]], i32 noundef [[AA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR2]] { // CHECK3-NEXT: entry: // CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -3393,7 +3599,48 @@ int bar(int n){ // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142 +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124 +// CHECK9-SAME: (i64 noundef [[A:%.*]], i64 noundef [[AA:%.*]]) #[[ATTR0]] { +// CHECK9-NEXT: entry: +// CHECK9-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 +// CHECK9-NEXT: [[AA_ADDR:%.*]] = alloca i64, align 8 +// CHECK9-NEXT: [[A_CASTED:%.*]] = alloca i64, align 8 +// CHECK9-NEXT: [[AA_CASTED:%.*]] = alloca i64, align 8 +// CHECK9-NEXT: store i64 [[A]], ptr [[A_ADDR]], align 8 +// CHECK9-NEXT: store i64 [[AA]], ptr [[AA_ADDR]], align 8 +// CHECK9-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK9-NEXT: store i32 [[TMP0]], ptr [[A_CASTED]], align 4 +// CHECK9-NEXT: [[TMP1:%.*]] = load i64, ptr [[A_CASTED]], align 8 +// CHECK9-NEXT: [[TMP2:%.*]] = load i16, ptr [[AA_ADDR]], align 2 +// CHECK9-NEXT: store i16 [[TMP2]], ptr [[AA_CASTED]], align 2 +// CHECK9-NEXT: [[TMP3:%.*]] = load i64, ptr [[AA_CASTED]], align 8 +// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124.omp_outlined, i64 [[TMP1]], i64 [[TMP3]]) +// CHECK9-NEXT: ret void +// +// +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124.omp_outlined +// CHECK9-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[A:%.*]], i64 noundef [[AA:%.*]]) #[[ATTR0]] { +// CHECK9-NEXT: entry: +// CHECK9-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 +// CHECK9-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8 +// CHECK9-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 +// CHECK9-NEXT: [[AA_ADDR:%.*]] = alloca i64, align 8 +// CHECK9-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8 +// CHECK9-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8 +// CHECK9-NEXT: store i64 [[A]], ptr [[A_ADDR]], align 8 +// CHECK9-NEXT: store i64 [[AA]], ptr [[AA_ADDR]], align 8 +// CHECK9-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK9-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], 1 +// CHECK9-NEXT: store i32 [[ADD]], ptr [[A_ADDR]], align 4 +// CHECK9-NEXT: [[TMP1:%.*]] = load i16, ptr [[AA_ADDR]], align 2 +// CHECK9-NEXT: [[CONV:%.*]] = sext i16 [[TMP1]] to i32 +// CHECK9-NEXT: [[ADD1:%.*]] = add nsw i32 [[CONV]], 1 +// CHECK9-NEXT: [[CONV2:%.*]] = trunc i32 [[ADD1]] to i16 +// CHECK9-NEXT: store i16 [[CONV2]], ptr [[AA_ADDR]], align 2 +// CHECK9-NEXT: ret void +// +// +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148 // CHECK9-SAME: (i64 noundef [[A:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[BN:%.*]], ptr noundef nonnull align 8 dereferenceable(400) [[C:%.*]], i64 noundef [[VLA1:%.*]], i64 noundef [[VLA3:%.*]], ptr noundef nonnull align 8 dereferenceable(8) [[CN:%.*]], ptr noundef nonnull align 8 dereferenceable(16) [[D:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 @@ -3426,11 +3673,11 @@ int bar(int n){ // CHECK9-NEXT: [[TMP8:%.*]] = load i32, ptr [[A_ADDR]], align 4 // CHECK9-NEXT: store i32 [[TMP8]], ptr [[A_CASTED]], align 4 // CHECK9-NEXT: [[TMP9:%.*]] = load i64, ptr [[A_CASTED]], align 8 -// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 9, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142.omp_outlined, i64 [[TMP9]], ptr [[TMP0]], i64 [[TMP1]], ptr [[TMP2]], ptr [[TMP3]], i64 [[TMP4]], i64 [[TMP5]], ptr [[TMP6]], ptr [[TMP7]]) +// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 9, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148.omp_outlined, i64 [[TMP9]], ptr [[TMP0]], i64 [[TMP1]], ptr [[TMP2]], ptr [[TMP3]], i64 [[TMP4]], i64 [[TMP5]], ptr [[TMP6]], ptr [[TMP7]]) // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142.omp_outlined +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148.omp_outlined // CHECK9-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[A:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[BN:%.*]], ptr noundef nonnull align 8 dereferenceable(400) [[C:%.*]], i64 noundef [[VLA1:%.*]], i64 noundef [[VLA3:%.*]], ptr noundef nonnull align 8 dereferenceable(8) [[CN:%.*]], ptr noundef nonnull align 8 dereferenceable(16) [[D:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -3502,7 +3749,7 @@ int bar(int n){ // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154 +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160 // CHECK9-SAME: (i64 noundef [[NN:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[NN_ADDR:%.*]] = alloca i64, align 8 @@ -3511,11 +3758,11 @@ int bar(int n){ // CHECK9-NEXT: [[TMP0:%.*]] = load i32, ptr [[NN_ADDR]], align 4 // CHECK9-NEXT: store i32 [[TMP0]], ptr [[NN_CASTED]], align 4 // CHECK9-NEXT: [[TMP1:%.*]] = load i64, ptr [[NN_CASTED]], align 8 -// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined, i64 [[TMP1]]) +// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined, i64 [[TMP1]]) // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined // CHECK9-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[NN:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -3528,11 +3775,11 @@ int bar(int n){ // CHECK9-NEXT: [[TMP0:%.*]] = load i32, ptr [[NN_ADDR]], align 4 // CHECK9-NEXT: store i32 [[TMP0]], ptr [[NN_CASTED]], align 4 // CHECK9-NEXT: [[TMP1:%.*]] = load i64, ptr [[NN_CASTED]], align 8 -// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined.omp_outlined, i64 [[TMP1]]) +// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined.omp_outlined, i64 [[TMP1]]) // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined.omp_outlined +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined.omp_outlined // CHECK9-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[NN:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -3544,7 +3791,7 @@ int bar(int n){ // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157 +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163 // CHECK9-SAME: (i64 noundef [[NN:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[NN_ADDR:%.*]] = alloca i64, align 8 @@ -3553,11 +3800,11 @@ int bar(int n){ // CHECK9-NEXT: [[TMP0:%.*]] = load i32, ptr [[NN_ADDR]], align 4 // CHECK9-NEXT: store i32 [[TMP0]], ptr [[NN_CASTED]], align 4 // CHECK9-NEXT: [[TMP1:%.*]] = load i64, ptr [[NN_CASTED]], align 8 -// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined, i64 [[TMP1]]) +// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined, i64 [[TMP1]]) // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined // CHECK9-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[NN:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -3566,11 +3813,11 @@ int bar(int n){ // CHECK9-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8 // CHECK9-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8 // CHECK9-NEXT: store i64 [[NN]], ptr [[NN_ADDR]], align 8 -// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined.omp_outlined, ptr [[NN_ADDR]]) +// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined.omp_outlined, ptr [[NN_ADDR]]) // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined.omp_outlined +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined.omp_outlined // CHECK9-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[NN:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -3583,17 +3830,17 @@ int bar(int n){ // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182 +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188 // CHECK9-SAME: (i64 noundef [[VLA:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8 // CHECK9-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8 // CHECK9-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8 -// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182.omp_outlined, i64 [[TMP0]]) +// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188.omp_outlined, i64 [[TMP0]]) // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182.omp_outlined +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188.omp_outlined // CHECK9-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[VLA:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -3607,7 +3854,7 @@ int bar(int n){ // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209 +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215 // CHECK9-SAME: (i64 noundef [[A:%.*]], i64 noundef [[AA:%.*]], i64 noundef [[AAA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 @@ -3631,11 +3878,11 @@ int bar(int n){ // CHECK9-NEXT: [[TMP5:%.*]] = load i8, ptr [[AAA_ADDR]], align 1 // CHECK9-NEXT: store i8 [[TMP5]], ptr [[AAA_CASTED]], align 1 // CHECK9-NEXT: [[TMP6:%.*]] = load i64, ptr [[AAA_CASTED]], align 8 -// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 4, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209.omp_outlined, i64 [[TMP2]], i64 [[TMP4]], i64 [[TMP6]], ptr [[TMP0]]) +// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 4, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215.omp_outlined, i64 [[TMP2]], i64 [[TMP4]], i64 [[TMP6]], ptr [[TMP0]]) // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209.omp_outlined +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215.omp_outlined // CHECK9-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[A:%.*]], i64 noundef [[AA:%.*]], i64 noundef [[AAA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -3671,7 +3918,7 @@ int bar(int n){ // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227 +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233 // CHECK9-SAME: (ptr noundef [[THIS:%.*]], i64 noundef [[B:%.*]], i64 noundef [[VLA:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 2 dereferenceable(2) [[C:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 @@ -3692,11 +3939,11 @@ int bar(int n){ // CHECK9-NEXT: [[TMP4:%.*]] = load i32, ptr [[B_ADDR]], align 4 // CHECK9-NEXT: store i32 [[TMP4]], ptr [[B_CASTED]], align 4 // CHECK9-NEXT: [[TMP5:%.*]] = load i64, ptr [[B_CASTED]], align 8 -// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227.omp_outlined, ptr [[TMP0]], i64 [[TMP5]], i64 [[TMP1]], i64 [[TMP2]], ptr [[TMP3]]) +// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233.omp_outlined, ptr [[TMP0]], i64 [[TMP5]], i64 [[TMP1]], i64 [[TMP2]], ptr [[TMP3]]) // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227.omp_outlined +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233.omp_outlined // CHECK9-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], ptr noundef [[THIS:%.*]], i64 noundef [[B:%.*]], i64 noundef [[VLA:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 2 dereferenceable(2) [[C:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -3734,7 +3981,7 @@ int bar(int n){ // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192 +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198 // CHECK9-SAME: (i64 noundef [[A:%.*]], i64 noundef [[AA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 @@ -3752,11 +3999,11 @@ int bar(int n){ // CHECK9-NEXT: [[TMP3:%.*]] = load i16, ptr [[AA_ADDR]], align 2 // CHECK9-NEXT: store i16 [[TMP3]], ptr [[AA_CASTED]], align 2 // CHECK9-NEXT: [[TMP4:%.*]] = load i64, ptr [[AA_CASTED]], align 8 -// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192.omp_outlined, i64 [[TMP2]], i64 [[TMP4]], ptr [[TMP0]]) +// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198.omp_outlined, i64 [[TMP2]], i64 [[TMP4]], ptr [[TMP0]]) // CHECK9-NEXT: ret void // // -// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192.omp_outlined +// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198.omp_outlined // CHECK9-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[A:%.*]], i64 noundef [[AA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR0]] { // CHECK9-NEXT: entry: // CHECK9-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 @@ -3889,7 +4136,48 @@ int bar(int n){ // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142 +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124 +// CHECK11-SAME: (i32 noundef [[A:%.*]], i32 noundef [[AA:%.*]]) #[[ATTR0]] { +// CHECK11-NEXT: entry: +// CHECK11-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK11-NEXT: [[AA_ADDR:%.*]] = alloca i32, align 4 +// CHECK11-NEXT: [[A_CASTED:%.*]] = alloca i32, align 4 +// CHECK11-NEXT: [[AA_CASTED:%.*]] = alloca i32, align 4 +// CHECK11-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4 +// CHECK11-NEXT: store i32 [[AA]], ptr [[AA_ADDR]], align 4 +// CHECK11-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK11-NEXT: store i32 [[TMP0]], ptr [[A_CASTED]], align 4 +// CHECK11-NEXT: [[TMP1:%.*]] = load i32, ptr [[A_CASTED]], align 4 +// CHECK11-NEXT: [[TMP2:%.*]] = load i16, ptr [[AA_ADDR]], align 2 +// CHECK11-NEXT: store i16 [[TMP2]], ptr [[AA_CASTED]], align 2 +// CHECK11-NEXT: [[TMP3:%.*]] = load i32, ptr [[AA_CASTED]], align 4 +// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124.omp_outlined, i32 [[TMP1]], i32 [[TMP3]]) +// CHECK11-NEXT: ret void +// +// +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l124.omp_outlined +// CHECK11-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[A:%.*]], i32 noundef [[AA:%.*]]) #[[ATTR0]] { +// CHECK11-NEXT: entry: +// CHECK11-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 +// CHECK11-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4 +// CHECK11-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK11-NEXT: [[AA_ADDR:%.*]] = alloca i32, align 4 +// CHECK11-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4 +// CHECK11-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4 +// CHECK11-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4 +// CHECK11-NEXT: store i32 [[AA]], ptr [[AA_ADDR]], align 4 +// CHECK11-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK11-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], 1 +// CHECK11-NEXT: store i32 [[ADD]], ptr [[A_ADDR]], align 4 +// CHECK11-NEXT: [[TMP1:%.*]] = load i16, ptr [[AA_ADDR]], align 2 +// CHECK11-NEXT: [[CONV:%.*]] = sext i16 [[TMP1]] to i32 +// CHECK11-NEXT: [[ADD1:%.*]] = add nsw i32 [[CONV]], 1 +// CHECK11-NEXT: [[CONV2:%.*]] = trunc i32 [[ADD1]] to i16 +// CHECK11-NEXT: store i16 [[CONV2]], ptr [[AA_ADDR]], align 2 +// CHECK11-NEXT: ret void +// +// +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148 // CHECK11-SAME: (i32 noundef [[A:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]], i32 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[BN:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[C:%.*]], i32 noundef [[VLA1:%.*]], i32 noundef [[VLA3:%.*]], ptr noundef nonnull align 4 dereferenceable(8) [[CN:%.*]], ptr noundef nonnull align 4 dereferenceable(12) [[D:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 @@ -3922,11 +4210,11 @@ int bar(int n){ // CHECK11-NEXT: [[TMP8:%.*]] = load i32, ptr [[A_ADDR]], align 4 // CHECK11-NEXT: store i32 [[TMP8]], ptr [[A_CASTED]], align 4 // CHECK11-NEXT: [[TMP9:%.*]] = load i32, ptr [[A_CASTED]], align 4 -// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 9, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142.omp_outlined, i32 [[TMP9]], ptr [[TMP0]], i32 [[TMP1]], ptr [[TMP2]], ptr [[TMP3]], i32 [[TMP4]], i32 [[TMP5]], ptr [[TMP6]], ptr [[TMP7]]) +// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 9, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148.omp_outlined, i32 [[TMP9]], ptr [[TMP0]], i32 [[TMP1]], ptr [[TMP2]], ptr [[TMP3]], i32 [[TMP4]], i32 [[TMP5]], ptr [[TMP6]], ptr [[TMP7]]) // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l142.omp_outlined +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l148.omp_outlined // CHECK11-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[A:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]], i32 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[BN:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[C:%.*]], i32 noundef [[VLA1:%.*]], i32 noundef [[VLA3:%.*]], ptr noundef nonnull align 4 dereferenceable(8) [[CN:%.*]], ptr noundef nonnull align 4 dereferenceable(12) [[D:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -3998,7 +4286,7 @@ int bar(int n){ // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154 +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160 // CHECK11-SAME: (i32 noundef [[NN:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[NN_ADDR:%.*]] = alloca i32, align 4 @@ -4007,11 +4295,11 @@ int bar(int n){ // CHECK11-NEXT: [[TMP0:%.*]] = load i32, ptr [[NN_ADDR]], align 4 // CHECK11-NEXT: store i32 [[TMP0]], ptr [[NN_CASTED]], align 4 // CHECK11-NEXT: [[TMP1:%.*]] = load i32, ptr [[NN_CASTED]], align 4 -// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined, i32 [[TMP1]]) +// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined, i32 [[TMP1]]) // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined // CHECK11-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[NN:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -4024,11 +4312,11 @@ int bar(int n){ // CHECK11-NEXT: [[TMP0:%.*]] = load i32, ptr [[NN_ADDR]], align 4 // CHECK11-NEXT: store i32 [[TMP0]], ptr [[NN_CASTED]], align 4 // CHECK11-NEXT: [[TMP1:%.*]] = load i32, ptr [[NN_CASTED]], align 4 -// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined.omp_outlined, i32 [[TMP1]]) +// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined.omp_outlined, i32 [[TMP1]]) // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l154.omp_outlined.omp_outlined +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l160.omp_outlined.omp_outlined // CHECK11-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[NN:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -4040,7 +4328,7 @@ int bar(int n){ // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157 +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163 // CHECK11-SAME: (i32 noundef [[NN:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[NN_ADDR:%.*]] = alloca i32, align 4 @@ -4049,11 +4337,11 @@ int bar(int n){ // CHECK11-NEXT: [[TMP0:%.*]] = load i32, ptr [[NN_ADDR]], align 4 // CHECK11-NEXT: store i32 [[TMP0]], ptr [[NN_CASTED]], align 4 // CHECK11-NEXT: [[TMP1:%.*]] = load i32, ptr [[NN_CASTED]], align 4 -// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined, i32 [[TMP1]]) +// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined, i32 [[TMP1]]) // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined // CHECK11-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[NN:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -4062,11 +4350,11 @@ int bar(int n){ // CHECK11-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4 // CHECK11-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4 // CHECK11-NEXT: store i32 [[NN]], ptr [[NN_ADDR]], align 4 -// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined.omp_outlined, ptr [[NN_ADDR]]) +// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined.omp_outlined, ptr [[NN_ADDR]]) // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l157.omp_outlined.omp_outlined +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3fooi_l163.omp_outlined.omp_outlined // CHECK11-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[NN:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -4079,17 +4367,17 @@ int bar(int n){ // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182 +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188 // CHECK11-SAME: (i32 noundef [[VLA:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[VLA_ADDR:%.*]] = alloca i32, align 4 // CHECK11-NEXT: store i32 [[VLA]], ptr [[VLA_ADDR]], align 4 // CHECK11-NEXT: [[TMP0:%.*]] = load i32, ptr [[VLA_ADDR]], align 4 -// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182.omp_outlined, i32 [[TMP0]]) +// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188.omp_outlined, i32 [[TMP0]]) // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l182.omp_outlined +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z6bazzzziPi_l188.omp_outlined // CHECK11-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[VLA:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -4103,7 +4391,7 @@ int bar(int n){ // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209 +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215 // CHECK11-SAME: (i32 noundef [[A:%.*]], i32 noundef [[AA:%.*]], i32 noundef [[AAA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 @@ -4127,11 +4415,11 @@ int bar(int n){ // CHECK11-NEXT: [[TMP5:%.*]] = load i8, ptr [[AAA_ADDR]], align 1 // CHECK11-NEXT: store i8 [[TMP5]], ptr [[AAA_CASTED]], align 1 // CHECK11-NEXT: [[TMP6:%.*]] = load i32, ptr [[AAA_CASTED]], align 4 -// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 4, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209.omp_outlined, i32 [[TMP2]], i32 [[TMP4]], i32 [[TMP6]], ptr [[TMP0]]) +// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 4, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215.omp_outlined, i32 [[TMP2]], i32 [[TMP4]], i32 [[TMP6]], ptr [[TMP0]]) // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l209.omp_outlined +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZL7fstatici_l215.omp_outlined // CHECK11-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[A:%.*]], i32 noundef [[AA:%.*]], i32 noundef [[AAA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -4167,7 +4455,7 @@ int bar(int n){ // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227 +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233 // CHECK11-SAME: (ptr noundef [[THIS:%.*]], i32 noundef [[B:%.*]], i32 noundef [[VLA:%.*]], i32 noundef [[VLA1:%.*]], ptr noundef nonnull align 2 dereferenceable(2) [[C:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 4 @@ -4188,11 +4476,11 @@ int bar(int n){ // CHECK11-NEXT: [[TMP4:%.*]] = load i32, ptr [[B_ADDR]], align 4 // CHECK11-NEXT: store i32 [[TMP4]], ptr [[B_CASTED]], align 4 // CHECK11-NEXT: [[TMP5:%.*]] = load i32, ptr [[B_CASTED]], align 4 -// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227.omp_outlined, ptr [[TMP0]], i32 [[TMP5]], i32 [[TMP1]], i32 [[TMP2]], ptr [[TMP3]]) +// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233.omp_outlined, ptr [[TMP0]], i32 [[TMP5]], i32 [[TMP1]], i32 [[TMP2]], ptr [[TMP3]]) // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l227.omp_outlined +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2S12r1Ei_l233.omp_outlined // CHECK11-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], ptr noundef [[THIS:%.*]], i32 noundef [[B:%.*]], i32 noundef [[VLA:%.*]], i32 noundef [[VLA1:%.*]], ptr noundef nonnull align 2 dereferenceable(2) [[C:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 @@ -4230,7 +4518,7 @@ int bar(int n){ // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192 +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198 // CHECK11-SAME: (i32 noundef [[A:%.*]], i32 noundef [[AA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 @@ -4248,11 +4536,11 @@ int bar(int n){ // CHECK11-NEXT: [[TMP3:%.*]] = load i16, ptr [[AA_ADDR]], align 2 // CHECK11-NEXT: store i16 [[TMP3]], ptr [[AA_CASTED]], align 2 // CHECK11-NEXT: [[TMP4:%.*]] = load i32, ptr [[AA_CASTED]], align 4 -// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192.omp_outlined, i32 [[TMP2]], i32 [[TMP4]], ptr [[TMP0]]) +// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB1]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198.omp_outlined, i32 [[TMP2]], i32 [[TMP4]], ptr [[TMP0]]) // CHECK11-NEXT: ret void // // -// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l192.omp_outlined +// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l198.omp_outlined // CHECK11-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[A:%.*]], i32 noundef [[AA:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR0]] { // CHECK11-NEXT: entry: // CHECK11-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4 diff --git a/clang/test/OpenMP/target_visibility.cpp b/clang/test/OpenMP/target_visibility.cpp index 938d164df89bf..2554f653170b9 100644 --- a/clang/test/OpenMP/target_visibility.cpp +++ b/clang/test/OpenMP/target_visibility.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -debug-info-kind=limited -verify -fopenmp -x c++ -triple nvptx64-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-target-device -o - | FileCheck %s -// RUN: %clang_cc1 -debug-info-kind=limited -verify -fopenmp -x c++ -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-target-device -o - | FileCheck %s +// RUN: %clang_cc1 -debug-info-kind=limited -verify -fopenmp -x c++ -triple amdgcn-amd-amdhsa -fopenmp-targets=amdgcn-amd-amdhsa -emit-llvm %s -fopenmp-is-target-device -o - | FileCheck %s // expected-no-diagnostics @@ -21,6 +21,14 @@ void B::bar() { A a; a.foo(); } void B::sbar() { A::sfoo(); } #pragma omp declare target to(B::bar, B::sbar) +[[gnu::visibility("hidden")]] extern const int x = 0; +#pragma omp declare target to(x) device_type(nohost) + +[[gnu::visibility("hidden")]] int y = 0; +#pragma omp declare target to(y) + +// CHECK-DAG: @x = hidden{{.*}} constant i32 0 +// CHECK-DAG: @y = protected{{.*}} i32 0 // CHECK-DAG: define hidden void @_ZN1B4sbarEv() // CHECK-DAG: define linkonce_odr hidden void @_ZN1A4sfooEv() // CHECK-DAG: define hidden void @_ZN1B3barEv( diff --git a/clang/test/Parser/c2x-auto.c b/clang/test/Parser/c2x-auto.c new file mode 100644 index 0000000000000..b878a5b7c42d4 --- /dev/null +++ b/clang/test/Parser/c2x-auto.c @@ -0,0 +1,132 @@ +// RUN: %clang_cc1 -fsyntax-only -verify=expected,c23 -std=c23 %s +// RUN: %clang_cc1 -fsyntax-only -verify=expected,c17 -std=c17 %s + +#define AUTO_MACRO(_NAME, ARG, ARG2, ARG3) \ +auto _NAME = ARG + (ARG2 / ARG3); + +struct S { + int a; + auto b; // c23-error {{'auto' not allowed in struct member}} \ + c17-error {{type name does not allow storage class to be specified}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + union { + char c; + auto smth; // c23-error {{'auto' not allowed in union member}} \ + c17-error {{type name does not allow storage class to be specified}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + } u; +}; + +enum E : auto { // c23-error {{'auto' not allowed here}} \ + c17-error {{expected a type}} \ + c17-error {{type name does not allow storage class to be specified}} + One, + Two, + Tree, +}; + +auto basic_usage(auto auto) { // c23-error {{'auto' not allowed in function prototype}} \ + c23-error {{'auto' not allowed in function return type}} \ + c23-error {{cannot combine with previous 'auto' declaration specifier}} \ + c17-error {{invalid storage class specifier in function declarator}} \ + c17-error {{illegal storage class on function}} \ + c17-warning {{duplicate 'auto' declaration specifier}} \ + c17-warning {{omitting the parameter name in a function definition is a C23 extension}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + auto = 4; // expected-error {{expected identifier or '('}} + + auto a = 4; // c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + auto auto aa = 12; // c23-error {{cannot combine with previous 'auto' declaration specifier}} \ + c17-warning {{duplicate 'auto' declaration specifier}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + auto b[4]; // c23-error {{'auto' not allowed in array declaration}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + auto array[auto]; // expected-error {{expected expression}} \ + c23-error {{declaration of variable 'array' with deduced type 'auto' requires an initializer}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + AUTO_MACRO(auto, 1, 2, 3); // c23-error {{cannot combine with previous 'auto' declaration specifier}} \ + expected-error {{expected identifier or '('}} \ + c17-warning {{duplicate 'auto' declaration specifier}} + + auto c = (auto)a; // expected-error {{expected expression}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + auto ci = (auto){12}; // expected-error {{expected expression}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + int auto_cxx_decl = auto(0); // expected-error {{expected expression}} + + return c; +} + +void structs(void) { + struct s_auto { auto a; }; // c23-error {{'auto' not allowed in struct member}} \ + c17-error {{type name does not allow storage class to be specified}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + // FIXME: this should end up being rejected when we implement underspecified + // declarations in N3006. + auto s_int = (struct { int a; } *)0; // c17-error {{incompatible pointer to integer conversion initializing 'int' with an expression of type}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + typedef auto auto_type; // c23-error {{'auto' not allowed in typedef}} \ + c17-error {{cannot combine with previous 'typedef' declaration specifier}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} +} + +void sizeof_alignas(void) { + auto auto_size = sizeof(auto); // expected-error {{expected expression}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} +} + +void generic_alignof_alignas(void) { + int g; + _Generic(g, auto : 0); // c23-error {{'auto' not allowed here}} \ + c17-error {{expected a type}} \ + c17-error {{type name does not allow storage class to be specified}} + + _Alignof(auto); // expected-error {{expected expression}} \ + expected-warning {{'_Alignof' applied to an expression is a GNU extension}} + + _Alignas(auto); // expected-error {{expected expression}} \ + expected-warning {{declaration does not declare anything}} +} + +void function_designators(void) { + extern auto auto_ret_func(void); // c23-error {{'auto' not allowed in function return type}} \ + c17-error {{cannot combine with previous 'extern' declaration specifier}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + extern void auto_param_func(auto); // c23-error {{'auto' not allowed in function prototype}} \ + c17-error {{invalid storage class specifier in function declarator}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + auto (auto_ret_func)(void); // c23-error {{'auto' not allowed in function return type}} \ + c17-error {{illegal storage class on function}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + void (auto_param_func)(auto); // c23-error {{'auto' not allowed in function prototype}} \ + c17-error {{invalid storage class specifier in function declarator}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} +} + +void atomic(void) { + _Atomic(auto) atom1 = 12; // c23-error {{'auto' not allowed here}} \ + c23-error {{a type specifier is required for all declarations}} \ + c17-error {{expected a type}} \ + c17-error {{type name does not allow storage class to be specified}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + _Atomic auto atom2 = 12; // c23-error {{_Atomic cannot be applied to type 'auto' in C23}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} +} + +void attributes(void) { + auto ident [[clang::annotate("this works")]] = 12; // c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} +} diff --git a/clang/test/Preprocessor/has_attribute.c b/clang/test/Preprocessor/has_attribute.c index 77787c9b64edb..0ba664a53e649 100644 --- a/clang/test/Preprocessor/has_attribute.c +++ b/clang/test/Preprocessor/has_attribute.c @@ -10,6 +10,11 @@ int always_inline(); int __always_inline__(); #endif +// CHECK: warn_unused_result +#if __has_attribute(warn_unused_result) +int warn_unused_result(); +#endif + // CHECK: no_dummy_attribute #if !__has_attribute(dummy_attribute) int no_dummy_attribute(); diff --git a/clang/test/Preprocessor/has_attribute.cpp b/clang/test/Preprocessor/has_attribute.cpp index 3fb99eda699b3..33546dbb175f6 100644 --- a/clang/test/Preprocessor/has_attribute.cpp +++ b/clang/test/Preprocessor/has_attribute.cpp @@ -3,14 +3,14 @@ #define CXX11(x) x: __has_cpp_attribute(x) -// CHECK: clang::fallthrough: 201603L +// CHECK: clang::fallthrough: 1 CXX11(clang::fallthrough) // CHECK: selectany: 0 CXX11(selectany) // The attribute name can be bracketed with double underscores. -// CHECK: clang::__fallthrough__: 201603L +// CHECK: clang::__fallthrough__: 1 CXX11(clang::__fallthrough__) // The scope cannot be bracketed with double underscores unless it is @@ -18,12 +18,21 @@ CXX11(clang::__fallthrough__) // CHECK: __gsl__::suppress: 0 CXX11(__gsl__::suppress) -// CHECK: _Clang::fallthrough: 201603L +// CHECK: _Clang::fallthrough: 1 CXX11(_Clang::fallthrough) // CHECK: __nodiscard__: 201907L CXX11(__nodiscard__) +// CHECK: warn_unused_result: 0 +CXX11(warn_unused_result) + +// CHECK: gnu::warn_unused_result: 1 +CXX11(gnu::warn_unused_result) + +// CHECK: clang::warn_unused_result: 1 +CXX11(clang::warn_unused_result) + // CHECK: __gnu__::__const__: 1 CXX11(__gnu__::__const__) diff --git a/clang/test/Preprocessor/has_c_attribute.c b/clang/test/Preprocessor/has_c_attribute.c index 2f4fdf1679485..3332571d758c8 100644 --- a/clang/test/Preprocessor/has_c_attribute.c +++ b/clang/test/Preprocessor/has_c_attribute.c @@ -9,6 +9,15 @@ C2x(fallthrough) // CHECK: __nodiscard__: 202003L C2x(__nodiscard__) +// CHECK: warn_unused_result: 0 +C2x(warn_unused_result) + +// CHECK: gnu::warn_unused_result: 1 +C2x(gnu::warn_unused_result) + +// CHECK: clang::warn_unused_result: 0 +C2x(clang::warn_unused_result) + // CHECK: selectany: 0 C2x(selectany); // Known attribute not supported in C mode @@ -27,10 +36,10 @@ C2x(deprecated) // CHECK: maybe_unused: 202106L C2x(maybe_unused) -// CHECK: __gnu__::warn_unused_result: 202003L +// CHECK: __gnu__::warn_unused_result: 1 C2x(__gnu__::warn_unused_result) -// CHECK: gnu::__warn_unused_result__: 202003L +// CHECK: gnu::__warn_unused_result__: 1 C2x(gnu::__warn_unused_result__) // Test that macro expansion of the builtin argument works. diff --git a/clang/test/Preprocessor/init-x86.c b/clang/test/Preprocessor/init-x86.c index 1ee770df0c4a3..58be9b7165717 100644 --- a/clang/test/Preprocessor/init-x86.c +++ b/clang/test/Preprocessor/init-x86.c @@ -1023,21 +1023,6 @@ // X86_64-LINUX:#define __DBL_MIN_EXP__ (-1021) // X86_64-LINUX:#define __DBL_MIN__ 2.2250738585072014e-308 // X86_64-LINUX:#define __DECIMAL_DIG__ __LDBL_DECIMAL_DIG__ -// X86_64-LINUX:#define __FLOAT128__ 1 -// X86_64-LINUX:#define __FLT128_DECIMAL_DIG__ 36 -// X86_64-LINUX:#define __FLT128_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966Q -// X86_64-LINUX:#define __FLT128_DIG__ 33 -// X86_64-LINUX:#define __FLT128_EPSILON__ 1.92592994438723585305597794258492732e-34Q -// X86_64-LINUX:#define __FLT128_HAS_DENORM__ 1 -// X86_64-LINUX:#define __FLT128_HAS_INFINITY__ 1 -// X86_64-LINUX:#define __FLT128_HAS_QUIET_NAN__ 1 -// X86_64-LINUX:#define __FLT128_MANT_DIG__ 113 -// X86_64-LINUX:#define __FLT128_MAX_10_EXP__ 4932 -// X86_64-LINUX:#define __FLT128_MAX_EXP__ 16384 -// X86_64-LINUX:#define __FLT128_MAX__ 1.18973149535723176508575932662800702e+4932Q -// X86_64-LINUX:#define __FLT128_MIN_10_EXP__ (-4931) -// X86_64-LINUX:#define __FLT128_MIN_EXP__ (-16381) -// X86_64-LINUX:#define __FLT128_MIN__ 3.36210314311209350626267781732175260e-4932Q // X86_64-LINUX:#define __FLT_DENORM_MIN__ 1.40129846e-45F // X86_64-LINUX:#define __FLT_DIG__ 6 // X86_64-LINUX:#define __FLT_EPSILON__ 1.19209290e-7F diff --git a/clang/test/Preprocessor/init.c b/clang/test/Preprocessor/init.c index 395c4cebfa5be..59c5122afe1e4 100644 --- a/clang/test/Preprocessor/init.c +++ b/clang/test/Preprocessor/init.c @@ -1576,20 +1576,6 @@ // EMSCRIPTEN-NEXT:#define __EMSCRIPTEN__ 1 // WEBASSEMBLY-NEXT:#define __FINITE_MATH_ONLY__ 0 // WEBASSEMBLY-NEXT:#define __FLOAT128__ 1 -// WEBASSEMBLY-NEXT:#define __FLT128_DECIMAL_DIG__ 36 -// WEBASSEMBLY-NEXT:#define __FLT128_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966Q -// WEBASSEMBLY-NEXT:#define __FLT128_DIG__ 33 -// WEBASSEMBLY-NEXT:#define __FLT128_EPSILON__ 1.92592994438723585305597794258492732e-34Q -// WEBASSEMBLY-NEXT:#define __FLT128_HAS_DENORM__ 1 -// WEBASSEMBLY-NEXT:#define __FLT128_HAS_INFINITY__ 1 -// WEBASSEMBLY-NEXT:#define __FLT128_HAS_QUIET_NAN__ 1 -// WEBASSEMBLY-NEXT:#define __FLT128_MANT_DIG__ 113 -// WEBASSEMBLY-NEXT:#define __FLT128_MAX_10_EXP__ 4932 -// WEBASSEMBLY-NEXT:#define __FLT128_MAX_EXP__ 16384 -// WEBASSEMBLY-NEXT:#define __FLT128_MAX__ 1.18973149535723176508575932662800702e+4932Q -// WEBASSEMBLY-NEXT:#define __FLT128_MIN_10_EXP__ (-4931) -// WEBASSEMBLY-NEXT:#define __FLT128_MIN_EXP__ (-16381) -// WEBASSEMBLY-NEXT:#define __FLT128_MIN__ 3.36210314311209350626267781732175260e-4932Q // WEBASSEMBLY-NOT:#define __FLT16_DECIMAL_DIG__ // WEBASSEMBLY-NOT:#define __FLT16_DENORM_MIN__ // WEBASSEMBLY-NOT:#define __FLT16_DIG__ diff --git a/clang/test/Preprocessor/minimize-whitespace-messages.c b/clang/test/Preprocessor/minimize-whitespace-messages.c index a78ddb471fb7c..f930bbe9c257f 100644 --- a/clang/test/Preprocessor/minimize-whitespace-messages.c +++ b/clang/test/Preprocessor/minimize-whitespace-messages.c @@ -1,8 +1,11 @@ -// RUN: not %clang -c -fminimize-whitespace %s 2>&1 | FileCheck %s --check-prefix=ON -// ON: error: invalid argument '-fminimize-whitespace' only allowed with '-E' +// RUN: not %clang -c -fminimize-whitespace %s 2>&1 | FileCheck %s --check-prefix=ON -DOPT=-fminimize-whitespace +// RUN: not %clang -c -fkeep-system-includes %s 2>&1 | FileCheck %s --check-prefix=ON -DOPT=-fkeep-system-includes +// ON: error: invalid argument '[[OPT]]' only allowed with '-E' -// RUN: not %clang -c -fno-minimize-whitespace %s 2>&1 | FileCheck %s --check-prefix=OFF -// OFF: error: invalid argument '-fno-minimize-whitespace' only allowed with '-E' +// RUN: not %clang -c -fno-minimize-whitespace %s 2>&1 | FileCheck %s --check-prefix=OFF -DOPT=-fno-minimize-whitespace +// RUN: not %clang -c -fno-keep-system-includes %s 2>&1 | FileCheck %s --check-prefix=OFF -DOPT=-fno-keep-system-includes +// OFF: error: invalid argument '[[OPT]]' only allowed with '-E' -// RUN: not %clang -E -fminimize-whitespace -x assembler-with-cpp %s 2>&1 | FileCheck %s --check-prefix=ASM -// ASM: error: '-fminimize-whitespace' invalid for input of type assembler-with-cpp +// RUN: not %clang -E -fminimize-whitespace -x assembler-with-cpp %s 2>&1 | FileCheck %s --check-prefix=ASM -DOPT=-fminimize-whitespace +// RUN: not %clang -E -fkeep-system-includes -x assembler-with-cpp %s 2>&1 | FileCheck %s --check-prefix=ASM -DOPT=-fkeep-system-includes +// ASM: error: '[[OPT]]' invalid for input of type assembler-with-cpp diff --git a/clang/test/Preprocessor/predefined-arch-macros-x86.c b/clang/test/Preprocessor/predefined-arch-macros-x86.c index 37b7c612b4919..a727e51bdd45f 100644 --- a/clang/test/Preprocessor/predefined-arch-macros-x86.c +++ b/clang/test/Preprocessor/predefined-arch-macros-x86.c @@ -52,3 +52,4 @@ // X86_64_V4-NEXT: #define __AVX512F__ 1 // X86_64_V4-NEXT: #define __AVX512VL__ 1 // X86_64_V4-NOT: #define __AVX512{{.*}} +// X86_64_V4: #define __EVEX512__ 1 diff --git a/clang/test/Preprocessor/predefined-arch-macros.c b/clang/test/Preprocessor/predefined-arch-macros.c index 5bb4edb218ec2..d95992dcdff2a 100644 --- a/clang/test/Preprocessor/predefined-arch-macros.c +++ b/clang/test/Preprocessor/predefined-arch-macros.c @@ -799,6 +799,7 @@ // CHECK_KNL_M32: #define __AVX__ 1 // CHECK_KNL_M32: #define __BMI2__ 1 // CHECK_KNL_M32: #define __BMI__ 1 +// CHECK_KNL_M32: #define __EVEX512__ 1 // CHECK_KNL_M32: #define __F16C__ 1 // CHECK_KNL_M32: #define __FMA__ 1 // CHECK_KNL_M32: #define __LZCNT__ 1 @@ -836,6 +837,7 @@ // CHECK_KNL_M64: #define __AVX__ 1 // CHECK_KNL_M64: #define __BMI2__ 1 // CHECK_KNL_M64: #define __BMI__ 1 +// CHECK_KNL_M64: #define __EVEX512__ 1 // CHECK_KNL_M64: #define __F16C__ 1 // CHECK_KNL_M64: #define __FMA__ 1 // CHECK_KNL_M64: #define __LZCNT__ 1 @@ -877,6 +879,7 @@ // CHECK_KNM_M32: #define __AVX__ 1 // CHECK_KNM_M32: #define __BMI2__ 1 // CHECK_KNM_M32: #define __BMI__ 1 +// CHECK_KNM_M32: #define __EVEX512__ 1 // CHECK_KNM_M32: #define __F16C__ 1 // CHECK_KNM_M32: #define __FMA__ 1 // CHECK_KNM_M32: #define __LZCNT__ 1 @@ -912,6 +915,7 @@ // CHECK_KNM_M64: #define __AVX__ 1 // CHECK_KNM_M64: #define __BMI2__ 1 // CHECK_KNM_M64: #define __BMI__ 1 +// CHECK_KNM_M64: #define __EVEX512__ 1 // CHECK_KNM_M64: #define __F16C__ 1 // CHECK_KNM_M64: #define __FMA__ 1 // CHECK_KNM_M64: #define __LZCNT__ 1 @@ -952,6 +956,7 @@ // CHECK_SKX_M32: #define __BMI__ 1 // CHECK_SKX_M32: #define __CLFLUSHOPT__ 1 // CHECK_SKX_M32: #define __CLWB__ 1 +// CHECK_SKX_M32: #define __EVEX512__ 1 // CHECK_SKX_M32: #define __F16C__ 1 // CHECK_SKX_M32: #define __FMA__ 1 // CHECK_SKX_M32: #define __INVPCID__ 1 @@ -997,6 +1002,7 @@ // CHECK_SKX_M64: #define __BMI__ 1 // CHECK_SKX_M64: #define __CLFLUSHOPT__ 1 // CHECK_SKX_M64: #define __CLWB__ 1 +// CHECK_SKX_M64: #define __EVEX512__ 1 // CHECK_SKX_M64: #define __F16C__ 1 // CHECK_SKX_M64: #define __FMA__ 1 // CHECK_SKX_M64: #define __INVPCID__ 1 @@ -1046,6 +1052,7 @@ // CHECK_CLX_M32: #define __BMI__ 1 // CHECK_CLX_M32: #define __CLFLUSHOPT__ 1 // CHECK_CLX_M32: #define __CLWB__ 1 +// CHECK_CLX_M32: #define __EVEX512__ 1 // CHECK_CLX_M32: #define __F16C__ 1 // CHECK_CLX_M32: #define __FMA__ 1 // CHECK_CLX_M32: #define __INVPCID__ 1 @@ -1092,6 +1099,7 @@ // CHECK_CLX_M64: #define __BMI__ 1 // CHECK_CLX_M64: #define __CLFLUSHOPT__ 1 // CHECK_CLX_M64: #define __CLWB__ 1 +// CHECK_CLX_M64: #define __EVEX512__ 1 // CHECK_CLX_M64: #define __F16C__ 1 // CHECK_CLX_M64: #define __FMA__ 1 // CHECK_CLX_M64: #define __INVPCID__ 1 @@ -1142,6 +1150,7 @@ // CHECK_CPX_M32: #define __BMI__ 1 // CHECK_CPX_M32: #define __CLFLUSHOPT__ 1 // CHECK_CPX_M32: #define __CLWB__ 1 +// CHECK_CPX_M32: #define __EVEX512__ 1 // CHECK_CPX_M32: #define __F16C__ 1 // CHECK_CPX_M32: #define __FMA__ 1 // CHECK_CPX_M32: #define __INVPCID__ 1 @@ -1189,6 +1198,7 @@ // CHECK_CPX_M64: #define __BMI__ 1 // CHECK_CPX_M64: #define __CLFLUSHOPT__ 1 // CHECK_CPX_M64: #define __CLWB__ 1 +// CHECK_CPX_M64: #define __EVEX512__ 1 // CHECK_CPX_M64: #define __F16C__ 1 // CHECK_CPX_M64: #define __FMA__ 1 // CHECK_CPX_M64: #define __INVPCID__ 1 @@ -1239,6 +1249,7 @@ // CHECK_CNL_M32: #define __BMI__ 1 // CHECK_CNL_M32: #define __CLFLUSHOPT__ 1 // CHECK_CNL_M32-NOT: #define __CLWB__ 1 +// CHECK_CNL_M32: #define __EVEX512__ 1 // CHECK_CNL_M32: #define __F16C__ 1 // CHECK_CNL_M32: #define __FMA__ 1 // CHECK_CNL_M32: #define __INVPCID__ 1 @@ -1287,6 +1298,7 @@ // CHECK_CNL_M64: #define __BMI__ 1 // CHECK_CNL_M64: #define __CLFLUSHOPT__ 1 // CHECK_CNL_M64-NOT: #define __CLWB__ 1 +// CHECK_CNL_M64: #define __EVEX512__ 1 // CHECK_CNL_M64: #define __F16C__ 1 // CHECK_CNL_M64: #define __FMA__ 1 // CHECK_CNL_M64: #define __INVPCID__ 1 @@ -1343,6 +1355,7 @@ // CHECK_ICL_M32: #define __BMI__ 1 // CHECK_ICL_M32: #define __CLFLUSHOPT__ 1 // CHECK_ICL_M32-NOT: #define __CLWB__ 1 +// CHECK_ICL_M32: #define __EVEX512__ 1 // CHECK_ICL_M32: #define __F16C__ 1 // CHECK_ICL_M32: #define __FMA__ 1 // CHECK_ICL_M32: #define __GFNI__ 1 @@ -1404,6 +1417,7 @@ // CHECK_ICL_M64: #define __BMI__ 1 // CHECK_ICL_M64: #define __CLFLUSHOPT__ 1 // CHECK_ICL_M64-NOT: #define __CLWB__ 1 +// CHECK_ICL_M64: #define __EVEX512__ 1 // CHECK_ICL_M64: #define __F16C__ 1 // CHECK_ICL_M64: #define __FMA__ 1 // CHECK_ICL_M64: #define __GFNI__ 1 @@ -1463,6 +1477,7 @@ // CHECK_ICX_M32: #define __BMI__ 1 // CHECK_ICX_M32: #define __CLFLUSHOPT__ 1 // CHECK_ICX_M32: #define __CLWB__ 1 +// CHECK_ICX_M32: #define __EVEX512__ 1 // CHECK_ICX_M32: #define __F16C__ 1 // CHECK_ICX_M32: #define __FMA__ 1 // CHECK_ICX_M32: #define __GFNI__ 1 @@ -1521,6 +1536,7 @@ // CHECK_ICX_M64: #define __BMI__ 1 // CHECK_ICX_M64: #define __CLFLUSHOPT__ 1 // CHECK_ICX_M64: #define __CLWB__ 1 +// CHECK_ICX_M64: #define __EVEX512__ 1 // CHECK_ICX_M64: #define __F16C__ 1 // CHECK_ICX_M64: #define __FMA__ 1 // CHECK_ICX_M64: #define __GFNI__ 1 @@ -1581,6 +1597,7 @@ // CHECK_TGL_M32: #define __BMI__ 1 // CHECK_TGL_M32: #define __CLFLUSHOPT__ 1 // CHECK_TGL_M32: #define __CLWB__ 1 +// CHECK_TGL_M32: #define __EVEX512__ 1 // CHECK_TGL_M32: #define __F16C__ 1 // CHECK_TGL_M32: #define __FMA__ 1 // CHECK_TGL_M32: #define __GFNI__ 1 @@ -1643,6 +1660,7 @@ // CHECK_TGL_M64: #define __BMI__ 1 // CHECK_TGL_M64: #define __CLFLUSHOPT__ 1 // CHECK_TGL_M64: #define __CLWB__ 1 +// CHECK_TGL_M64: #define __EVEX512__ 1 // CHECK_TGL_M64: #define __F16C__ 1 // CHECK_TGL_M64: #define __FMA__ 1 // CHECK_TGL_M64: #define __GFNI__ 1 @@ -1716,6 +1734,7 @@ // CHECK_SPR_M32: #define __CLFLUSHOPT__ 1 // CHECK_SPR_M32: #define __CLWB__ 1 // CHECK_SPR_M32: #define __ENQCMD__ 1 +// CHECK_SPR_M32: #define __EVEX512__ 1 // CHECK_SPR_M32: #define __F16C__ 1 // CHECK_SPR_M32: #define __FMA__ 1 // CHECK_SPR_M32: #define __GFNI__ 1 @@ -1791,6 +1810,7 @@ // CHECK_SPR_M64: #define __CLFLUSHOPT__ 1 // CHECK_SPR_M64: #define __CLWB__ 1 // CHECK_SPR_M64: #define __ENQCMD__ 1 +// CHECK_SPR_M64: #define __EVEX512__ 1 // CHECK_SPR_M64: #define __F16C__ 1 // CHECK_SPR_M64: #define __FMA__ 1 // CHECK_SPR_M64: #define __GFNI__ 1 @@ -1870,6 +1890,7 @@ // CHECK_GNR_M32: #define __CLFLUSHOPT__ 1 // CHECK_GNR_M32: #define __CLWB__ 1 // CHECK_GNR_M32: #define __ENQCMD__ 1 +// CHECK_GNR_M32: #define __EVEX512__ 1 // CHECK_GNR_M32: #define __F16C__ 1 // CHECK_GNR_M32: #define __FMA__ 1 // CHECK_GNR_M32: #define __GFNI__ 1 @@ -1949,6 +1970,7 @@ // CHECK_GNR_M64: #define __CLFLUSHOPT__ 1 // CHECK_GNR_M64: #define __CLWB__ 1 // CHECK_GNR_M64: #define __ENQCMD__ 1 +// CHECK_GNR_M64: #define __EVEX512__ 1 // CHECK_GNR_M64: #define __F16C__ 1 // CHECK_GNR_M64: #define __FMA__ 1 // CHECK_GNR_M64: #define __GFNI__ 1 @@ -3845,6 +3867,7 @@ // CHECK_ZNVER4_M32: #define __CLFLUSHOPT__ 1 // CHECK_ZNVER4_M32: #define __CLWB__ 1 // CHECK_ZNVER4_M32: #define __CLZERO__ 1 +// CHECK_ZNVER4_M32: #define __EVEX512__ 1 // CHECK_ZNVER4_M32: #define __F16C__ 1 // CHECK_ZNVER4_M32-NOT: #define __FMA4__ 1 // CHECK_ZNVER4_M32: #define __FMA__ 1 @@ -3909,6 +3932,7 @@ // CHECK_ZNVER4_M64: #define __CLFLUSHOPT__ 1 // CHECK_ZNVER4_M64: #define __CLWB__ 1 // CHECK_ZNVER4_M64: #define __CLZERO__ 1 +// CHECK_ZNVER4_M64: #define __EVEX512__ 1 // CHECK_ZNVER4_M64: #define __F16C__ 1 // CHECK_ZNVER4_M64-NOT: #define __FMA4__ 1 // CHECK_ZNVER4_M64: #define __FMA__ 1 diff --git a/clang/test/Sema/builtins-x86.c b/clang/test/Sema/builtins-x86.c index 0882c80514ae9..cbaf7bcde871e 100644 --- a/clang/test/Sema/builtins-x86.c +++ b/clang/test/Sema/builtins-x86.c @@ -22,19 +22,19 @@ void call_x86_32_builtins(void) { } __m128 test__builtin_ia32_cmpps(__m128 __a, __m128 __b) { - return __builtin_ia32_cmpps(__a, __b, 32); // expected-error {{argument value 32 is outside the valid range [0, 7]}} + return __builtin_ia32_cmpps(__a, __b, 32); // expected-error {{argument value 32 is outside the valid range [0, 31]}} } __m128d test__builtin_ia32_cmppd(__m128d __a, __m128d __b) { - return __builtin_ia32_cmppd(__a, __b, 32); // expected-error {{argument value 32 is outside the valid range [0, 7]}} + return __builtin_ia32_cmppd(__a, __b, 32); // expected-error {{argument value 32 is outside the valid range [0, 31]}} } __m128 test__builtin_ia32_cmpss(__m128 __a, __m128 __b) { - return __builtin_ia32_cmpss(__a, __b, 32); // expected-error {{argument value 32 is outside the valid range [0, 7]}} + return __builtin_ia32_cmpss(__a, __b, 32); // expected-error {{argument value 32 is outside the valid range [0, 31]}} } __m128d test__builtin_ia32_cmpsd(__m128d __a, __m128d __b) { - return __builtin_ia32_cmpsd(__a, __b, 32); // expected-error {{argument value 32 is outside the valid range [0, 7]}} + return __builtin_ia32_cmpsd(__a, __b, 32); // expected-error {{argument value 32 is outside the valid range [0, 31]}} } __mmask16 test__builtin_ia32_cmpps512_mask(__m512 __a, __m512 __b) { diff --git a/clang/test/Sema/c2x-auto.c b/clang/test/Sema/c2x-auto.c new file mode 100644 index 0000000000000..916c179adcf31 --- /dev/null +++ b/clang/test/Sema/c2x-auto.c @@ -0,0 +1,137 @@ +// RUN: %clang_cc1 -std=c2x -verify -pedantic -Wno-comments %s + +void test_basic_types(void) { + auto undefined; // expected-error {{declaration of variable 'undefined' with deduced type 'auto' requires an initializer}} + auto auto_int = 4; + auto auto_long = 4UL; + signed auto a = 1L; // expected-error {{'auto' cannot be signed or unsigned}} + + _Static_assert(_Generic(auto_int, int : 1)); + _Static_assert(_Generic(auto_long, unsigned long : 1)); +} + +void test_complex_types(void) { + _Complex auto i = 12.0; // expected-error {{'_Complex auto' is invalid}} +} + +void test_gnu_extensions(void) { + auto t = ({ // expected-warning {{use of GNU statement expression extension}} + auto b = 12; + b; + }); + _Static_assert(_Generic(t, int : 1)); +} + +void test_sizeof_typeof(void) { + auto auto_size = sizeof(auto); // expected-error {{expected expression}} + typeof(auto) tpof = 4; // expected-error {{expected expression}} +} + +void test_casts(void) { + auto int_cast = (int)(4 + 3); + auto double_cast = (double)(1 / 3); + auto long_cast = (long)(4UL + 3UL); + auto auto_cast = (auto)(4 + 3); // expected-error {{expected expression}} + + _Static_assert(_Generic(int_cast, int : 1)); + _Static_assert(_Generic(double_cast, double : 1)); + _Static_assert(_Generic(long_cast, long : 1)); +} + +void test_compound_literral(void) { + auto int_cl = (int){13}; + auto double_cl = (double){2.5}; + auto array[] = { 1, 2, 3 }; // expected-error {{cannot use 'auto' with array in C}} + + auto auto_cl = (auto){13}; // expected-error {{expected expression}} + + _Static_assert(_Generic(int_cl, int : 1)); + _Static_assert(_Generic(double_cl, double : 1)); +} + +void test_array_pointers(void) { + double array[3] = { 0 }; + auto a = array; + auto b = &array; + + _Static_assert(_Generic(array, double * : 1)); + _Static_assert(_Generic(a, double * : 1)); + _Static_assert(_Generic(b, double (*)[3] : 1)); +} + +void test_typeof() { + int typeof_target(); + auto result = (typeof(typeof_target())){12}; + + _Static_assert(_Generic(result, int : 1)); +} + +void test_qualifiers(const int y) { + const auto a = 12; + auto b = y; + static auto c = 1UL; + int* pa = &a; // expected-warning {{initializing 'int *' with an expression of type 'const int *' discards qualifiers}} + const int* pb = &b; + int* pc = &c; // expected-warning {{incompatible pointer types initializing 'int *' with an expression of type 'unsigned long *'}} + + _Static_assert(_Generic(a, int : 1)); + _Static_assert(_Generic(b, int : 1)); + _Static_assert(_Generic(c, unsigned long : 1)); + _Static_assert(_Generic(pa, int * : 1)); + _Static_assert(_Generic(pb, const int * : 1)); + _Static_assert(_Generic(pc, int * : 1)); +} + +void test_strings(void) { + auto str = "this is a string"; + auto str2[] = "this is a string"; // expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + auto (str3) = "this is a string"; + auto (((str4))) = "this is a string"; + + _Static_assert(_Generic(str, char * : 1)); + _Static_assert(_Generic(str2, char * : 1)); + _Static_assert(_Generic(str3, char * : 1)); + _Static_assert(_Generic(str4, char * : 1)); +} + +void test_pointers(void) { + auto a = 12; + auto *ptr = &a; // expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + auto *str = "this is a string"; // expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + const auto *str2 = "this is a string"; // expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + auto *b = &a; // expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + *b = &a; // expected-error {{incompatible pointer to integer conversion assigning to 'int' from 'int *'; remove &}} + auto nptr = nullptr; + + _Static_assert(_Generic(a, int : 1)); + _Static_assert(_Generic(ptr, int * : 1)); + _Static_assert(_Generic(str, char * : 1)); + _Static_assert(_Generic(str2, const char * : 1)); + _Static_assert(_Generic(b, int * : 1)); + _Static_assert(_Generic(nptr, typeof(nullptr) : 1)); +} + +void test_prototypes(void) { + extern void foo(int a, int array[({ auto x = 12; x;})]); // expected-warning {{use of GNU statement expression extension}} +} + +void test_scopes(void) { + double a = 7; + double b = 9; + { + auto a = a * a; // expected-error {{variable 'a' declared with deduced type 'auto' cannot appear in its own initializer}} \ + expected-error {{variable 'a' declared with deduced type 'auto' cannot appear in its own initializer}} + } + { + auto b = a * a; + auto a = b; + + _Static_assert(_Generic(b, double : 1)); + _Static_assert(_Generic(a, double : 1)); + } +} + +[[clang::overloadable]] auto test(auto x) { // expected-error {{'auto' not allowed in function prototype}} \ + expected-error {{'auto' not allowed in function return type}} + return x; +} diff --git a/clang/test/SemaCXX/PR68542.cpp b/clang/test/SemaCXX/PR68542.cpp new file mode 100644 index 0000000000000..fc767a78c8b00 --- /dev/null +++ b/clang/test/SemaCXX/PR68542.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s + +struct S { + int e; +}; + +template +consteval int get_format() { + return nullptr; // expected-error{{cannot initialize return object of type 'int' with an rvalue of type 'std::nullptr_t'}} +} + +template +constexpr S f(T) noexcept { + return get_format(); // expected-error{{no viable conversion from returned value of type 'int' to function return type 'S'}} +} + +constexpr S x = f(0); // expected-error{{constexpr variable 'x' must be initialized by a constant expression}} +// expected-note@-1{{in instantiation of function template specialization 'f' requested here}} +// expected-note@3{{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'S &&' for 1st argument}} +// expected-note@3{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const S &' for 1st argument}} diff --git a/clang/test/SemaCXX/class-layout.cpp b/clang/test/SemaCXX/class-layout.cpp index 9782ff08100b2..22fb34b8419c5 100644 --- a/clang/test/SemaCXX/class-layout.cpp +++ b/clang/test/SemaCXX/class-layout.cpp @@ -1,34 +1,34 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++98 -Wno-inaccessible-base -Wno-c++11-extensions -// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=15 -// RUN: %clang_cc1 -triple x86_64-scei-ps4 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=6 -// RUN: %clang_cc1 -triple x86_64-sie-ps5 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=6 -// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=6 -DCLANG_ABI_COMPAT=6 -// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=14 -DCLANG_ABI_COMPAT=14 -// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 -// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=16 -DCLANG_ABI_COMPAT=16 -// RUN: %clang_cc1 -triple powerpc-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=15 -// RUN: %clang_cc1 -triple powerpc-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 -// RUN: %clang_cc1 -triple powerpc64-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=15 -// RUN: %clang_cc1 -triple powerpc64-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 -// RUN: %clang_cc1 -triple s390x-none-zos %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -// RUN: %clang_cc1 -triple s390x-none-zos %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 - -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++98 -Wno-inaccessible-base -Wno-c++11-extensions -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-apple-darwin %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=15 -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-scei-ps4 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=6 -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-sie-ps5 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=6 -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=6 -DCLANG_ABI_COMPAT=6 -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=14 -DCLANG_ABI_COMPAT=14 -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=16 -DCLANG_ABI_COMPAT=16 -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple powerpc-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=15 -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple powerpc-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple powerpc64-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=15 -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple powerpc64-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple s390x-none-zos %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple s390x-none-zos %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++98 -Wno-inaccessible-base -Wno-invalid-offsetof -Wno-c++11-extensions +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof +// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof -DCLANG_ABI_COMPAT=15 +// RUN: %clang_cc1 -triple x86_64-scei-ps4 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof -DCLANG_ABI_COMPAT=6 +// RUN: %clang_cc1 -triple x86_64-sie-ps5 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof -DCLANG_ABI_COMPAT=6 +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof -fclang-abi-compat=6 -DCLANG_ABI_COMPAT=6 +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof -fclang-abi-compat=14 -DCLANG_ABI_COMPAT=14 +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof -fclang-abi-compat=16 -DCLANG_ABI_COMPAT=16 +// RUN: %clang_cc1 -triple powerpc-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof -DCLANG_ABI_COMPAT=15 +// RUN: %clang_cc1 -triple powerpc-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 +// RUN: %clang_cc1 -triple powerpc64-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof -DCLANG_ABI_COMPAT=15 +// RUN: %clang_cc1 -triple powerpc64-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 +// RUN: %clang_cc1 -triple s390x-none-zos %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof +// RUN: %clang_cc1 -triple s390x-none-zos %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 + +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++98 -Wno-inaccessible-base -Wno-c++11-extensions -Wno-invalid-offsetof +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-apple-darwin %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=15 -Wno-invalid-offsetof +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-scei-ps4 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=6 -Wno-invalid-offsetof +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-sie-ps5 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=6 -Wno-invalid-offsetof +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=6 -DCLANG_ABI_COMPAT=6 -Wno-invalid-offsetof +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=14 -DCLANG_ABI_COMPAT=14 -Wno-invalid-offsetof +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 -Wno-invalid-offsetof +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=16 -DCLANG_ABI_COMPAT=16 -Wno-invalid-offsetof +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple powerpc-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=15 -Wno-invalid-offsetof +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple powerpc-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 -Wno-invalid-offsetof +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple powerpc64-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=15 -Wno-invalid-offsetof +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple powerpc64-ibm-aix7.3.0.0 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 -Wno-invalid-offsetof +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple s390x-none-zos %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-invalid-offsetof +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple s390x-none-zos %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 -Wno-invalid-offsetof diff --git a/clang/test/SemaCXX/constant-expression-cxx1z.cpp b/clang/test/SemaCXX/constant-expression-cxx1z.cpp index 9335626a5c90a..c0766f70cf881 100644 --- a/clang/test/SemaCXX/constant-expression-cxx1z.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx1z.cpp @@ -177,3 +177,16 @@ namespace LambdaCallOp { p(); } } + +// This used to crash due to an assertion failure, +// see gh#67690 +namespace { + struct C { + int x; + }; + + template void f() { + const auto &[c] = *p; + &c; // expected-warning {{expression result unused}} + } +} diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp index a091fadfa3094..38cc4be32a27c 100644 --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -8,7 +8,7 @@ consteval int f1(int i) { return i; } -consteval constexpr int f2(int i) { +consteval constexpr int f2(int i) { //expected-error@-1 {{cannot combine}} return i; } @@ -195,7 +195,7 @@ auto ptr = ret1(0); struct A { consteval int f(int) { // expected-note@-1+ {{declared here}} - return 0; + return 0; } }; @@ -239,7 +239,7 @@ constexpr int f_c(int i) { int t = f(i); // expected-error@-1 {{is not a constant expression}} // expected-note@-2 {{function parameter}} - return f(0); + return f(0); } consteval int f_eval(int i) { @@ -675,7 +675,7 @@ Bar a; // expected-note {{in instantiation of member function 'issue_55601 struct constantDerp { // Can be used in a constant expression. - consteval constantDerp(int) {} + consteval constantDerp(int) {} consteval operator int() const { return 5; } }; Bar b; @@ -1175,4 +1175,28 @@ struct T { static constexpr auto xx = ns::foo(A{}); // expected-error {{cannot take address of consteval function 'foo' outside of an immediate invocation}} }; +} + +namespace GH65520 { + +consteval int bar (int i) { if (i != 1) return 1/0; return 0; } +// expected-note@-1{{division by zero}} + +void +g () +{ + int a_ok[bar(1)]; + int a_err[bar(3)]; // expected-error {{call to consteval function 'GH65520::bar' is not a constant expression}} \ + // expected-note {{in call to 'bar(3)'}} +} + +consteval int undefined(); // expected-note {{declared here}} + +consteval void immediate() { + int a [undefined()]; // expected-note {{undefined function 'undefined' cannot be used in a constant expression}} \ + // expected-error {{call to consteval function 'GH65520::undefined' is not a constant expression}} \ + // expected-error {{variable of non-literal type 'int[undefined()]' cannot be defined in a constexpr function before C++23}} +} + + } diff --git a/clang/test/SemaCXX/cxx2b-deducing-this-constexpr.cpp b/clang/test/SemaCXX/cxx2b-deducing-this-constexpr.cpp index 44de0d711674b..9dbea17dd2cae 100644 --- a/clang/test/SemaCXX/cxx2b-deducing-this-constexpr.cpp +++ b/clang/test/SemaCXX/cxx2b-deducing-this-constexpr.cpp @@ -54,3 +54,21 @@ consteval void test() { static_assert(*s == 42); static_assert((s << 11) == 31); } + +namespace GH68070 { + +constexpr auto f = [x = 3](this Self&& self) { + return x; +}; + +auto g = [x = 3](this Self&& self) { + return x; +}; + +int test() { + constexpr int a = f(); + static_assert(a == 3); + return f() + g(); +} + +} diff --git a/clang/test/SemaCXX/ms_struct.cpp b/clang/test/SemaCXX/ms_struct.cpp index e6f0a25b38ea8..995e424d1f876 100644 --- a/clang/test/SemaCXX/ms_struct.cpp +++ b/clang/test/SemaCXX/ms_struct.cpp @@ -25,6 +25,7 @@ struct B : public A { static_assert(__builtin_offsetof(B, d) == 12, "We can't allocate the bitfield into the padding under ms_struct"); +// expected-warning@-2 {{offset of on non-standard-layout type 'B'}} struct C { #ifdef TEST_FOR_ERROR @@ -38,6 +39,5 @@ struct C { static_assert(__builtin_offsetof(C, n) == 8, "long long field in ms_struct should be 8-byte aligned"); -#if !defined(TEST_FOR_ERROR) && !defined(TEST_FOR_WARNING) -// expected-no-diagnostics -#endif +// expected-warning@-2 {{offset of on non-standard-layout type 'C'}} + diff --git a/clang/test/SemaCXX/offsetof.cpp b/clang/test/SemaCXX/offsetof.cpp index c984657ebe1f0..c4e86369f007d 100644 --- a/clang/test/SemaCXX/offsetof.cpp +++ b/clang/test/SemaCXX/offsetof.cpp @@ -51,9 +51,9 @@ struct Derived2 : public Base1, public Base2 { int z; }; -int derived1[__builtin_offsetof(Derived2, x) == 0? 1 : -1]; -int derived2[__builtin_offsetof(Derived2, y) == 4? 1 : -1]; -int derived3[__builtin_offsetof(Derived2, z) == 8? 1 : -1]; +int derived1[__builtin_offsetof(Derived2, x) == 0? 1 : -1]; // expected-warning{{offset of on non-POD type 'Derived2'}} +int derived2[__builtin_offsetof(Derived2, y) == 4? 1 : -1]; // expected-warning{{offset of on non-POD type 'Derived2'}} +int derived3[__builtin_offsetof(Derived2, z) == 8? 1 : -1]; // expected-warning{{offset of on non-POD type 'Derived2'}} // offsetof referring to anonymous struct in base. // PR7769 @@ -66,7 +66,8 @@ struct foo { struct bar : public foo { }; -int anonstruct[__builtin_offsetof(bar, x) == 0 ? 1 : -1]; +int anonstruct[__builtin_offsetof(bar, x) == 0 ? 1 : -1]; // expected-warning{{offset of on non-POD type 'bar'}} + struct LtoRCheck { int a[10]; diff --git a/clang/test/SemaTemplate/instantiate-method.cpp b/clang/test/SemaTemplate/instantiate-method.cpp index 9cd668dacf5c9..60889a4cffe46 100644 --- a/clang/test/SemaTemplate/instantiate-method.cpp +++ b/clang/test/SemaTemplate/instantiate-method.cpp @@ -45,7 +45,7 @@ class HasDestructor { virtual ~HasDestructor() = 0; }; -int i = sizeof(HasDestructor); // FIXME: forces instantiation, but +int i = sizeof(HasDestructor); // FIXME: forces instantiation, but // the code below should probably instantiate by itself. int abstract_destructor[__is_abstract(HasDestructor)? 1 : -1]; @@ -94,7 +94,7 @@ struct X0 : X0Base { template struct X1 : X0 { - int &f2() { + int &f2() { return X0Base::f(); } }; @@ -129,19 +129,19 @@ namespace test1 { } namespace PR6947 { - template< class T > + template< class T > struct X { - int f0( ) + int f0( ) { typedef void ( X::*impl_fun_ptr )( ); impl_fun_ptr pImpl = &X::template f0_impl1; } - private: + private: int f1() { } - template< class Processor> - void f0_impl1( ) + template< class Processor> + void f0_impl1( ) { } }; @@ -154,7 +154,7 @@ namespace PR6947 { } namespace PR7022 { - template + template struct X1 { typedef int state_t( ); @@ -185,13 +185,12 @@ namespace SameSignatureAfterInstantiation { namespace PR22040 { template struct Foobar { - template <> void bazqux(typename T::type) {} // expected-error 2{{cannot be used prior to '::' because it has no members}} + template <> void bazqux(typename T::type) {} // expected-error {{no candidate function template was found for dependent member function template specialization}} }; void test() { - // FIXME: we should suppress the "no member" errors - Foobar::bazqux(); // expected-error{{no member named 'bazqux' in }} expected-note{{in instantiation of template class }} - Foobar::bazqux(); // expected-error{{no member named 'bazqux' in }} expected-note{{in instantiation of template class }} + Foobar::bazqux(); + Foobar::bazqux(); Foobar::bazqux(3); // expected-error{{no member named 'bazqux' in }} } } diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp index 632e37e3cac8f..f95b0f8cb317c 100644 --- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp +++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp @@ -595,6 +595,7 @@ Error linkBitcodeFiles(SmallVectorImpl &InputFiles, StringRef Arch = Args.getLastArgValue(OPT_arch_EQ); SmallVector BitcodeInputFiles; + DenseSet StrongResolutions; DenseSet UsedInRegularObj; DenseSet UsedInSharedLib; BumpPtrAllocator Alloc; @@ -608,6 +609,18 @@ Error linkBitcodeFiles(SmallVectorImpl &InputFiles, file_magic Type = identify_magic(Buffer.getBuffer()); switch (Type) { case file_magic::bitcode: { + Expected IRSymtabOrErr = readIRSymtab(Buffer); + if (!IRSymtabOrErr) + return IRSymtabOrErr.takeError(); + + // Check for any strong resolutions we need to preserve. + for (unsigned I = 0; I != IRSymtabOrErr->Mods.size(); ++I) { + for (const auto &Sym : IRSymtabOrErr->TheReader.module_symbols(I)) { + if (!Sym.isFormatSpecific() && Sym.isGlobal() && !Sym.isWeak() && + !Sym.isUndefined()) + StrongResolutions.insert(Saver.save(Sym.Name)); + } + } BitcodeInputFiles.emplace_back(std::move(File)); continue; } @@ -696,6 +709,7 @@ Error linkBitcodeFiles(SmallVectorImpl &InputFiles, // it is undefined or another definition has already been used. Res.Prevailing = !Sym.isUndefined() && + !(Sym.isWeak() && StrongResolutions.contains(Sym.getName())) && PrevailingSymbols.insert(Saver.save(Sym.getName())).second; // We need LTO to preseve the following global symbols: diff --git a/clang/tools/clang-offload-bundler/CMakeLists.txt b/clang/tools/clang-offload-bundler/CMakeLists.txt index dabd82382cdf0..dec2881589a53 100644 --- a/clang/tools/clang-offload-bundler/CMakeLists.txt +++ b/clang/tools/clang-offload-bundler/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + BinaryFormat Object Support TargetParser diff --git a/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp b/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp index f20157622d79f..90c475e541f4c 100644 --- a/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp +++ b/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp @@ -136,6 +136,11 @@ int main(int argc, const char **argv) { cl::desc("Treat hip and hipv4 offload kinds as " "compatible with openmp kind, and vice versa.\n"), cl::init(false), cl::cat(ClangOffloadBundlerCategory)); + cl::opt Compress("compress", + cl::desc("Compress output file when bundling.\n"), + cl::init(false), cl::cat(ClangOffloadBundlerCategory)); + cl::opt Verbose("verbose", cl::desc("Print debug information.\n"), + cl::init(false), cl::cat(ClangOffloadBundlerCategory)); // Process commandline options and report errors sys::PrintStackTraceOnErrorSignal(argv[0]); @@ -163,6 +168,11 @@ int main(int argc, const char **argv) { BundlerConfig.BundleAlignment = BundleAlignment; BundlerConfig.FilesType = FilesType; BundlerConfig.ObjcopyPath = ""; + // Do not override the default value Compress and Verbose in BundlerConfig. + if (Compress.getNumOccurrences() > 0) + BundlerConfig.Compress = Compress; + if (Verbose.getNumOccurrences() > 0) + BundlerConfig.Verbose = Verbose; BundlerConfig.TargetNames = TargetNames; BundlerConfig.InputFileNames = InputFileNames; diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index f0c8ecfcb6264..46226f4325b0a 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2735,6 +2735,7 @@ void OMPClauseEnqueue::VisitOMPDoacrossClause(const OMPDoacrossClause *C) { } void OMPClauseEnqueue::VisitOMPXAttributeClause(const OMPXAttributeClause *C) { } +void OMPClauseEnqueue::VisitOMPXBareClause(const OMPXBareClause *C) {} } // namespace @@ -6847,7 +6848,6 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::Captured: case Decl::OMPCapturedExpr: case Decl::Label: // FIXME: Is this right?? - case Decl::ClassScopeFunctionSpecialization: case Decl::CXXDeductionGuide: case Decl::Import: case Decl::OMPThreadPrivate: diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index e9e8cac2a15bc..393ed44de3f18 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -4988,6 +4988,37 @@ TEST_P(ASTImporterOptionSpecificTestBase, } } +TEST_P(ImportFriendClasses, RecordVarTemplateDecl) { + Decl *ToTU = getToTuDecl( + R"( + template + class A { + public: + template + static constexpr bool X = true; + }; + )", + Lang_CXX14); + + auto *ToTUX = FirstDeclMatcher().match( + ToTU, varTemplateDecl(hasName("X"))); + Decl *FromTU = getTuDecl( + R"( + template + class A { + public: + template + static constexpr bool X = true; + }; + )", + Lang_CXX14, "input1.cc"); + auto *FromX = FirstDeclMatcher().match( + FromTU, varTemplateDecl(hasName("X"))); + auto *ToX = Import(FromX, Lang_CXX11); + EXPECT_TRUE(ToX); + EXPECT_EQ(ToTUX, ToX); +} + TEST_P(ASTImporterOptionSpecificTestBase, VarTemplateParameterDeclContext) { constexpr auto Code = R"( diff --git a/clang/unittests/Analysis/MacroExpansionContextTest.cpp b/clang/unittests/Analysis/MacroExpansionContextTest.cpp index 5c694c836a488..54b209e7b28c1 100644 --- a/clang/unittests/Analysis/MacroExpansionContextTest.cpp +++ b/clang/unittests/Analysis/MacroExpansionContextTest.cpp @@ -73,12 +73,7 @@ class MacroExpansionContextTest : public ::testing::Test { // Lex source text. PP.EnterMainSourceFile(); - while (true) { - Token Tok; - PP.Lex(Tok); - if (Tok.is(tok::eof)) - break; - } + PP.LexTokensUntilEOF(); // Callbacks have been executed at this point. return Ctx; diff --git a/clang/unittests/Basic/SourceManagerTest.cpp b/clang/unittests/Basic/SourceManagerTest.cpp index f451e43bb53d7..557281499998a 100644 --- a/clang/unittests/Basic/SourceManagerTest.cpp +++ b/clang/unittests/Basic/SourceManagerTest.cpp @@ -26,6 +26,13 @@ using namespace clang; +namespace clang { +class SourceManagerTestHelper { +public: + static FileID makeFileID(int ID) { return FileID::get(ID); } +}; +} // namespace clang + namespace { // The test fixture. @@ -138,13 +145,7 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnit) { PP.EnterMainSourceFile(); std::vector toks; - while (1) { - Token tok; - PP.Lex(tok); - if (tok.is(tok::eof)) - break; - toks.push_back(tok); - } + PP.LexTokensUntilEOF(&toks); // Make sure we got the tokens that we expected. ASSERT_EQ(3U, toks.size()); @@ -195,13 +196,7 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithTokenSplit) { llvm::SmallString<8> Scratch; std::vector toks; - while (1) { - Token tok; - PP.Lex(tok); - if (tok.is(tok::eof)) - break; - toks.push_back(tok); - } + PP.LexTokensUntilEOF(&toks); // Make sure we got the tokens that we expected. ASSERT_EQ(4U, toks.size()) << "a >> b c"; @@ -409,6 +404,53 @@ TEST_F(SourceManagerTest, getLineNumber) { ASSERT_NO_FATAL_FAILURE(SourceMgr.getLineNumber(mainFileID, 1, nullptr)); } +struct FakeExternalSLocEntrySource : ExternalSLocEntrySource { + bool ReadSLocEntry(int ID) override { return {}; } + int getSLocEntryID(SourceLocation::UIntTy SLocOffset) override { return 0; } + std::pair getModuleImportLoc(int ID) override { + return {}; + } +}; + +TEST_F(SourceManagerTest, loadedSLocEntryIsInTheSameTranslationUnit) { + auto InSameTU = [=](int LID, int RID) { + return SourceMgr.isInTheSameTranslationUnitImpl( + std::make_pair(SourceManagerTestHelper::makeFileID(LID), 0), + std::make_pair(SourceManagerTestHelper::makeFileID(RID), 0)); + }; + + FakeExternalSLocEntrySource ExternalSource; + SourceMgr.setExternalSLocEntrySource(&ExternalSource); + + unsigned ANumFileIDs = 10; + auto [AFirstID, X] = SourceMgr.AllocateLoadedSLocEntries(ANumFileIDs, 10); + int ALastID = AFirstID + ANumFileIDs - 1; + // FileID(-11)..FileID(-2) + ASSERT_EQ(AFirstID, -11); + ASSERT_EQ(ALastID, -2); + + unsigned BNumFileIDs = 20; + auto [BFirstID, Y] = SourceMgr.AllocateLoadedSLocEntries(BNumFileIDs, 20); + int BLastID = BFirstID + BNumFileIDs - 1; + // FileID(-31)..FileID(-12) + ASSERT_EQ(BFirstID, -31); + ASSERT_EQ(BLastID, -12); + + // Loaded vs local. + EXPECT_FALSE(InSameTU(-2, 1)); + + // Loaded in the same allocation A. + EXPECT_TRUE(InSameTU(-11, -2)); + EXPECT_TRUE(InSameTU(-11, -6)); + + // Loaded in the same allocation B. + EXPECT_TRUE(InSameTU(-31, -12)); + EXPECT_TRUE(InSameTU(-31, -16)); + + // Loaded from different allocations A and B. + EXPECT_FALSE(InSameTU(-12, -11)); +} + #if defined(LLVM_ON_UNIX) TEST_F(SourceManagerTest, getMacroArgExpandedLocation) { @@ -452,13 +494,7 @@ TEST_F(SourceManagerTest, getMacroArgExpandedLocation) { PP.EnterMainSourceFile(); std::vector toks; - while (1) { - Token tok; - PP.Lex(tok); - if (tok.is(tok::eof)) - break; - toks.push_back(tok); - } + PP.LexTokensUntilEOF(&toks); // Make sure we got the tokens that we expected. ASSERT_EQ(4U, toks.size()); @@ -574,13 +610,7 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { PP.EnterMainSourceFile(); std::vector toks; - while (1) { - Token tok; - PP.Lex(tok); - if (tok.is(tok::eof)) - break; - toks.push_back(tok); - } + PP.LexTokensUntilEOF(&toks); // Make sure we got the tokens that we expected. ASSERT_EQ(0U, toks.size()); diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 62ec460eba7fd..2d590f2af05e6 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -393,32 +393,39 @@ TEST_F(TokenAnnotatorTest, UnderstandsClasses) { auto Tokens = annotate("class C {};"); EXPECT_EQ(Tokens.size(), 6u) << Tokens; EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_ClassLBrace); + EXPECT_TOKEN(Tokens[3], tok::r_brace, TT_ClassRBrace); Tokens = annotate("const class C {} c;"); EXPECT_EQ(Tokens.size(), 8u) << Tokens; EXPECT_TOKEN(Tokens[3], tok::l_brace, TT_ClassLBrace); + EXPECT_TOKEN(Tokens[4], tok::r_brace, TT_ClassRBrace); Tokens = annotate("const class {} c;"); EXPECT_EQ(Tokens.size(), 7u) << Tokens; EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_ClassLBrace); + EXPECT_TOKEN(Tokens[3], tok::r_brace, TT_ClassRBrace); Tokens = annotate("class [[deprecated(\"\")]] C { int i; };"); EXPECT_EQ(Tokens.size(), 17u) << Tokens; EXPECT_TOKEN(Tokens[10], tok::l_brace, TT_ClassLBrace); + EXPECT_TOKEN(Tokens[14], tok::r_brace, TT_ClassRBrace); } TEST_F(TokenAnnotatorTest, UnderstandsStructs) { auto Tokens = annotate("struct S {};"); EXPECT_EQ(Tokens.size(), 6u) << Tokens; EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_StructLBrace); + EXPECT_TOKEN(Tokens[3], tok::r_brace, TT_StructRBrace); Tokens = annotate("struct EXPORT_MACRO [[nodiscard]] C { int i; };"); EXPECT_EQ(Tokens.size(), 15u) << Tokens; EXPECT_TOKEN(Tokens[8], tok::l_brace, TT_StructLBrace); + EXPECT_TOKEN(Tokens[12], tok::r_brace, TT_StructRBrace); Tokens = annotate("struct [[deprecated]] [[nodiscard]] C { int i; };"); EXPECT_EQ(Tokens.size(), 19u) << Tokens; EXPECT_TOKEN(Tokens[12], tok::l_brace, TT_StructLBrace); + EXPECT_TOKEN(Tokens[16], tok::r_brace, TT_StructRBrace); Tokens = annotate("template struct S {};"); EXPECT_EQ(Tokens.size(), 18u) << Tokens; @@ -426,6 +433,7 @@ TEST_F(TokenAnnotatorTest, UnderstandsStructs) { EXPECT_TOKEN(Tokens[10], tok::l_square, TT_ArraySubscriptLSquare); EXPECT_TOKEN(Tokens[13], tok::greater, TT_TemplateCloser); EXPECT_TOKEN(Tokens[14], tok::l_brace, TT_StructLBrace); + EXPECT_TOKEN(Tokens[15], tok::r_brace, TT_StructRBrace); Tokens = annotate("template struct S {};"); EXPECT_EQ(Tokens.size(), 18u) << Tokens; @@ -433,6 +441,7 @@ TEST_F(TokenAnnotatorTest, UnderstandsStructs) { EXPECT_TOKEN(Tokens[10], tok::l_square, TT_ArraySubscriptLSquare); EXPECT_TOKEN(Tokens[13], tok::greater, TT_TemplateCloser); EXPECT_TOKEN(Tokens[14], tok::l_brace, TT_StructLBrace); + EXPECT_TOKEN(Tokens[15], tok::r_brace, TT_StructRBrace); Tokens = annotate("template struct S {\n" " void f(T const (&a)[n]);\n" @@ -445,23 +454,27 @@ TEST_F(TokenAnnotatorTest, UnderstandsStructs) { EXPECT_TOKEN(Tokens[23], tok::l_paren, TT_FunctionTypeLParen); EXPECT_TOKEN(Tokens[24], tok::amp, TT_UnaryOperator); EXPECT_TOKEN(Tokens[27], tok::l_square, TT_ArraySubscriptLSquare); + EXPECT_TOKEN(Tokens[32], tok::r_brace, TT_StructRBrace); } TEST_F(TokenAnnotatorTest, UnderstandsUnions) { auto Tokens = annotate("union U {};"); EXPECT_EQ(Tokens.size(), 6u) << Tokens; EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_UnionLBrace); + EXPECT_TOKEN(Tokens[3], tok::r_brace, TT_UnionRBrace); Tokens = annotate("union U { void f() { return; } };"); EXPECT_EQ(Tokens.size(), 14u) << Tokens; EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_UnionLBrace); EXPECT_TOKEN(Tokens[7], tok::l_brace, TT_FunctionLBrace); + EXPECT_TOKEN(Tokens[11], tok::r_brace, TT_UnionRBrace); } TEST_F(TokenAnnotatorTest, UnderstandsEnums) { auto Tokens = annotate("enum E {};"); EXPECT_EQ(Tokens.size(), 6u) << Tokens; EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_EnumLBrace); + EXPECT_TOKEN(Tokens[3], tok::r_brace, TT_EnumRBrace); } TEST_F(TokenAnnotatorTest, UnderstandsDefaultedAndDeletedFunctions) { diff --git a/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp b/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp index 2f1c4efb381f0..7b47d93446192 100644 --- a/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp +++ b/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp @@ -122,6 +122,11 @@ extern "C" int throw_exception() { Triple.getArch() == llvm::Triple::aarch64_32)) GTEST_SKIP(); + // FIXME: RISC-V fails as .eh_frame handling is not yet implemented in + // JITLink for RISC-V. See PR #66067. + if (Triple.isRISCV()) + GTEST_SKIP(); + llvm::cantFail(Interp->ParseAndExecute(ExceptionCode)); testing::internal::CaptureStdout(); auto ThrowException = diff --git a/clang/unittests/Lex/LexerTest.cpp b/clang/unittests/Lex/LexerTest.cpp index 8932265674a59..47aa2c131a304 100644 --- a/clang/unittests/Lex/LexerTest.cpp +++ b/clang/unittests/Lex/LexerTest.cpp @@ -74,13 +74,7 @@ class LexerTest : public ::testing::Test { PP = CreatePP(Source, ModLoader); std::vector toks; - while (1) { - Token tok; - PP->Lex(tok); - if (tok.is(tok::eof)) - break; - toks.push_back(tok); - } + PP->LexTokensUntilEOF(&toks); return toks; } @@ -628,12 +622,7 @@ TEST_F(LexerTest, FindNextToken) { TEST_F(LexerTest, CreatedFIDCountForPredefinedBuffer) { TrivialModuleLoader ModLoader; auto PP = CreatePP("", ModLoader); - while (1) { - Token tok; - PP->Lex(tok); - if (tok.is(tok::eof)) - break; - } + PP->LexTokensUntilEOF(); EXPECT_EQ(SourceMgr.getNumCreatedFIDsForFileID(PP->getPredefinesFileID()), 1U); } diff --git a/clang/unittests/Lex/ModuleDeclStateTest.cpp b/clang/unittests/Lex/ModuleDeclStateTest.cpp index ed694384da57c..15306ba22bf67 100644 --- a/clang/unittests/Lex/ModuleDeclStateTest.cpp +++ b/clang/unittests/Lex/ModuleDeclStateTest.cpp @@ -90,12 +90,7 @@ class ModuleDeclStateTest : public ::testing::Test { PP.addPPCallbacks(std::move(C)); PP.EnterMainSourceFile(); - while (1) { - Token tok; - PP.Lex(tok); - if (tok.is(tok::eof)) - break; - } + PP.LexTokensUntilEOF(); } FileSystemOptions FileMgrOpts; diff --git a/clang/unittests/Lex/PPCallbacksTest.cpp b/clang/unittests/Lex/PPCallbacksTest.cpp index b2be40ef3812e..e0a27b5111821 100644 --- a/clang/unittests/Lex/PPCallbacksTest.cpp +++ b/clang/unittests/Lex/PPCallbacksTest.cpp @@ -229,13 +229,7 @@ class PPCallbacksTest : public ::testing::Test { // Lex source text. PP.EnterMainSourceFile(); - - while (true) { - Token Tok; - PP.Lex(Tok); - if (Tok.is(tok::eof)) - break; - } + PP.LexTokensUntilEOF(); // Callbacks have been executed at this point -- return filename range. return Callbacks; @@ -259,13 +253,7 @@ class PPCallbacksTest : public ::testing::Test { // Lex source text. PP.EnterMainSourceFile(); - - while (true) { - Token Tok; - PP.Lex(Tok); - if (Tok.is(tok::eof)) - break; - } + PP.LexTokensUntilEOF(); return Callbacks->Results; } @@ -290,12 +278,7 @@ class PPCallbacksTest : public ::testing::Test { // Lex source text. PP.EnterMainSourceFile(); - while (true) { - Token Tok; - PP.Lex(Tok); - if (Tok.is(tok::eof)) - break; - } + PP.LexTokensUntilEOF(); return Callbacks->Marks; } @@ -334,12 +317,7 @@ class PPCallbacksTest : public ::testing::Test { // Lex source text. PP.EnterMainSourceFile(); - while (true) { - Token Tok; - PP.Lex(Tok); - if (Tok.is(tok::eof)) - break; - } + PP.LexTokensUntilEOF(); PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = { Callbacks->Name, @@ -477,12 +455,7 @@ TEST_F(PPCallbacksTest, FileNotFoundSkipped) { // Lex source text. PP.EnterMainSourceFile(); - while (true) { - Token Tok; - PP.Lex(Tok); - if (Tok.is(tok::eof)) - break; - } + PP.LexTokensUntilEOF(); ASSERT_EQ(1u, Callbacks->NumCalls); ASSERT_EQ(0u, DiagConsumer->getNumErrors()); diff --git a/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp b/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp index ba75639578651..84c4cc3a1b2dc 100644 --- a/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp +++ b/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp @@ -87,13 +87,7 @@ TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) { PP.EnterMainSourceFile(); std::vector toks; - while (1) { - Token tok; - PP.Lex(tok); - if (tok.is(tok::eof)) - break; - toks.push_back(tok); - } + PP.LexTokensUntilEOF(&toks); // Make sure we got the tokens that we expected. ASSERT_EQ(10U, toks.size()); diff --git a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp index 4685021b6ecdb..6ff87f720a559 100644 --- a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp +++ b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp @@ -133,12 +133,7 @@ TEST_F(PPDependencyDirectivesTest, MacroGuard) { SmallVector IncludedFiles; PP.addPPCallbacks(std::make_unique(PP, IncludedFiles)); PP.EnterMainSourceFile(); - while (true) { - Token tok; - PP.Lex(tok); - if (tok.is(tok::eof)) - break; - } + PP.LexTokensUntilEOF(); SmallVector IncludedFilesSlash; for (StringRef IncludedFile : IncludedFiles) diff --git a/clang/unittests/Lex/PPMemoryAllocationsTest.cpp b/clang/unittests/Lex/PPMemoryAllocationsTest.cpp index 894d94e149a9f..f7fb097b1f7fa 100644 --- a/clang/unittests/Lex/PPMemoryAllocationsTest.cpp +++ b/clang/unittests/Lex/PPMemoryAllocationsTest.cpp @@ -75,12 +75,7 @@ TEST_F(PPMemoryAllocationsTest, PPMacroDefinesAllocations) { PP.Initialize(*Target); PP.EnterMainSourceFile(); - while (1) { - Token tok; - PP.Lex(tok); - if (tok.is(tok::eof)) - break; - } + PP.LexTokensUntilEOF(); size_t NumAllocated = PP.getPreprocessorAllocator().getBytesAllocated(); float BytesPerDefine = float(NumAllocated) / float(NumMacros); diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp index fdfbbfe4e3a9d..a7ca2bf91e474 100644 --- a/clang/unittests/Support/TimeProfilerTest.cpp +++ b/clang/unittests/Support/TimeProfilerTest.cpp @@ -190,6 +190,7 @@ Frontend | EvaluateAsInitializer (slow_value) | EvaluateAsConstantExpr () | EvaluateAsConstantExpr () +| EvaluateAsConstantExpr () | EvaluateAsRValue () | EvaluateAsInitializer (slow_init_list) | PerformPendingInstantiations diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index ffada02ac4d30..45e2fa7b283e1 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -2690,7 +2690,8 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS, OS << ", "; emitFormInitializer(OS, Spellings[0], "0"); } else { - OS << ", (\n"; + OS << ", [&]() {\n"; + OS << " switch (S) {\n"; std::set Uniques; unsigned Idx = 0; for (auto I = Spellings.begin(), E = Spellings.end(); I != E; @@ -2698,15 +2699,19 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS, const FlattenedSpelling &S = *I; const auto &Name = SemanticToSyntacticMap[Idx]; if (Uniques.insert(Name).second) { - OS << " S == " << Name << " ? AttributeCommonInfo::Form"; + OS << " case " << Name << ":\n"; + OS << " return AttributeCommonInfo::Form"; emitFormInitializer(OS, S, Name); - OS << " :\n"; + OS << ";\n"; } } - OS << " (llvm_unreachable(\"Unknown attribute spelling!\"), " - << " AttributeCommonInfo::Form"; + OS << " default:\n"; + OS << " llvm_unreachable(\"Unknown attribute spelling!\");\n" + << " return AttributeCommonInfo::Form"; emitFormInitializer(OS, Spellings[0], "0"); - OS << "))"; + OS << ";\n" + << " }\n" + << " }()"; } OS << ");\n"; @@ -3429,9 +3434,10 @@ static bool GenerateTargetSpecificAttrChecks(const Record *R, } static void GenerateHasAttrSpellingStringSwitch( - const std::vector &Attrs, raw_ostream &OS, - const std::string &Variety = "", const std::string &Scope = "") { - for (const auto *Attr : Attrs) { + const std::vector> &Attrs, + raw_ostream &OS, const std::string &Variety, + const std::string &Scope = "") { + for (const auto &[Attr, Spelling] : Attrs) { // C++11-style attributes have specific version information associated with // them. If the attribute has no scope, the version information must not // have the default value (1), as that's incorrect. Instead, the unscoped @@ -3450,26 +3456,22 @@ static void GenerateHasAttrSpellingStringSwitch( // a way that is impactful to the end user. int Version = 1; - std::vector Spellings = GetFlattenedSpellings(*Attr); + assert(Spelling.variety() == Variety); std::string Name = ""; - for (const auto &Spelling : Spellings) { - if (Spelling.variety() == Variety && - (Spelling.nameSpace().empty() || Scope == Spelling.nameSpace())) { - Name = Spelling.name(); - Version = static_cast( - Spelling.getSpellingRecord().getValueAsInt("Version")); - // Verify that explicitly specified CXX11 and C23 spellings (i.e. - // not inferred from Clang/GCC spellings) have a version that's - // different than the default (1). - bool RequiresValidVersion = - (Variety == "CXX11" || Variety == "C23") && - Spelling.getSpellingRecord().getValueAsString("Variety") == Variety; - if (RequiresValidVersion && Scope.empty() && Version == 1) - PrintError(Spelling.getSpellingRecord().getLoc(), - "Standard attributes must have " - "valid version information."); - break; - } + if (Spelling.nameSpace().empty() || Scope == Spelling.nameSpace()) { + Name = Spelling.name(); + Version = static_cast( + Spelling.getSpellingRecord().getValueAsInt("Version")); + // Verify that explicitly specified CXX11 and C23 spellings (i.e. + // not inferred from Clang/GCC spellings) have a version that's + // different from the default (1). + bool RequiresValidVersion = + (Variety == "CXX11" || Variety == "C23") && + Spelling.getSpellingRecord().getValueAsString("Variety") == Variety; + if (RequiresValidVersion && Scope.empty() && Version == 1) + PrintError(Spelling.getSpellingRecord().getLoc(), + "Standard attributes must have " + "valid version information."); } std::string Test; @@ -3509,10 +3511,8 @@ static void GenerateHasAttrSpellingStringSwitch( std::string TestStr = !Test.empty() ? Test + " ? " + llvm::itostr(Version) + " : 0" : llvm::itostr(Version); - for (const auto &S : Spellings) - if (Variety.empty() || (Variety == S.variety() && - (Scope.empty() || Scope == S.nameSpace()))) - OS << " .Case(\"" << S.name() << "\", " << TestStr << ")\n"; + if (Scope.empty() || Scope == Spelling.nameSpace()) + OS << " .Case(\"" << Spelling.name() << "\", " << TestStr << ")\n"; } OS << " .Default(0);\n"; } @@ -3545,8 +3545,11 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { // Separate all of the attributes out into four group: generic, C++11, GNU, // and declspecs. Then generate a big switch statement for each of them. std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); - std::vector Declspec, Microsoft, GNU, Pragma, HLSLSemantic; - std::map> CXX, C23; + std::vector> Declspec, Microsoft, + GNU, Pragma, HLSLSemantic; + std::map>> + CXX, C23; // Walk over the list of all attributes, and split them out based on the // spelling variety. @@ -3555,19 +3558,19 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { for (const auto &SI : Spellings) { const std::string &Variety = SI.variety(); if (Variety == "GNU") - GNU.push_back(R); + GNU.emplace_back(R, SI); else if (Variety == "Declspec") - Declspec.push_back(R); + Declspec.emplace_back(R, SI); else if (Variety == "Microsoft") - Microsoft.push_back(R); + Microsoft.emplace_back(R, SI); else if (Variety == "CXX11") - CXX[SI.nameSpace()].push_back(R); + CXX[SI.nameSpace()].emplace_back(R, SI); else if (Variety == "C23") - C23[SI.nameSpace()].push_back(R); + C23[SI.nameSpace()].emplace_back(R, SI); else if (Variety == "Pragma") - Pragma.push_back(R); + Pragma.emplace_back(R, SI); else if (Variety == "HLSLSemantic") - HLSLSemantic.push_back(R); + HLSLSemantic.emplace_back(R, SI); } } @@ -3589,7 +3592,10 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { OS << " return llvm::StringSwitch(Name)\n"; GenerateHasAttrSpellingStringSwitch(HLSLSemantic, OS, "HLSLSemantic"); auto fn = [&OS](const char *Spelling, - const std::map> &List) { + const std::map< + std::string, + std::vector>> + &List) { OS << "case AttributeCommonInfo::Syntax::AS_" << Spelling << ": {\n"; // C++11-style attributes are further split out based on the Scope. for (auto I = List.cbegin(), E = List.cend(); I != E; ++I) { diff --git a/clang/www/c_status.html b/clang/www/c_status.html index 99e5c0109d4ff..13bb1971c61de 100644 --- a/clang/www/c_status.html +++ b/clang/www/c_status.html @@ -1186,12 +1186,12 @@

C23 implementation status

Underspecified object definitions N3006 - Unknown + No Type inference for object declarations N3007 - No + Clang 18 constexpr for object definitions diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt index 514ac250075a8..1a46f5b334806 100644 --- a/compiler-rt/CMakeLists.txt +++ b/compiler-rt/CMakeLists.txt @@ -5,7 +5,9 @@ cmake_minimum_required(VERSION 3.20.0) -set(LLVM_COMMON_CMAKE_UTILS "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") +if(NOT DEFINED LLVM_COMMON_CMAKE_UTILS) + set(LLVM_COMMON_CMAKE_UTILS ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) +endif() include(${LLVM_COMMON_CMAKE_UTILS}/Modules/CMakePolicy.cmake NO_POLICY_SCOPE) diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake index 09a9b62ce4cd3..a8e078f1ebc98 100644 --- a/compiler-rt/cmake/config-ix.cmake +++ b/compiler-rt/cmake/config-ix.cmake @@ -63,6 +63,16 @@ if (C_SUPPORTS_NODEFAULTLIBS_FLAG) moldname mingwex msvcrt) list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES}) endif() + if (NOT TARGET unwind) + # Don't check for a library named unwind, if there's a target with that name within + # the same build. + check_library_exists(unwind _Unwind_GetRegionStart "" COMPILER_RT_HAS_LIBUNWIND) + if (COMPILER_RT_HAS_LIBUNWIND) + # If we're omitting default libraries, we might need to manually link in libunwind. + # This can affect whether we detect a statically linked libc++ correctly. + list(APPEND CMAKE_REQUIRED_LIBRARIES unwind) + endif() + endif() endif () # CodeGen options. diff --git a/compiler-rt/include/fuzzer/FuzzedDataProvider.h b/compiler-rt/include/fuzzer/FuzzedDataProvider.h index 8a8214bd99fef..5903ed837917c 100644 --- a/compiler-rt/include/fuzzer/FuzzedDataProvider.h +++ b/compiler-rt/include/fuzzer/FuzzedDataProvider.h @@ -158,7 +158,7 @@ FuzzedDataProvider::ConsumeRandomLengthString(size_t max_length) { // picking its contents. std::string result; - // Reserve the anticipated capaticity to prevent several reallocations. + // Reserve the anticipated capacity to prevent several reallocations. result.reserve(std::min(max_length, remaining_bytes_)); for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) { char next = ConvertUnsignedToSigned(data_ptr_[0]); diff --git a/compiler-rt/lib/asan_abi/asan_abi.cpp b/compiler-rt/lib/asan_abi/asan_abi.cpp index 74efcb158bd13..cf8663024eb73 100644 --- a/compiler-rt/lib/asan_abi/asan_abi.cpp +++ b/compiler-rt/lib/asan_abi/asan_abi.cpp @@ -86,22 +86,4 @@ void *__asan_abi_stack_malloc_always_n(size_t scale, size_t size) { // Functions concerning fake stack free void __asan_abi_stack_free_n(int scale, void *p, size_t n) {} - -// Functions concerning introspection (including lldb support) -void *__asan_abi_get_alloc_stack(void *addr, void **trace, size_t size, - int *thread_id) { - return NULL; -} -void __asan_abi_report_error(void *pc, void *bp, void *sp, void *addr, - bool is_write, size_t access_size, int exp) {} -void __asan_abi_set_error_report_callback(void (*callback)(const char *)) {} -void __asan_abi_describe_address(void *addr) {} -bool __asan_abi_report_present(void) { return false; } -void *__asan_abi_get_report_pc(void) { return NULL; } -void *__asan_abi_get_report_bp(void) { return NULL; } -void *__asan_abi_get_report_sp(void) { return NULL; } -void *__asan_abi_get_report_address(void) { return NULL; } -int __asan_abi_get_report_access_type(void) { return 0; } -size_t __asan_abi_get_report_access_size(void) { return 0; } -const char *__asan_abi_get_report_description(void) { return NULL; } } diff --git a/compiler-rt/lib/asan_abi/asan_abi.h b/compiler-rt/lib/asan_abi/asan_abi.h index 546af3822e50b..8702bcd133919 100644 --- a/compiler-rt/lib/asan_abi/asan_abi.h +++ b/compiler-rt/lib/asan_abi/asan_abi.h @@ -87,21 +87,5 @@ void *__asan_abi_stack_malloc_always_n(size_t scale, size_t size); // Functions concerning fake stack free void __asan_abi_stack_free_n(int scale, void *p, size_t n); -// Functions concerning introspection (including lldb support) -void *__asan_abi_get_alloc_stack(void *addr, void **trace, size_t size, - int *thread_id); -void __asan_abi_report_error(void *pc, void *bp, void *sp, void *addr, - bool is_write, size_t access_size, int exp); -void __asan_abi_set_error_report_callback(void (*callback)(const char *)); -void __asan_abi_describe_address(void *addr); -bool __asan_abi_report_present(void); -void *__asan_abi_get_report_pc(void); -void *__asan_abi_get_report_bp(void); -void *__asan_abi_get_report_sp(void); -void *__asan_abi_get_report_address(void); -int __asan_abi_get_report_access_type(void); -size_t __asan_abi_get_report_access_size(void); -const char *__asan_abi_get_report_description(void); - __END_DECLS #endif // ASAN_ABI_H diff --git a/compiler-rt/lib/asan_abi/asan_abi_shim.cpp b/compiler-rt/lib/asan_abi/asan_abi_shim.cpp index f039bf7c7f6d7..bf3cba3178efb 100644 --- a/compiler-rt/lib/asan_abi/asan_abi_shim.cpp +++ b/compiler-rt/lib/asan_abi/asan_abi_shim.cpp @@ -478,37 +478,4 @@ void __asan_stack_free_9(uptr ptr, uptr size) { void __asan_stack_free_10(uptr ptr, uptr size) { __asan_abi_stack_free_n(10, (void *)ptr, size); } - -// Functions concerning introspection (including lldb support) -uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) { - return (uptr)__asan_abi_get_alloc_stack((void *)addr, (void **)trace, - (size_t)size, (int *)thread_id); -} -void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, - uptr access_size, u32 exp) { - __asan_abi_report_error((void *)pc, (void *)bp, (void *)sp, (void *)addr, - (bool)is_write, (size_t)access_size, (int)exp); -} -void __asan_set_error_report_callback(void (*callback)(const char *)) { - __asan_abi_set_error_report_callback(callback); -} -void __asan_describe_address(uptr addr) { - __asan_abi_describe_address((void *)addr); -} -int __asan_report_present(void) { return __asan_abi_report_present(); } -uptr __asan_get_report_pc(void) { return (uptr)__asan_abi_get_report_pc(); } -uptr __asan_get_report_bp(void) { return (uptr)__asan_abi_get_report_bp(); } -uptr __asan_get_report_sp(void) { return (uptr)__asan_abi_get_report_sp(); } -uptr __asan_get_report_address(void) { - return (uptr)__asan_abi_get_report_address(); -} -int __asan_get_report_access_type(void) { - return __asan_abi_get_report_access_type(); -} -uptr __asan_get_report_access_size(void) { - return (uptr)__asan_abi_get_report_access_size(); -} -const char *__asan_get_report_description(void) { - return __asan_abi_get_report_description(); -} } diff --git a/compiler-rt/lib/asan_abi/asan_abi_tbd.txt b/compiler-rt/lib/asan_abi/asan_abi_tbd.txt index 2022c0b94283e..a712093d7b213 100644 --- a/compiler-rt/lib/asan_abi/asan_abi_tbd.txt +++ b/compiler-rt/lib/asan_abi/asan_abi_tbd.txt @@ -8,3 +8,15 @@ __asan_on_error __asan_print_accumulated_stats __asan_set_death_callback __asan_update_allocation_context +__asan_describe_address +__asan_get_alloc_stack +__asan_get_report_access_size +__asan_get_report_access_type +__asan_get_report_address +__asan_get_report_bp +__asan_get_report_description +__asan_get_report_pc +__asan_get_report_sp +__asan_report_error +__asan_report_present +__asan_set_error_report_callback diff --git a/compiler-rt/lib/interception/interception_win.cpp b/compiler-rt/lib/interception/interception_win.cpp index 23d26ea94b51a..d57afa3fda7bc 100644 --- a/compiler-rt/lib/interception/interception_win.cpp +++ b/compiler-rt/lib/interception/interception_win.cpp @@ -726,16 +726,22 @@ static bool CopyInstructions(uptr to, uptr from, size_t size) { size_t instruction_size = GetInstructionSize(from + cursor, &rel_offset); if (!instruction_size) return false; - _memcpy((void*)(to + cursor), (void*)(from + cursor), + _memcpy((void *)(to + cursor), (void *)(from + cursor), (size_t)instruction_size); if (rel_offset) { - uptr delta = to - from; - uptr relocated_offset = *(u32*)(to + cursor + rel_offset) - delta; -#if SANITIZER_WINDOWS64 - if (relocated_offset + 0x80000000U >= 0xFFFFFFFFU) +# if SANITIZER_WINDOWS64 + // we want to make sure that the new relative offset still fits in 32-bits + // this will be untrue if relocated_offset \notin [-2**31, 2**31) + s64 delta = to - from; + s64 relocated_offset = *(s32 *)(to + cursor + rel_offset) - delta; + if (-0x8000'0000ll > relocated_offset || relocated_offset > 0x7FFF'FFFFll) return false; -#endif - *(u32*)(to + cursor + rel_offset) = relocated_offset; +# else + // on 32-bit, the relative offset will always be correct + s32 delta = to - from; + s32 relocated_offset = *(s32 *)(to + cursor + rel_offset) - delta; +# endif + *(s32 *)(to + cursor + rel_offset) = relocated_offset; } cursor += instruction_size; } diff --git a/compiler-rt/lib/scudo/standalone/CMakeLists.txt b/compiler-rt/lib/scudo/standalone/CMakeLists.txt index 2b7a613066b83..c4d3ea1e4f05b 100644 --- a/compiler-rt/lib/scudo/standalone/CMakeLists.txt +++ b/compiler-rt/lib/scudo/standalone/CMakeLists.txt @@ -56,6 +56,7 @@ if(ANDROID) endif() set(SCUDO_HEADERS + allocator_common.h allocator_config.h atomic_helpers.h bytemap.h diff --git a/compiler-rt/lib/scudo/standalone/allocator_common.h b/compiler-rt/lib/scudo/standalone/allocator_common.h new file mode 100644 index 0000000000000..95f4776ac596d --- /dev/null +++ b/compiler-rt/lib/scudo/standalone/allocator_common.h @@ -0,0 +1,85 @@ +//===-- allocator_common.h --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_ALLOCATOR_COMMON_H_ +#define SCUDO_ALLOCATOR_COMMON_H_ + +#include "common.h" +#include "list.h" + +namespace scudo { + +template struct TransferBatch { + typedef typename SizeClassAllocator::SizeClassMap SizeClassMap; + typedef typename SizeClassAllocator::CompactPtrT CompactPtrT; + + static const u16 MaxNumCached = SizeClassMap::MaxNumCachedHint; + void setFromArray(CompactPtrT *Array, u16 N) { + DCHECK_LE(N, MaxNumCached); + Count = N; + memcpy(Batch, Array, sizeof(Batch[0]) * Count); + } + void appendFromArray(CompactPtrT *Array, u16 N) { + DCHECK_LE(N, MaxNumCached - Count); + memcpy(Batch + Count, Array, sizeof(Batch[0]) * N); + // u16 will be promoted to int by arithmetic type conversion. + Count = static_cast(Count + N); + } + void appendFromTransferBatch(TransferBatch *B, u16 N) { + DCHECK_LE(N, MaxNumCached - Count); + DCHECK_GE(B->Count, N); + // Append from the back of `B`. + memcpy(Batch + Count, B->Batch + (B->Count - N), sizeof(Batch[0]) * N); + // u16 will be promoted to int by arithmetic type conversion. + Count = static_cast(Count + N); + B->Count = static_cast(B->Count - N); + } + void clear() { Count = 0; } + void add(CompactPtrT P) { + DCHECK_LT(Count, MaxNumCached); + Batch[Count++] = P; + } + void moveToArray(CompactPtrT *Array) { + memcpy(Array, Batch, sizeof(Batch[0]) * Count); + clear(); + } + u16 getCount() const { return Count; } + bool isEmpty() const { return Count == 0U; } + CompactPtrT get(u16 I) const { + DCHECK_LE(I, Count); + return Batch[I]; + } + TransferBatch *Next; + +private: + CompactPtrT Batch[MaxNumCached]; + u16 Count; +}; + +// A BatchGroup is used to collect blocks. Each group has a group id to +// identify the group kind of contained blocks. +template struct BatchGroup { + // `Next` is used by IntrusiveList. + BatchGroup *Next; + // The compact base address of each group + uptr CompactPtrGroupBase; + // Cache value of SizeClassAllocatorLocalCache::getMaxCached() + u16 MaxCachedPerBatch; + // Number of blocks pushed into this group. This is an increment-only + // counter. + uptr PushedBlocks; + // This is used to track how many bytes are not in-use since last time we + // tried to release pages. + uptr BytesInBGAtLastCheckpoint; + // Blocks are managed by TransferBatch in a list. + SinglyLinkedList> Batches; +}; + +} // namespace scudo + +#endif // SCUDO_ALLOCATOR_COMMON_H_ diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h index e4ba6ee7886f2..b1700e5ecef7f 100644 --- a/compiler-rt/lib/scudo/standalone/combined.h +++ b/compiler-rt/lib/scudo/standalone/combined.h @@ -245,12 +245,14 @@ class Allocator { // - unlinking the local stats from the global ones (destroying the cache does // the last two items). void commitBack(TSD *TSD) { + TSD->assertLocked(/*BypassCheck=*/true); Quarantine.drain(&TSD->getQuarantineCache(), QuarantineCallback(*this, TSD->getCache())); TSD->getCache().destroy(&Stats); } void drainCache(TSD *TSD) { + TSD->assertLocked(/*BypassCheck=*/true); Quarantine.drainAndRecycle(&TSD->getQuarantineCache(), QuarantineCallback(*this, TSD->getCache())); TSD->getCache().drain(); @@ -363,11 +365,11 @@ class Allocator { DCHECK_NE(ClassId, 0U); bool UnlockRequired; auto *TSD = TSDRegistry.getTSDAndLock(&UnlockRequired); + TSD->assertLocked(/*BypassCheck=*/!UnlockRequired); Block = TSD->getCache().allocate(ClassId); - // If the allocation failed, the most likely reason with a 32-bit primary - // is the region being full. In that event, retry in each successively - // larger class until it fits. If it fails to fit in the largest class, - // fallback to the Secondary. + // If the allocation failed, retry in each successively larger class until + // it fits. If it fails to fit in the largest class, fallback to the + // Secondary. if (UNLIKELY(!Block)) { while (ClassId < SizeClassMap::LargestClassId && !Block) Block = TSD->getCache().allocate(++ClassId); @@ -385,6 +387,7 @@ class Allocator { if (UNLIKELY(!Block)) { if (Options.get(OptionBit::MayReturnNull)) return nullptr; + printStats(); reportOutOfMemory(NeededSize); } @@ -1147,6 +1150,7 @@ class Allocator { if (LIKELY(ClassId)) { bool UnlockRequired; auto *TSD = TSDRegistry.getTSDAndLock(&UnlockRequired); + TSD->assertLocked(/*BypassCheck=*/!UnlockRequired); const bool CacheDrained = TSD->getCache().deallocate(ClassId, BlockBegin); if (UnlockRequired) @@ -1166,6 +1170,7 @@ class Allocator { } else { bool UnlockRequired; auto *TSD = TSDRegistry.getTSDAndLock(&UnlockRequired); + TSD->assertLocked(/*BypassCheck=*/!UnlockRequired); Quarantine.put(&TSD->getQuarantineCache(), QuarantineCallback(*this, TSD->getCache()), Ptr, Size); if (UnlockRequired) diff --git a/compiler-rt/lib/scudo/standalone/local_cache.h b/compiler-rt/lib/scudo/standalone/local_cache.h index 1095eb5f186d1..1814272277ff4 100644 --- a/compiler-rt/lib/scudo/standalone/local_cache.h +++ b/compiler-rt/lib/scudo/standalone/local_cache.h @@ -22,74 +22,6 @@ template struct SizeClassAllocatorLocalCache { typedef typename SizeClassAllocator::SizeClassMap SizeClassMap; typedef typename SizeClassAllocator::CompactPtrT CompactPtrT; - struct TransferBatch { - static const u16 MaxNumCached = SizeClassMap::MaxNumCachedHint; - void setFromArray(CompactPtrT *Array, u16 N) { - DCHECK_LE(N, MaxNumCached); - Count = N; - memcpy(Batch, Array, sizeof(Batch[0]) * Count); - } - void appendFromArray(CompactPtrT *Array, u16 N) { - DCHECK_LE(N, MaxNumCached - Count); - memcpy(Batch + Count, Array, sizeof(Batch[0]) * N); - // u16 will be promoted to int by arithmetic type conversion. - Count = static_cast(Count + N); - } - void appendFromTransferBatch(TransferBatch *B, u16 N) { - DCHECK_LE(N, MaxNumCached - Count); - DCHECK_GE(B->Count, N); - // Append from the back of `B`. - memcpy(Batch + Count, B->Batch + (B->Count - N), sizeof(Batch[0]) * N); - // u16 will be promoted to int by arithmetic type conversion. - Count = static_cast(Count + N); - B->Count = static_cast(B->Count - N); - } - void clear() { Count = 0; } - void add(CompactPtrT P) { - DCHECK_LT(Count, MaxNumCached); - Batch[Count++] = P; - } - void copyToArray(CompactPtrT *Array) const { - memcpy(Array, Batch, sizeof(Batch[0]) * Count); - } - u16 getCount() const { return Count; } - bool isEmpty() const { return Count == 0U; } - CompactPtrT get(u16 I) const { - DCHECK_LE(I, Count); - return Batch[I]; - } - static u16 getMaxCached(uptr Size) { - return Min(MaxNumCached, SizeClassMap::getMaxCachedHint(Size)); - } - TransferBatch *Next; - - private: - CompactPtrT Batch[MaxNumCached]; - u16 Count; - }; - - // A BatchGroup is used to collect blocks. Each group has a group id to - // identify the group kind of contained blocks. - struct BatchGroup { - // `Next` is used by IntrusiveList. - BatchGroup *Next; - // The compact base address of each group - uptr CompactPtrGroupBase; - // Cache value of TransferBatch::getMaxCached() - u16 MaxCachedPerBatch; - // Number of blocks pushed into this group. This is an increment-only - // counter. - uptr PushedBlocks; - // This is used to track how many bytes are not in-use since last time we - // tried to release pages. - uptr BytesInBGAtLastCheckpoint; - // Blocks are managed by TransferBatch in a list. - SinglyLinkedList Batches; - }; - - static_assert(sizeof(BatchGroup) <= sizeof(TransferBatch), - "BatchGroup uses the same class size as TransferBatch"); - void init(GlobalStats *S, SizeClassAllocator *A) { DCHECK(isEmpty()); Stats.init(); @@ -151,7 +83,7 @@ template struct SizeClassAllocatorLocalCache { } void drain() { - // Drain BatchClassId last as createBatch can refill it. + // Drain BatchClassId last as it may be needed while draining normal blocks. for (uptr I = 0; I < NumClasses; ++I) { if (I == BatchClassId) continue; @@ -163,19 +95,11 @@ template struct SizeClassAllocatorLocalCache { DCHECK(isEmpty()); } - TransferBatch *createBatch(uptr ClassId, void *B) { - if (ClassId != BatchClassId) - B = allocate(BatchClassId); + void *getBatchClassBlock() { + void *B = allocate(BatchClassId); if (UNLIKELY(!B)) reportOutOfMemory(SizeClassAllocator::getSizeByClassId(BatchClassId)); - return reinterpret_cast(B); - } - - BatchGroup *createGroup() { - void *Ptr = allocate(BatchClassId); - if (UNLIKELY(!Ptr)) - reportOutOfMemory(SizeClassAllocator::getSizeByClassId(BatchClassId)); - return reinterpret_cast(Ptr); + return B; } LocalStats &getStats() { return Stats; } @@ -203,6 +127,11 @@ template struct SizeClassAllocatorLocalCache { Str->append(" No block is cached.\n"); } + static u16 getMaxCached(uptr Size) { + return Min(SizeClassMap::MaxNumCachedHint, + SizeClassMap::getMaxCachedHint(Size)); + } + private: static const uptr NumClasses = SizeClassMap::NumClasses; static const uptr BatchClassId = SizeClassMap::BatchClassId; @@ -211,7 +140,7 @@ template struct SizeClassAllocatorLocalCache { u16 MaxCount; // Note: ClassSize is zero for the transfer batch. uptr ClassSize; - CompactPtrT Chunks[2 * TransferBatch::MaxNumCached]; + CompactPtrT Chunks[2 * SizeClassMap::MaxNumCachedHint]; }; PerClass PerClassArray[NumClasses] = {}; LocalStats Stats; @@ -228,7 +157,7 @@ template struct SizeClassAllocatorLocalCache { for (uptr I = 0; I < NumClasses; I++) { PerClass *P = &PerClassArray[I]; const uptr Size = SizeClassAllocator::getSizeByClassId(I); - P->MaxCount = static_cast(2 * TransferBatch::getMaxCached(Size)); + P->MaxCount = static_cast(2 * getMaxCached(Size)); if (I != BatchClassId) { P->ClassSize = Size; } else { @@ -246,15 +175,14 @@ template struct SizeClassAllocatorLocalCache { NOINLINE bool refill(PerClass *C, uptr ClassId) { initCacheMaybe(C); - TransferBatch *B = Allocator->popBatch(this, ClassId); - if (UNLIKELY(!B)) - return false; - DCHECK_GT(B->getCount(), 0); - C->Count = B->getCount(); - B->copyToArray(C->Chunks); - B->clear(); - destroyBatch(ClassId, B); - return true; + + // TODO(chiahungduan): Pass the max number cached for each size class. + const u16 NumBlocksRefilled = + Allocator->popBlocks(this, ClassId, C->Chunks); + DCHECK_LE(NumBlocksRefilled, + getMaxCached(SizeClassAllocator::getSizeByClassId(ClassId))); + C->Count = static_cast(C->Count + NumBlocksRefilled); + return NumBlocksRefilled != 0; } NOINLINE void drain(PerClass *C, uptr ClassId) { diff --git a/compiler-rt/lib/scudo/standalone/primary32.h b/compiler-rt/lib/scudo/standalone/primary32.h index 533615ad3816d..c900550ac675e 100644 --- a/compiler-rt/lib/scudo/standalone/primary32.h +++ b/compiler-rt/lib/scudo/standalone/primary32.h @@ -9,6 +9,7 @@ #ifndef SCUDO_PRIMARY32_H_ #define SCUDO_PRIMARY32_H_ +#include "allocator_common.h" #include "bytemap.h" #include "common.h" #include "list.h" @@ -53,12 +54,15 @@ template class SizeClassAllocator32 { ""); typedef SizeClassAllocator32 ThisT; typedef SizeClassAllocatorLocalCache CacheT; - typedef typename CacheT::TransferBatch TransferBatch; - typedef typename CacheT::BatchGroup BatchGroup; + typedef TransferBatch TransferBatchT; + typedef BatchGroup BatchGroupT; + + static_assert(sizeof(BatchGroupT) <= sizeof(TransferBatchT), + "BatchGroupT uses the same class size as TransferBatchT"); static uptr getSizeByClassId(uptr ClassId) { return (ClassId == SizeClassMap::BatchClassId) - ? sizeof(TransferBatch) + ? sizeof(TransferBatchT) : SizeClassMap::getSizeByClassId(ClassId); } @@ -126,7 +130,7 @@ template class SizeClassAllocator32 { SizeClassInfo *Sci = getSizeClassInfo(I); ScopedLock L1(Sci->Mutex); uptr TotalBlocks = 0; - for (BatchGroup &BG : Sci->FreeListInfo.BlockList) { + for (BatchGroupT &BG : Sci->FreeListInfo.BlockList) { // `BG::Batches` are `TransferBatches`. +1 for `BatchGroup`. BatchClassUsedInFreeLists += BG.Batches.size() + 1; for (const auto &It : BG.Batches) @@ -141,7 +145,7 @@ template class SizeClassAllocator32 { SizeClassInfo *Sci = getSizeClassInfo(SizeClassMap::BatchClassId); ScopedLock L1(Sci->Mutex); uptr TotalBlocks = 0; - for (BatchGroup &BG : Sci->FreeListInfo.BlockList) { + for (BatchGroupT &BG : Sci->FreeListInfo.BlockList) { if (LIKELY(!BG.Batches.empty())) { for (const auto &It : BG.Batches) TotalBlocks += It.getCount(); @@ -187,11 +191,26 @@ template class SizeClassAllocator32 { return BlockSize > PageSize; } - TransferBatch *popBatch(CacheT *C, uptr ClassId) { + u16 popBlocks(CacheT *C, uptr ClassId, CompactPtrT *ToArray) { + TransferBatchT *B = popBatch(C, ClassId); + if (!B) + return 0; + + const u16 Count = B->getCount(); + DCHECK_GT(Count, 0U); + B->moveToArray(ToArray); + + if (ClassId != SizeClassMap::BatchClassId) + C->deallocate(SizeClassMap::BatchClassId, B); + + return Count; + } + + TransferBatchT *popBatch(CacheT *C, uptr ClassId) { DCHECK_LT(ClassId, NumClasses); SizeClassInfo *Sci = getSizeClassInfo(ClassId); ScopedLock L(Sci->Mutex); - TransferBatch *B = popBatchImpl(C, ClassId, Sci); + TransferBatchT *B = popBatchImpl(C, ClassId, Sci); if (UNLIKELY(!B)) { if (UNLIKELY(!populateFreeList(C, ClassId, Sci))) return nullptr; @@ -381,7 +400,7 @@ template class SizeClassAllocator32 { }; struct BlocksInfo { - SinglyLinkedList BlockList = {}; + SinglyLinkedList BlockList = {}; uptr PoppedBlocks = 0; uptr PushedBlocks = 0; }; @@ -505,11 +524,11 @@ template class SizeClassAllocator32 { // reusable and don't need additional space for them. Sci->FreeListInfo.PushedBlocks += Size; - BatchGroup *BG = Sci->FreeListInfo.BlockList.front(); + BatchGroupT *BG = Sci->FreeListInfo.BlockList.front(); if (BG == nullptr) { // Construct `BatchGroup` on the last element. - BG = reinterpret_cast( + BG = reinterpret_cast( decompactPtr(SizeClassMap::BatchClassId, Array[Size - 1])); --Size; BG->Batches.clear(); @@ -520,8 +539,8 @@ template class SizeClassAllocator32 { // from `CreateGroup` in `pushBlocksImpl` BG->PushedBlocks = 1; BG->BytesInBGAtLastCheckpoint = 0; - BG->MaxCachedPerBatch = TransferBatch::getMaxCached( - getSizeByClassId(SizeClassMap::BatchClassId)); + BG->MaxCachedPerBatch = + CacheT::getMaxCached(getSizeByClassId(SizeClassMap::BatchClassId)); Sci->FreeListInfo.BlockList.push_front(BG); } @@ -534,7 +553,7 @@ template class SizeClassAllocator32 { // 2. Only 1 block is pushed when the freelist is empty. if (BG->Batches.empty()) { // Construct the `TransferBatch` on the last element. - TransferBatch *TB = reinterpret_cast( + TransferBatchT *TB = reinterpret_cast( decompactPtr(SizeClassMap::BatchClassId, Array[Size - 1])); TB->clear(); // As mentioned above, addresses of `TransferBatch` and `BatchGroup` are @@ -549,14 +568,14 @@ template class SizeClassAllocator32 { BG->Batches.push_front(TB); } - TransferBatch *CurBatch = BG->Batches.front(); + TransferBatchT *CurBatch = BG->Batches.front(); DCHECK_NE(CurBatch, nullptr); for (u32 I = 0; I < Size;) { u16 UnusedSlots = static_cast(BG->MaxCachedPerBatch - CurBatch->getCount()); if (UnusedSlots == 0) { - CurBatch = reinterpret_cast( + CurBatch = reinterpret_cast( decompactPtr(SizeClassMap::BatchClassId, Array[I])); CurBatch->clear(); // Self-contained @@ -600,24 +619,25 @@ template class SizeClassAllocator32 { DCHECK_GT(Size, 0U); auto CreateGroup = [&](uptr CompactPtrGroupBase) { - BatchGroup *BG = C->createGroup(); + BatchGroupT *BG = + reinterpret_cast(C->getBatchClassBlock()); BG->Batches.clear(); - TransferBatch *TB = C->createBatch(ClassId, nullptr); + TransferBatchT *TB = + reinterpret_cast(C->getBatchClassBlock()); TB->clear(); BG->CompactPtrGroupBase = CompactPtrGroupBase; BG->Batches.push_front(TB); BG->PushedBlocks = 0; BG->BytesInBGAtLastCheckpoint = 0; - BG->MaxCachedPerBatch = - TransferBatch::getMaxCached(getSizeByClassId(ClassId)); + BG->MaxCachedPerBatch = CacheT::getMaxCached(getSizeByClassId(ClassId)); return BG; }; - auto InsertBlocks = [&](BatchGroup *BG, CompactPtrT *Array, u32 Size) { - SinglyLinkedList &Batches = BG->Batches; - TransferBatch *CurBatch = Batches.front(); + auto InsertBlocks = [&](BatchGroupT *BG, CompactPtrT *Array, u32 Size) { + SinglyLinkedList &Batches = BG->Batches; + TransferBatchT *CurBatch = Batches.front(); DCHECK_NE(CurBatch, nullptr); for (u32 I = 0; I < Size;) { @@ -625,9 +645,8 @@ template class SizeClassAllocator32 { u16 UnusedSlots = static_cast(BG->MaxCachedPerBatch - CurBatch->getCount()); if (UnusedSlots == 0) { - CurBatch = C->createBatch( - ClassId, - reinterpret_cast(decompactPtr(ClassId, Array[I]))); + CurBatch = + reinterpret_cast(C->getBatchClassBlock()); CurBatch->clear(); Batches.push_front(CurBatch); UnusedSlots = BG->MaxCachedPerBatch; @@ -642,11 +661,11 @@ template class SizeClassAllocator32 { }; Sci->FreeListInfo.PushedBlocks += Size; - BatchGroup *Cur = Sci->FreeListInfo.BlockList.front(); + BatchGroupT *Cur = Sci->FreeListInfo.BlockList.front(); // In the following, `Cur` always points to the BatchGroup for blocks that // will be pushed next. `Prev` is the element right before `Cur`. - BatchGroup *Prev = nullptr; + BatchGroupT *Prev = nullptr; while (Cur != nullptr && compactPtrGroupBase(Array[0]) > Cur->CompactPtrGroupBase) { @@ -707,22 +726,22 @@ template class SizeClassAllocator32 { // group id will be considered first. // // The region mutex needs to be held while calling this method. - TransferBatch *popBatchImpl(CacheT *C, uptr ClassId, SizeClassInfo *Sci) + TransferBatchT *popBatchImpl(CacheT *C, uptr ClassId, SizeClassInfo *Sci) REQUIRES(Sci->Mutex) { if (Sci->FreeListInfo.BlockList.empty()) return nullptr; - SinglyLinkedList &Batches = + SinglyLinkedList &Batches = Sci->FreeListInfo.BlockList.front()->Batches; if (Batches.empty()) { DCHECK_EQ(ClassId, SizeClassMap::BatchClassId); - BatchGroup *BG = Sci->FreeListInfo.BlockList.front(); + BatchGroupT *BG = Sci->FreeListInfo.BlockList.front(); Sci->FreeListInfo.BlockList.pop_front(); // Block used by `BatchGroup` is from BatchClassId. Turn the block into // `TransferBatch` with single block. - TransferBatch *TB = reinterpret_cast(BG); + TransferBatchT *TB = reinterpret_cast(BG); TB->clear(); TB->add( compactPtr(SizeClassMap::BatchClassId, reinterpret_cast(TB))); @@ -730,13 +749,13 @@ template class SizeClassAllocator32 { return TB; } - TransferBatch *B = Batches.front(); + TransferBatchT *B = Batches.front(); Batches.pop_front(); DCHECK_NE(B, nullptr); DCHECK_GT(B->getCount(), 0U); if (Batches.empty()) { - BatchGroup *BG = Sci->FreeListInfo.BlockList.front(); + BatchGroupT *BG = Sci->FreeListInfo.BlockList.front(); Sci->FreeListInfo.BlockList.pop_front(); // We don't keep BatchGroup with zero blocks to avoid empty-checking while @@ -775,7 +794,7 @@ template class SizeClassAllocator32 { } const uptr Size = getSizeByClassId(ClassId); - const u16 MaxCount = TransferBatch::getMaxCached(Size); + const u16 MaxCount = CacheT::getMaxCached(Size); DCHECK_GT(MaxCount, 0U); // The maximum number of blocks we should carve in the region is dictated // by the maximum number of batches we want to fill, and the amount of @@ -788,7 +807,7 @@ template class SizeClassAllocator32 { DCHECK_GT(NumberOfBlocks, 0U); constexpr u32 ShuffleArraySize = - MaxNumBatches * TransferBatch::MaxNumCached; + MaxNumBatches * TransferBatchT::MaxNumCached; // Fill the transfer batches and put them in the size-class freelist. We // need to randomize the blocks for security purposes, so we first fill a // local array that we then shuffle before populating the batches. @@ -1053,7 +1072,7 @@ template class SizeClassAllocator32 { auto DecompactPtr = [](CompactPtrT CompactPtr) { return reinterpret_cast(CompactPtr); }; - for (BatchGroup &BG : Sci->FreeListInfo.BlockList) { + for (BatchGroupT &BG : Sci->FreeListInfo.BlockList) { const uptr GroupBase = decompactGroupBase(BG.CompactPtrGroupBase); // The `GroupSize` may not be divided by `BlockSize`, which means there is // an unused space at the end of Region. Exclude that space to avoid diff --git a/compiler-rt/lib/scudo/standalone/primary64.h b/compiler-rt/lib/scudo/standalone/primary64.h index ed0c4deaac2c8..6e5ab7e3ba796 100644 --- a/compiler-rt/lib/scudo/standalone/primary64.h +++ b/compiler-rt/lib/scudo/standalone/primary64.h @@ -9,6 +9,7 @@ #ifndef SCUDO_PRIMARY64_H_ #define SCUDO_PRIMARY64_H_ +#include "allocator_common.h" #include "bytemap.h" #include "common.h" #include "list.h" @@ -55,12 +56,15 @@ template class SizeClassAllocator64 { static const uptr GroupScale = GroupSizeLog - CompactPtrScale; typedef SizeClassAllocator64 ThisT; typedef SizeClassAllocatorLocalCache CacheT; - typedef typename CacheT::TransferBatch TransferBatch; - typedef typename CacheT::BatchGroup BatchGroup; + typedef TransferBatch TransferBatchT; + typedef BatchGroup BatchGroupT; + + static_assert(sizeof(BatchGroupT) <= sizeof(TransferBatchT), + "BatchGroupT uses the same class size as TransferBatchT"); static uptr getSizeByClassId(uptr ClassId) { return (ClassId == SizeClassMap::BatchClassId) - ? roundUp(sizeof(TransferBatch), 1U << CompactPtrScale) + ? roundUp(sizeof(TransferBatchT), 1U << CompactPtrScale) : SizeClassMap::getSizeByClassId(ClassId); } @@ -167,7 +171,7 @@ template class SizeClassAllocator64 { ScopedLock FL(Region->FLLock); const uptr BlockSize = getSizeByClassId(I); uptr TotalBlocks = 0; - for (BatchGroup &BG : Region->FreeListInfo.BlockList) { + for (BatchGroupT &BG : Region->FreeListInfo.BlockList) { // `BG::Batches` are `TransferBatches`. +1 for `BatchGroup`. BatchClassUsedInFreeLists += BG.Batches.size() + 1; for (const auto &It : BG.Batches) @@ -184,7 +188,7 @@ template class SizeClassAllocator64 { ScopedLock FL(Region->FLLock); const uptr BlockSize = getSizeByClassId(SizeClassMap::BatchClassId); uptr TotalBlocks = 0; - for (BatchGroup &BG : Region->FreeListInfo.BlockList) { + for (BatchGroupT &BG : Region->FreeListInfo.BlockList) { if (LIKELY(!BG.Batches.empty())) { for (const auto &It : BG.Batches) TotalBlocks += It.getCount(); @@ -203,19 +207,34 @@ template class SizeClassAllocator64 { DCHECK_EQ(BlocksInUse, BatchClassUsedInFreeLists); } - TransferBatch *popBatch(CacheT *C, uptr ClassId) { + u16 popBlocks(CacheT *C, uptr ClassId, CompactPtrT *ToArray) { + TransferBatchT *B = popBatch(C, ClassId); + if (!B) + return 0; + + const u16 Count = B->getCount(); + DCHECK_GT(Count, 0U); + B->moveToArray(ToArray); + + if (ClassId != SizeClassMap::BatchClassId) + C->deallocate(SizeClassMap::BatchClassId, B); + + return Count; + } + + TransferBatchT *popBatch(CacheT *C, uptr ClassId) { DCHECK_LT(ClassId, NumClasses); RegionInfo *Region = getRegionInfo(ClassId); { ScopedLock L(Region->FLLock); - TransferBatch *B = popBatchImpl(C, ClassId, Region); + TransferBatchT *B = popBatchImpl(C, ClassId, Region); if (LIKELY(B)) return B; } - bool PrintStats = false; - TransferBatch *B = nullptr; + bool ReportRegionExhausted = false; + TransferBatchT *B = nullptr; while (true) { // When two threads compete for `Region->MMLock`, we only want one of them @@ -235,19 +254,13 @@ template class SizeClassAllocator64 { const bool RegionIsExhausted = Region->Exhausted; if (!RegionIsExhausted) B = populateFreeListAndPopBatch(C, ClassId, Region); - PrintStats = !RegionIsExhausted && Region->Exhausted; + ReportRegionExhausted = !RegionIsExhausted && Region->Exhausted; break; } - // Note that `getStats()` requires locking each region so we can't call it - // while locking the Region->Mutex in the above. - if (UNLIKELY(PrintStats)) { - ScopedString Str; - getStats(&Str); - Str.append( - "Scudo OOM: The process has exhausted %zuM for size class %zu.\n", - RegionSize >> 20, getSizeByClassId(ClassId)); - Str.output(); + if (UNLIKELY(ReportRegionExhausted)) { + Printf("Can't populate more pages for size class %zu.\n", + getSizeByClassId(ClassId)); // Theoretically, BatchClass shouldn't be used up. Abort immediately when // it happens. @@ -509,7 +522,7 @@ template class SizeClassAllocator64 { }; struct BlocksInfo { - SinglyLinkedList BlockList = {}; + SinglyLinkedList BlockList = {}; uptr PoppedBlocks = 0; uptr PushedBlocks = 0; }; @@ -621,11 +634,11 @@ template class SizeClassAllocator64 { // reusable and don't need additional space for them. Region->FreeListInfo.PushedBlocks += Size; - BatchGroup *BG = Region->FreeListInfo.BlockList.front(); + BatchGroupT *BG = Region->FreeListInfo.BlockList.front(); if (BG == nullptr) { // Construct `BatchGroup` on the last element. - BG = reinterpret_cast( + BG = reinterpret_cast( decompactPtr(SizeClassMap::BatchClassId, Array[Size - 1])); --Size; BG->Batches.clear(); @@ -636,8 +649,8 @@ template class SizeClassAllocator64 { // from `CreateGroup` in `pushBlocksImpl` BG->PushedBlocks = 1; BG->BytesInBGAtLastCheckpoint = 0; - BG->MaxCachedPerBatch = TransferBatch::getMaxCached( - getSizeByClassId(SizeClassMap::BatchClassId)); + BG->MaxCachedPerBatch = + CacheT::getMaxCached(getSizeByClassId(SizeClassMap::BatchClassId)); Region->FreeListInfo.BlockList.push_front(BG); } @@ -650,7 +663,7 @@ template class SizeClassAllocator64 { // 2. Only 1 block is pushed when the freelist is empty. if (BG->Batches.empty()) { // Construct the `TransferBatch` on the last element. - TransferBatch *TB = reinterpret_cast( + TransferBatchT *TB = reinterpret_cast( decompactPtr(SizeClassMap::BatchClassId, Array[Size - 1])); TB->clear(); // As mentioned above, addresses of `TransferBatch` and `BatchGroup` are @@ -665,14 +678,14 @@ template class SizeClassAllocator64 { BG->Batches.push_front(TB); } - TransferBatch *CurBatch = BG->Batches.front(); + TransferBatchT *CurBatch = BG->Batches.front(); DCHECK_NE(CurBatch, nullptr); for (u32 I = 0; I < Size;) { u16 UnusedSlots = static_cast(BG->MaxCachedPerBatch - CurBatch->getCount()); if (UnusedSlots == 0) { - CurBatch = reinterpret_cast( + CurBatch = reinterpret_cast( decompactPtr(SizeClassMap::BatchClassId, Array[I])); CurBatch->clear(); // Self-contained @@ -715,24 +728,25 @@ template class SizeClassAllocator64 { DCHECK_GT(Size, 0U); auto CreateGroup = [&](uptr CompactPtrGroupBase) { - BatchGroup *BG = C->createGroup(); + BatchGroupT *BG = + reinterpret_cast(C->getBatchClassBlock()); BG->Batches.clear(); - TransferBatch *TB = C->createBatch(ClassId, nullptr); + TransferBatchT *TB = + reinterpret_cast(C->getBatchClassBlock()); TB->clear(); BG->CompactPtrGroupBase = CompactPtrGroupBase; BG->Batches.push_front(TB); BG->PushedBlocks = 0; BG->BytesInBGAtLastCheckpoint = 0; - BG->MaxCachedPerBatch = - TransferBatch::getMaxCached(getSizeByClassId(ClassId)); + BG->MaxCachedPerBatch = CacheT::getMaxCached(getSizeByClassId(ClassId)); return BG; }; - auto InsertBlocks = [&](BatchGroup *BG, CompactPtrT *Array, u32 Size) { - SinglyLinkedList &Batches = BG->Batches; - TransferBatch *CurBatch = Batches.front(); + auto InsertBlocks = [&](BatchGroupT *BG, CompactPtrT *Array, u32 Size) { + SinglyLinkedList &Batches = BG->Batches; + TransferBatchT *CurBatch = Batches.front(); DCHECK_NE(CurBatch, nullptr); for (u32 I = 0; I < Size;) { @@ -740,9 +754,8 @@ template class SizeClassAllocator64 { u16 UnusedSlots = static_cast(BG->MaxCachedPerBatch - CurBatch->getCount()); if (UnusedSlots == 0) { - CurBatch = C->createBatch( - ClassId, - reinterpret_cast(decompactPtr(ClassId, Array[I]))); + CurBatch = + reinterpret_cast(C->getBatchClassBlock()); CurBatch->clear(); Batches.push_front(CurBatch); UnusedSlots = BG->MaxCachedPerBatch; @@ -757,11 +770,11 @@ template class SizeClassAllocator64 { }; Region->FreeListInfo.PushedBlocks += Size; - BatchGroup *Cur = Region->FreeListInfo.BlockList.front(); + BatchGroupT *Cur = Region->FreeListInfo.BlockList.front(); // In the following, `Cur` always points to the BatchGroup for blocks that // will be pushed next. `Prev` is the element right before `Cur`. - BatchGroup *Prev = nullptr; + BatchGroupT *Prev = nullptr; while (Cur != nullptr && compactPtrGroup(Array[0]) > Cur->CompactPtrGroupBase) { @@ -822,22 +835,22 @@ template class SizeClassAllocator64 { // group id will be considered first. // // The region mutex needs to be held while calling this method. - TransferBatch *popBatchImpl(CacheT *C, uptr ClassId, RegionInfo *Region) + TransferBatchT *popBatchImpl(CacheT *C, uptr ClassId, RegionInfo *Region) REQUIRES(Region->FLLock) { if (Region->FreeListInfo.BlockList.empty()) return nullptr; - SinglyLinkedList &Batches = + SinglyLinkedList &Batches = Region->FreeListInfo.BlockList.front()->Batches; if (Batches.empty()) { DCHECK_EQ(ClassId, SizeClassMap::BatchClassId); - BatchGroup *BG = Region->FreeListInfo.BlockList.front(); + BatchGroupT *BG = Region->FreeListInfo.BlockList.front(); Region->FreeListInfo.BlockList.pop_front(); // Block used by `BatchGroup` is from BatchClassId. Turn the block into // `TransferBatch` with single block. - TransferBatch *TB = reinterpret_cast(BG); + TransferBatchT *TB = reinterpret_cast(BG); TB->clear(); TB->add( compactPtr(SizeClassMap::BatchClassId, reinterpret_cast(TB))); @@ -845,13 +858,13 @@ template class SizeClassAllocator64 { return TB; } - TransferBatch *B = Batches.front(); + TransferBatchT *B = Batches.front(); Batches.pop_front(); DCHECK_NE(B, nullptr); DCHECK_GT(B->getCount(), 0U); if (Batches.empty()) { - BatchGroup *BG = Region->FreeListInfo.BlockList.front(); + BatchGroupT *BG = Region->FreeListInfo.BlockList.front(); Region->FreeListInfo.BlockList.pop_front(); // We don't keep BatchGroup with zero blocks to avoid empty-checking while @@ -869,11 +882,11 @@ template class SizeClassAllocator64 { } // Refill the freelist and return one batch. - NOINLINE TransferBatch *populateFreeListAndPopBatch(CacheT *C, uptr ClassId, - RegionInfo *Region) + NOINLINE TransferBatchT *populateFreeListAndPopBatch(CacheT *C, uptr ClassId, + RegionInfo *Region) REQUIRES(Region->MMLock) EXCLUDES(Region->FLLock) { const uptr Size = getSizeByClassId(ClassId); - const u16 MaxCount = TransferBatch::getMaxCached(Size); + const u16 MaxCount = CacheT::getMaxCached(Size); const uptr RegionBeg = Region->RegionBeg; const uptr MappedUser = Region->MemMapInfo.MappedUser; @@ -909,7 +922,7 @@ template class SizeClassAllocator64 { DCHECK_GT(NumberOfBlocks, 0); constexpr u32 ShuffleArraySize = - MaxNumBatches * TransferBatch::MaxNumCached; + MaxNumBatches * TransferBatchT::MaxNumCached; CompactPtrT ShuffleArray[ShuffleArraySize]; DCHECK_LE(NumberOfBlocks, ShuffleArraySize); @@ -942,7 +955,7 @@ template class SizeClassAllocator64 { pushBatchClassBlocks(Region, ShuffleArray, NumberOfBlocks); } - TransferBatch *B = popBatchImpl(C, ClassId, Region); + TransferBatchT *B = popBatchImpl(C, ClassId, Region); DCHECK_NE(B, nullptr); // Note that `PushedBlocks` and `PoppedBlocks` are supposed to only record @@ -978,7 +991,7 @@ template class SizeClassAllocator64 { "%s %02zu (%6zu): mapped: %6zuK popped: %7zu pushed: %7zu " "inuse: %6zu total: %6zu releases: %6zu last " "released: %6zuK latest pushed bytes: %6zuK region: 0x%zx (0x%zx)\n", - Region->Exhausted ? "F" : " ", ClassId, getSizeByClassId(ClassId), + Region->Exhausted ? "E" : " ", ClassId, getSizeByClassId(ClassId), Region->MemMapInfo.MappedUser >> 10, Region->FreeListInfo.PoppedBlocks, Region->FreeListInfo.PushedBlocks, InUseBlocks, TotalChunks, Region->ReleaseInfo.RangesReleased, @@ -993,7 +1006,7 @@ template class SizeClassAllocator64 { const uptr AllocatedUserEnd = Region->MemMapInfo.AllocatedUser + Region->RegionBeg; - SinglyLinkedList GroupsToRelease; + SinglyLinkedList GroupsToRelease; { ScopedLock L(Region->FLLock); GroupsToRelease = Region->FreeListInfo.BlockList; @@ -1036,7 +1049,7 @@ template class SizeClassAllocator64 { uptr BytesInFreeList; const uptr AllocatedUserEnd = Region->MemMapInfo.AllocatedUser + Region->RegionBeg; - SinglyLinkedList GroupsToRelease; + SinglyLinkedList GroupsToRelease; { ScopedLock L(Region->FLLock); @@ -1179,13 +1192,13 @@ template class SizeClassAllocator64 { return true; } - SinglyLinkedList + SinglyLinkedList collectGroupsToRelease(RegionInfo *Region, const uptr BlockSize, const uptr AllocatedUserEnd, const uptr CompactPtrBase) REQUIRES(Region->MMLock, Region->FLLock) { const uptr GroupSize = (1UL << GroupSizeLog); const uptr PageSize = getPageSizeCached(); - SinglyLinkedList GroupsToRelease; + SinglyLinkedList GroupsToRelease; // We are examining each group and will take the minimum distance to the // release threshold as the next Region::TryReleaseThreshold(). Note that if @@ -1194,8 +1207,8 @@ template class SizeClassAllocator64 { // the comment on `SmallerBlockReleasePageDelta` for more details. uptr MinDistToThreshold = GroupSize; - for (BatchGroup *BG = Region->FreeListInfo.BlockList.front(), - *Prev = nullptr; + for (BatchGroupT *BG = Region->FreeListInfo.BlockList.front(), + *Prev = nullptr; BG != nullptr;) { // Group boundary is always GroupSize-aligned from CompactPtr base. The // layout of memory groups is like, @@ -1279,7 +1292,7 @@ template class SizeClassAllocator64 { } } - // If `BG` is the first BatchGroup in the list, we only need to advance + // If `BG` is the first BatchGroupT in the list, we only need to advance // `BG` and call FreeListInfo.BlockList::pop_front(). No update is needed // for `Prev`. // @@ -1315,7 +1328,7 @@ template class SizeClassAllocator64 { // Note that we need to advance before pushing this BatchGroup to // GroupsToRelease because it's a destructive operation. - BatchGroup *Cur = BG; + BatchGroupT *Cur = BG; BG = BG->Next; // Ideally, we may want to update this only after successful release. @@ -1348,7 +1361,7 @@ template class SizeClassAllocator64 { PageReleaseContext markFreeBlocks(RegionInfo *Region, const uptr BlockSize, const uptr AllocatedUserEnd, const uptr CompactPtrBase, - SinglyLinkedList &GroupsToRelease) + SinglyLinkedList &GroupsToRelease) REQUIRES(Region->MMLock) EXCLUDES(Region->FLLock) { const uptr GroupSize = (1UL << GroupSizeLog); auto DecompactPtr = [CompactPtrBase](CompactPtrT CompactPtr) { @@ -1377,7 +1390,7 @@ template class SizeClassAllocator64 { if (UNLIKELY(!Context.ensurePageMapAllocated())) return Context; - for (BatchGroup &BG : GroupsToRelease) { + for (BatchGroupT &BG : GroupsToRelease) { const uptr BatchGroupBase = decompactGroupBase(CompactPtrBase, BG.CompactPtrGroupBase); const uptr BatchGroupEnd = BatchGroupBase + GroupSize; @@ -1425,7 +1438,7 @@ template class SizeClassAllocator64 { } void mergeGroupsToReleaseBack(RegionInfo *Region, - SinglyLinkedList &GroupsToRelease) + SinglyLinkedList &GroupsToRelease) REQUIRES(Region->MMLock) EXCLUDES(Region->FLLock) { ScopedLock L(Region->FLLock); @@ -1446,8 +1459,8 @@ template class SizeClassAllocator64 { // Merge GroupsToRelease back to the Region::FreeListInfo.BlockList. Note // that both `Region->FreeListInfo.BlockList` and `GroupsToRelease` are // sorted. - for (BatchGroup *BG = Region->FreeListInfo.BlockList.front(), - *Prev = nullptr; + for (BatchGroupT *BG = Region->FreeListInfo.BlockList.front(), + *Prev = nullptr; ;) { if (BG == nullptr || GroupsToRelease.empty()) { if (!GroupsToRelease.empty()) @@ -1464,8 +1477,8 @@ template class SizeClassAllocator64 { continue; } - BatchGroup *Cur = GroupsToRelease.front(); - TransferBatch *UnusedTransferBatch = nullptr; + BatchGroupT *Cur = GroupsToRelease.front(); + TransferBatchT *UnusedTransferBatch = nullptr; GroupsToRelease.pop_front(); if (BG->CompactPtrGroupBase == Cur->CompactPtrGroupBase) { @@ -1481,7 +1494,7 @@ template class SizeClassAllocator64 { if (Cur->Batches.front()->getCount() == MaxCachedPerBatch) { BG->Batches.append_back(&Cur->Batches); } else { - TransferBatch *NonFullBatch = Cur->Batches.front(); + TransferBatchT *NonFullBatch = Cur->Batches.front(); Cur->Batches.pop_front(); const u16 NonFullBatchCount = NonFullBatch->getCount(); // The remaining Batches in `Cur` are full. @@ -1546,8 +1559,8 @@ template class SizeClassAllocator64 { } if (SCUDO_DEBUG) { - BatchGroup *Prev = Region->FreeListInfo.BlockList.front(); - for (BatchGroup *Cur = Prev->Next; Cur != nullptr; + BatchGroupT *Prev = Region->FreeListInfo.BlockList.front(); + for (BatchGroupT *Cur = Prev->Next; Cur != nullptr; Prev = Cur, Cur = Cur->Next) { CHECK_LT(Prev->CompactPtrGroupBase, Cur->CompactPtrGroupBase); } diff --git a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp index 1143aaab8371d..7958e9dabf60d 100644 --- a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp @@ -512,6 +512,7 @@ SCUDO_TYPED_TEST(ScudoCombinedTest, CacheDrain) NO_THREAD_SAFETY_ANALYSIS { bool UnlockRequired; auto *TSD = Allocator->getTSDRegistry()->getTSDAndLock(&UnlockRequired); + TSD->assertLocked(/*BypassCheck=*/!UnlockRequired); EXPECT_TRUE(!TSD->getCache().isEmpty()); TSD->getCache().drain(); EXPECT_TRUE(TSD->getCache().isEmpty()); @@ -536,6 +537,7 @@ SCUDO_TYPED_TEST(ScudoCombinedTest, ForceCacheDrain) NO_THREAD_SAFETY_ANALYSIS { bool UnlockRequired; auto *TSD = Allocator->getTSDRegistry()->getTSDAndLock(&UnlockRequired); + TSD->assertLocked(/*BypassCheck=*/!UnlockRequired); EXPECT_TRUE(TSD->getCache().isEmpty()); EXPECT_EQ(TSD->getQuarantineCache().getSize(), 0U); EXPECT_TRUE(Allocator->getQuarantine()->isEmpty()); @@ -842,6 +844,7 @@ TEST(ScudoCombinedTest, BasicTrustyConfig) { bool UnlockRequired; auto *TSD = Allocator->getTSDRegistry()->getTSDAndLock(&UnlockRequired); + TSD->assertLocked(/*BypassCheck=*/!UnlockRequired); TSD->getCache().drain(); Allocator->releaseToOS(scudo::ReleaseToOS::Force); diff --git a/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp b/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp index 074977ff27e65..4db05b7624113 100644 --- a/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp @@ -207,7 +207,7 @@ struct SmallRegionsConfig { // For the 32-bit one, it requires actually exhausting memory, so we skip it. TEST(ScudoPrimaryTest, Primary64OOM) { using Primary = scudo::SizeClassAllocator64; - using TransferBatch = Primary::CacheT::TransferBatch; + using TransferBatch = Primary::TransferBatchT; Primary Allocator; Allocator.init(/*ReleaseToOsInterval=*/-1); typename Primary::CacheT Cache; @@ -233,8 +233,9 @@ TEST(ScudoPrimaryTest, Primary64OOM) { while (!Batches.empty()) { TransferBatch *B = Batches.back(); Batches.pop_back(); - B->copyToArray(Blocks); - Allocator.pushBlocks(&Cache, ClassId, Blocks, B->getCount()); + const scudo::u16 Count = B->getCount(); + B->moveToArray(Blocks); + Allocator.pushBlocks(&Cache, ClassId, Blocks, Count); Cache.deallocate(Primary::SizeClassMap::BatchClassId, B); } Cache.destroy(nullptr); diff --git a/compiler-rt/lib/scudo/standalone/tests/tsd_test.cpp b/compiler-rt/lib/scudo/standalone/tests/tsd_test.cpp index 5953d759a69a9..fad8fcf900771 100644 --- a/compiler-rt/lib/scudo/standalone/tests/tsd_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/tsd_test.cpp @@ -101,6 +101,7 @@ template static void testRegistry() { bool UnlockRequired; auto TSD = Registry->getTSDAndLock(&UnlockRequired); + TSD->assertLocked(/*BypassCheck=*/!UnlockRequired); EXPECT_NE(TSD, nullptr); EXPECT_EQ(TSD->getCache().Canary, 0U); if (UnlockRequired) @@ -108,6 +109,7 @@ template static void testRegistry() { Registry->initThreadMaybe(Allocator.get(), /*MinimalInit=*/false); TSD = Registry->getTSDAndLock(&UnlockRequired); + TSD->assertLocked(/*BypassCheck=*/!UnlockRequired); EXPECT_NE(TSD, nullptr); EXPECT_EQ(TSD->getCache().Canary, 0U); memset(&TSD->getCache(), 0x42, sizeof(TSD->getCache())); @@ -137,6 +139,7 @@ template static void stressCache(AllocatorT *Allocator) { Registry->initThreadMaybe(Allocator, /*MinimalInit=*/false); bool UnlockRequired; auto TSD = Registry->getTSDAndLock(&UnlockRequired); + TSD->assertLocked(/*BypassCheck=*/!UnlockRequired); EXPECT_NE(TSD, nullptr); // For an exclusive TSD, the cache should be empty. We cannot guarantee the // same for a shared TSD. @@ -195,6 +198,7 @@ static void stressSharedRegistry(MockAllocator *Allocator) { bool UnlockRequired; for (scudo::uptr I = 0; I < 4096U; I++) { auto TSD = Registry->getTSDAndLock(&UnlockRequired); + TSD->assertLocked(/*BypassCheck=*/!UnlockRequired); EXPECT_NE(TSD, nullptr); Set.insert(reinterpret_cast(TSD)); if (UnlockRequired) diff --git a/compiler-rt/lib/scudo/standalone/tsd.h b/compiler-rt/lib/scudo/standalone/tsd.h index f4fa545de5e04..b2108a01900bc 100644 --- a/compiler-rt/lib/scudo/standalone/tsd.h +++ b/compiler-rt/lib/scudo/standalone/tsd.h @@ -53,8 +53,14 @@ template struct alignas(SCUDO_CACHE_LINE_SIZE) TSD { inline void unlock() NO_THREAD_SAFETY_ANALYSIS { Mutex.unlock(); } inline uptr getPrecedence() { return atomic_load_relaxed(&Precedence); } - void commitBack(Allocator *Instance) ASSERT_CAPABILITY(Mutex) { - Instance->commitBack(this); + void commitBack(Allocator *Instance) { Instance->commitBack(this); } + + // As the comments attached to `getCache()`, the TSD doesn't always need to be + // locked. In that case, we would only skip the check before we have all TSDs + // locked in all paths. + void assertLocked(bool BypassCheck) ASSERT_CAPABILITY(Mutex) { + if (SCUDO_DEBUG && !BypassCheck) + Mutex.assertHeld(); } // Ideally, we may want to assert that all the operations on @@ -66,11 +72,8 @@ template struct alignas(SCUDO_CACHE_LINE_SIZE) TSD { // TODO(chiahungduan): Ideally, we want to do `Mutex.assertHeld` but acquiring // TSD doesn't always require holding the lock. Add this assertion while the // lock is always acquired. - typename Allocator::CacheT &getCache() ASSERT_CAPABILITY(Mutex) { - return Cache; - } - typename Allocator::QuarantineCacheT &getQuarantineCache() - ASSERT_CAPABILITY(Mutex) { + typename Allocator::CacheT &getCache() REQUIRES(Mutex) { return Cache; } + typename Allocator::QuarantineCacheT &getQuarantineCache() REQUIRES(Mutex) { return QuarantineCache; } diff --git a/compiler-rt/lib/scudo/standalone/tsd_shared.h b/compiler-rt/lib/scudo/standalone/tsd_shared.h index dcb0948ad78fa..1bca578ee14be 100644 --- a/compiler-rt/lib/scudo/standalone/tsd_shared.h +++ b/compiler-rt/lib/scudo/standalone/tsd_shared.h @@ -120,6 +120,11 @@ struct TSDRegistrySharedT { TSDsArraySize); for (uptr I = 0; I < NumberOfTSDs; ++I) { TSDs[I].lock(); + // Theoretically, we want to mark TSD::lock()/TSD::unlock() with proper + // thread annotations. However, given the TSD is only locked on shared + // path, do the assertion in a separate path to avoid confusing the + // analyzer. + TSDs[I].assertLocked(/*BypassCheck=*/true); Str->append(" Shared TSD[%zu]:\n", I); TSDs[I].getCache().getStats(Str); TSDs[I].unlock(); diff --git a/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp b/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp index 3cb8cb80feb06..e39a0ab4e6589 100644 --- a/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp +++ b/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp @@ -1,6 +1,8 @@ // RUN: %clangxx %gmlt -fsanitize=alignment %s -O3 -o %t // RUN: %run %t l0 && %run %t s0 && %run %t r0 && %run %t m0 && %run %t f0 && %run %t n0 && %run %t u0 // RUN: %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --strict-whitespace +// RUN: %run %t L1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMCPY-LOAD +// RUN: %run %t S1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMCPY-STORE // RUN: %run %t r1 2>&1 | FileCheck %s --check-prefix=CHECK-REFERENCE // RUN: %run %t m1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER // RUN: %run %t f1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN @@ -15,6 +17,7 @@ // XFAIL: target={{.*openbsd.*}} #include +#include struct S { S() {} @@ -47,6 +50,16 @@ int main(int, char **argv) { return *p && 0; // CHECK-STACK-LOAD: #0 {{.*}}main{{.*}}misaligned.cpp + case 'L': { + int x; + // CHECK-MEMCPY-LOAD: misaligned.cpp:[[#@LINE+4]]{{(:16)?}}: runtime error: load of misaligned address [[PTR:0x[0-9a-f]*]] for type 'int *', which requires 4 byte alignment + // CHECK-MEMCPY-LOAD-NEXT: [[PTR]]: note: pointer points here + // CHECK-MEMCPY-LOAD-NEXT: {{^ 00 00 00 01 02 03 04 05}} + // CHECK-MEMCPY-LOAD-NEXT: {{^ \^}} + memcpy(&x, p, sizeof(x)); + return x && 0; + } + case 's': // CHECK-STORE: misaligned.cpp:[[@LINE+4]]{{(:5)?}}: runtime error: store to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment // CHECK-STORE-NEXT: [[PTR]]: note: pointer points here @@ -55,6 +68,16 @@ int main(int, char **argv) { *p = 1; break; + case 'S': { + int x = 1; + // CHECK-MEMCPY-STORE: misaligned.cpp:[[#@LINE+4]]{{(:12)?}}: runtime error: store to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int *', which requires 4 byte alignment + // CHECK-MEMCPY-STORE-NEXT: [[PTR]]: note: pointer points here + // CHECK-MEMCPY-STORE-NEXT: {{^ 00 00 00 01 02 03 04 05}} + // CHECK-MEMCPY-STORE-NEXT: {{^ \^}} + memcpy(p, &x, sizeof(x)); + break; + } + case 'r': // CHECK-REFERENCE: misaligned.cpp:[[@LINE+4]]{{(:(5|15))?}}: runtime error: reference binding to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment // CHECK-REFERENCE-NEXT: [[PTR]]: note: pointer points here diff --git a/flang/docs/ComplexOperations.md b/flang/docs/ComplexOperations.md index d035658b90acd..03566035c28a3 100644 --- a/flang/docs/ComplexOperations.md +++ b/flang/docs/ComplexOperations.md @@ -1,8 +1,9 @@ # Complex Operations -```{eval-rst} -.. toctree:: - :local: +```{contents} +--- +local: +--- ``` Fortran includes support for complex number types and a set of operators and @@ -34,7 +35,7 @@ end function pow_self ``` **FIR** -```c +``` func.func @_QPpow_self(%arg0: !fir.ref>) -> !fir.complex<4> { %0 = fir.alloca !fir.complex<4> %1 = fir.load %arg0 : !fir.ref> @@ -66,7 +67,7 @@ libm functions. Similarly to the numerical lowering through the math dialect, certain MLIR optimisations could violate the precise floating point model, so when that is -requested lowering manually emits calls to libm, rather than going through the +requested lowering manually emits calls to libm, rather than going through the MLIR complex dialect. The ComplexToStandard dialect does still call into libm for some floating diff --git a/flang/docs/FIRArrayOperations.md b/flang/docs/FIRArrayOperations.md index bea49eae37a38..6f9ffb2c5a070 100644 --- a/flang/docs/FIRArrayOperations.md +++ b/flang/docs/FIRArrayOperations.md @@ -1,9 +1,9 @@ - # Design: FIR Array operations @@ -19,7 +19,7 @@ local: The array operations in FIR model the copy-in/copy-out semantics over Fortran statements. -Fortran language semantics sometimes require the compiler to make a temporary +Fortran language semantics sometimes require the compiler to make a temporary copy of an array or array slice. Situations where this can occur include: * Passing a non-contiguous array to a procedure that does not declare it as @@ -40,7 +40,7 @@ There are currently the following operations: `array_load`(s) and `array_merge_store` are a pairing that brackets the lifetime of the array copies. -`array_fetch` and `array_update` are defined to work as getter/setter pairs on +`array_fetch` and `array_update` are defined to work as getter/setter pairs on values of elements from loaded array copies. These have "GEP-like" syntax and semantics. @@ -83,7 +83,7 @@ alter its composite value. This operation lets one load an array as a value while applying a runtime shape, shift, or slice to the memory reference, and its semantics guarantee immutability. -```mlir +``` %s = fir.shape_shift %lb1, %ex1, %lb2, %ex2 : (index, index, index, index) -> !fir.shapeshift<2> // load the entire array 'a' %v = fir.array_load %a(%s) : (!fir.ref>, !fir.shapeshift<2>) -> !fir.array @@ -92,7 +92,7 @@ reference, and its semantics guarantee immutability. # array_merge_store -The `array_merge_store` operation stores a merged array value to memory. +The `array_merge_store` operation stores a merged array value to memory. ```fortran @@ -104,7 +104,7 @@ The `array_merge_store` operation stores a merged array value to memory. One can use `fir.array_merge_store` to merge/copy the value of `a` in an array expression as shown above. -```mlir +``` %v = fir.array_load %a(%shape) : ... %r = fir.array_update %v, %f, %i, %j : (!fir.array, f32, index, index) -> !fir.array fir.array_merge_store %v, %r to %a : !fir.ref> @@ -137,7 +137,7 @@ One can use `fir.array_fetch` to fetch the (implied) value of `a(i,j)` in an array expression as shown above. It can also be used to extract the element `a(r,s+1)` in the second expression. -```mlir +``` %s = fir.shape %n, %m : (index, index) -> !fir.shape<2> // load the entire array 'a' %v = fir.array_load %a(%s) : (!fir.ref>, !fir.shape<2>) -> !fir.array @@ -165,7 +165,7 @@ the update. One can use `fir.array_update` to update the (implied) value of `a(i,j)` in an array expression as shown above. -```mlir +``` %s = fir.shape %n, %m : (index, index) -> !fir.shape<2> // load the entire array 'a' %v = fir.array_load %a(%s) : (!fir.ref>, !fir.shape<2>) -> !fir.array @@ -206,7 +206,7 @@ the element `a(i,j)` in an array expression `a` as shown above. It can also be used to recover the reference element `a(r,s+1)` in the second expression. -```mlir +``` %s = fir.shape %n, %m : (index, index) -> !fir.shape<2> // load the entire array 'a' %v = fir.array_load %a(%s) : (!fir.ref>, !fir.shape<2>) -> !fir.array @@ -220,9 +220,9 @@ source. Other array operation such as `array_amend` can be in between. `array_access` if mainly used with `character`'s arrays and arrays of derived types where because they might have a non-compile time sizes that would be -useless too load entirely or too big to load. +useless too load entirely or too big to load. -Here is a simple example with a `character` array assignment. +Here is a simple example with a `character` array assignment. Fortran ``` @@ -271,12 +271,12 @@ it has dynamic length, and even if constant, could be too long to do so. ## array_amend -The `array_amend` operation marks an array value as having been changed via a +The `array_amend` operation marks an array value as having been changed via a reference obtain by an `array_access`. It acts as a logical transaction log that is used to merge the final result back with an `array_merge_store` operation. -```mlir +``` // fetch the value of one of the array value's elements %1 = fir.array_access %v, %i, %j : (!fir.array, index, index) -> !fir.ref // modify the element by storing data using %1 as a reference @@ -317,7 +317,7 @@ func @_QPs(%arg0: !fir.box>>, %arg1: !fir. // This is the "seed" for the "copy-out" array on the LHS. It'll flow from iteration to iteration and gets // updated at each iteration. %array_a_dest_init = fir.array_load %arg0 : (!fir.box>>) -> !fir.array> - + %array_a_final = fir.do_loop %i = %l_index to %u_index step %c1 unordered iter_args(%array_a_dest = %array_a_dest_init) -> (!fir.array>) { // Compute indexing for the RHS and array the element. %u_minus_i = arith.subi %u_index, %i : index // u-i diff --git a/flang/docs/GettingStarted.md b/flang/docs/GettingStarted.md index f5319a7c38541..3b3f14d4fed1a 100644 --- a/flang/docs/GettingStarted.md +++ b/flang/docs/GettingStarted.md @@ -141,8 +141,14 @@ code is in good shape. ### Building flang standalone To do the standalone build, start by building flang in tree as described above. -This build is base build for subsequent standalone builds. Start each -standalone build the same way by cloning the source for llvm-project: +This build can be used as the base build for several subsequent standalone +builds. Set the environment variable **ROOT_DIR** to the directory that +contains the subdirectory `build` that was created previously, for example: +```bash +export ROOTDIR=/home/user/root +``` +Start each standalone build the same way by cloning the source for +llvm-project: ```bash mkdir standalone cd standalone @@ -175,7 +181,7 @@ cmake \ ninja ``` -To run the flang tests on this build, execute the command in the "flang/build" +To run the flang tests on this build, execute the command in the `flang/build` directory: ```bash ninja check-flang diff --git a/flang/docs/HighLevelFIR.md b/flang/docs/HighLevelFIR.md index 9b3f75671dfea..fa3d943e59474 100644 --- a/flang/docs/HighLevelFIR.md +++ b/flang/docs/HighLevelFIR.md @@ -119,7 +119,7 @@ its first operand to return an HLFIR variable compatible type. The fir.declare op is the only operation described by this change that will be added to FIR. The rational for this is that it is intended to survive until LLVM dialect codegeneration so that debug info generation can use them and -alias information can take advantage of them even on FIR. +alias information can take advantage of them even on FIR. Note that Fortran variables are not necessarily named objects, they can also be the result of function references returning POINTERs. hlfir.declare will also @@ -1021,7 +1021,7 @@ end subroutine Lowering output: -```HLFIR +``` func.func @_QPfoo(%arg0: !fir.box>, %arg1: !fir.box>) { %a = hlfir.declare %arg0 {fir.def = "_QPfooEa"} : !fir.box>, !fir.box> %b = hlfir.declare %arg1 {fir.def = "_QPfooEb"} : !fir.box>, !fir.box> @@ -1107,7 +1107,7 @@ end subroutine Lowering output: -```HLFIR +``` func.func @_QPfoo(%arg0: !fir.box>, %arg1: !fir.box>, %arg2: !fir.box>>, %arg3: !fir.ref>) { %a = hlfir.declare %arg0 {fir.def = "_QPfooEa"} {fir.target} : !fir.box, !fir.box %b = hlfir.declare %arg1 {fir.def = "_QPfooEb"} : !fir.box>, !fir.box> @@ -1145,7 +1145,7 @@ Step 1: hlfir.elemental inlining: inline the first hlfir.elemental into the second one at the hlfir.apply. -```HLFIR +``` func.func @_QPfoo(%arg0: !fir.box>, %arg1: !fir.box>, %arg2: !fir.box>>, %arg3: !fir.ref>) { %a = hlfir.declare %arg0 {fir.def = "_QPfooEa"} {fir.target} : !fir.box, !fir.box %b = hlfir.declare %arg1 {fir.def = "_QPfooEb"} : !fir.box>, !fir.box> @@ -1190,7 +1190,7 @@ Note that the alias analysis could have already occurred without inlining the %add hlfir.elemental. -```HLFIR +``` func.func @_QPfoo(%arg0: !fir.box>, %arg1: !fir.box>, %arg2: !fir.box>>, %arg3: !fir.ref>) { %a = hlfir.declare %arg0 {fir.def = "_QPfooEa"} {fir.target} : !fir.box, !fir.box %b = hlfir.declare %arg1 {fir.def = "_QPfooEb"} : !fir.box>, !fir.box> @@ -1229,7 +1229,7 @@ func.func @_QPfoo(%arg0: !fir.box>, %arg1: !fir.box>, %arg1: !fir.box>, %arg2: !fir.box>>, %arg3: !fir.ref>) { %a = hlfir.declare %arg0 {fir.def = "_QPfooEa"} {fir.target} : !fir.box, !fir.box %b = hlfir.declare %arg1 {fir.def = "_QPfooEb"} : !fir.box>, !fir.box> @@ -1275,7 +1275,7 @@ Step 5 (may also occur earlier or several times): shape propagation. conformance checks can be added for %a, %b and %p. - %temp is small, and its fir.allocmem can be promoted to a stack allocation -```HLFIR +``` func.func @_QPfoo(%arg0: !fir.box>, %arg1: !fir.box>, %arg2: !fir.box>>, %arg3: !fir.ref>) { // ..... %cshape = fir.shape %c100 @@ -1366,7 +1366,7 @@ the MLIR infrastructure experience that was gained. ## Using symbols for HLFIR variables -### Using attributes as pseudo variable symbols +### Using attributes as pseudo variable symbols Instead of restricting the memory types an HLFIR variable can have, it was force the defining operation of HLFIR variable SSA values to always be diff --git a/flang/docs/ParameterizedDerivedTypes.md b/flang/docs/ParameterizedDerivedTypes.md index 892653c9689ca..39ba20d232468 100644 --- a/flang/docs/ParameterizedDerivedTypes.md +++ b/flang/docs/ParameterizedDerivedTypes.md @@ -96,7 +96,7 @@ In case of `len_type1`, the size, offset, etc. of `fld1` and `fld2` depend on the runtime values of `i` and `j` when the components are inlined into the derived type. At runtime, this information needs to be computed to be retrieved. While lowering the PDT, compiler generated functions can be created in order to -compute this information. +compute this information. Note: The type description tables generated by semantics and used throughout the runtime have component offsets as constants. Inlining component would require @@ -127,7 +127,7 @@ type len_type2(i, j) ! allocatable components managed by the compiler. The ! `compiler_managed_allocatable` is not a proper keyword but just added here ! to have a better understanding. - character(i+j), compiler_managed_allocatable :: fld1 + character(i+j), compiler_managed_allocatable :: fld1 character(j-i+2), compiler_managed_allocatable :: fld2 end type ``` @@ -266,7 +266,7 @@ the offset of `fld1` in `len_type1` could be 0; its size would be computed as function. **FIR** -```c +``` // Example of compiler generated functions to compute offsets, size, etc. // This is just an example and actual implementation might have more functions. @@ -337,7 +337,7 @@ pdt_inlined_array(1)%field%fld2 ``` Example of offset computation in the PDTs. -```c +``` %0 = call @_len_type3.field.typeparam.1(%i, %j) : (index, index) -> index %1 = call @_len_type3.field.typeparam.2(%i, %j) : (index, index) -> index %2 = call @_len_type3.offset.fld(%i, %j) : (index, index) -> index @@ -367,7 +367,7 @@ operation can take the length type parameters needed for size/offset computation. **FIR** -```c +``` %5 = fir.field_index i, !fir.type<_QMmod1Tt{l:i32,i:!fir.array}>(%n : i32) ``` @@ -431,7 +431,7 @@ allocate(t1(2)::p) ``` **FIR** -```c +``` // For allocatable %5 = fir.call @_FortranAAllocatableInitDerived(%desc, %type) : (!fir.box, ) -> () // The AllocatableSetDerivedLength functions is called for each length type parameters. @@ -455,8 +455,8 @@ The `DEALLOCATE` statement is lowered to a runtime call to deallocate(pdt1) ``` -**FIR** -```c +**FIR** +``` // For allocatable %8 = fir.call @_FortranAAllocatableDeallocate(%desc1) : (!fir.box) -> (i32) @@ -475,7 +475,7 @@ NULLIFY(p) ``` **FIR** -```c +``` %0 = fir.call @_FortranAPointerNullifyDerived(%desc, %type) : (!fir.box, !fir.tdesc) -> () ``` @@ -507,11 +507,11 @@ end subroutine ``` **FIR** -```c +``` func.func @_QMpdtPprint_pdt() { %l = arith.constant = 10 %0 = fir.alloca !fir.type<_QMpdtTt{l:i32,i:!fir.array}> (%l : i32) {bindc_name = "x", uniq_name = "_QMpdt_initFlocalEx"} - %1 = fir.embox %0 : (!fir.ref}>>) (typeparams %l : i32) -> !fir.box}>> + %1 = fir.embox %0 : (!fir.ref}>>) (typeparams %l : i32) -> !fir.box}>> %2 = fir.address_of(@_QQcl.2E2F6669725F7064745F6578616D706C652E66393000) : !fir.ref> %c8_i32 = arith.constant 8 : i32 %3 = fir.convert %1 : (!fir.box}>>) -> !fir.box @@ -564,7 +564,7 @@ type(t(10)) :: a, b type(t(20)) :: c type(t(:)), allocatable :: d a = b ! Legal assignment -c = b ! Illegal assignment because `c` does not have the same length type +c = b ! Illegal assignment because `c` does not have the same length type ! parameter value than `b`. d = c ! Legal because `d` is allocatable ``` @@ -607,12 +607,12 @@ module m end type contains - + subroutine finalize_t1s(x) type(t(kind(0.0))) x if (associated(x%vector)) deallocate(x%vector) END subroutine - + subroutine finalize_t1v(x) type(t(kind(0.0))) x(:) do i = lbound(x,1), ubound(x,1) @@ -832,7 +832,7 @@ allocating a PDT, the length type parameters are passed to the operation so its size can be computed accordingly. **FIR** -```c +``` %i = arith.constant 10 : i32 %0 = fir.alloca !fir.type<_QMmod1Tpdt{i:i32,data:!fir.array}> (%i : i32) // %i is the ssa value of the length type parameter @@ -845,7 +845,7 @@ value of the given type. When creating a PDT, the length type parameters are passed so the size can be computed accordingly. **FIR** -```c +``` %i = arith.constant 10 : i32 %0 = fir.alloca !fir.type<_QMmod1Tpdt{i:i32,data:!fir.array}> (%i : i32) // ... @@ -866,7 +866,7 @@ end subroutine ``` **FIR** -```c +``` func.func @_QMpdt_initPlocal() { %c2_i32 = arith.constant 2 : i32 %0 = fir.alloca !fir.type<_QMpdt_initTt{l:i32,i:!fir.array}> (%c2 : i32) @@ -892,7 +892,7 @@ a field identifier in a derived-type. The operation takes length type parameter values with a PDT so it can compute a correct offset. **FIR** -```c +``` %l = arith.constant 10 : i32 %1 = fir.field_index i, !fir.type<_QMpdt_initTt{l:i32,i:i32}> (%l : i32) %2 = fir.coordinate_of %ref, %1 : (!fir.type<_QMpdt_initTt{l:i32,i:i32}>, !fir.field) -> !fir.ref @@ -905,7 +905,7 @@ return %3 This operation is used to get the length type parameter offset in from a PDT. **FIR** -```c +``` func.func @_QPpdt_len_value(%arg0: !fir.box}>>) -> i32 { %0 = fir.len_param_index l, !fir.box}>> %1 = fir.coordinate_of %arg0, %0 : (!fir.box}>>, !fir.len) -> !fir.ref @@ -921,7 +921,7 @@ a memory location given the shape and LEN parameters of the result. Length type parameters is passed if the PDT is not boxed. **FIR** -```c +``` func.func @return_pdt(%buffer: !fir.ref>) { %l1 = arith.constant 3 : i32 %l2 = arith.constant 5 : i32 @@ -938,7 +938,7 @@ parameters operands. This is designed to use PDT without descriptor directly in FIR. **FIR** -```c +``` // Operation used with a boxed PDT does not need the length type parameters as // they are directly retrieved from the box. %0 = fir.array_coor %boxed_pdt, %i, %j (fir.box}>>>>, index, index) -> !fir.ref}>>> diff --git a/flang/docs/PolymorphicEntities.md b/flang/docs/PolymorphicEntities.md index 3935861b6207c..8eabc9eb3c6ab 100644 --- a/flang/docs/PolymorphicEntities.md +++ b/flang/docs/PolymorphicEntities.md @@ -75,7 +75,7 @@ end subroutine ``` **FIR** -```c +``` func.func @foo(%p : !fir.class>) ``` @@ -93,7 +93,7 @@ end subroutine ``` **FIR** -```c +``` func.func @bar(%x : !fir.class) ``` @@ -437,7 +437,7 @@ get_all_area = get_all_area + shapes(i)%item%get_area() ``` **FIR** -```c +``` %1 = fir.convert %0 : !fir.ref,base:f32,height:f32>>> %2 = fir.dispatch "get_area"(%1 : !fir.class,base:f32,height:f32>>) -> f32 ``` @@ -451,7 +451,7 @@ its ancestor types appear first. **LLVMIR** Representation of the derived type information with the bindings. -```c +``` %_QM__fortran_type_infoTderivedtype = type { { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, { ptr, i64, i32, i8, i8, i8, i8 }, i64, { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, i32, i8, i8, i8, i8, [4 x i8] } %_QM__fortran_type_infoTbinding = type { %_QM__fortran_builtinsT__builtin_c_funptr, { ptr, i64, i32, i8, i8, i8, i8 } } %_QM__fortran_builtinsT__builtin_c_funptr = type { i64 } @@ -463,7 +463,7 @@ correct function from the vtable and to perform the actual call. Here is what it can look like in pseudo LLVM IR code. **FIR** -```c +``` %2 = fir.box_tdesc %arg0 : (!fir.class,base:f32,height:f32>>) -> !fir.tdesc %3 = fir.box_tdesc %arg0 : (!fir.class>) -> !fir.tdesc %4 = fir.convert %3 : (!fir.tdesc) -> !fir.ref> @@ -483,7 +483,7 @@ what it can look like in pseudo LLVM IR code. ``` **LLVMIR** -```c +``` // Retrieve the derived type runtime information and the vtable. %14 = getelementptr %_QM__fortran_type_infoTderivedtype, ptr %13, i32 0, i32 0 %15 = load { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %14 @@ -516,7 +516,7 @@ END TYPE 2) Dummy argument is polymorphic and actual argument is fixed type. In these cases, the actual argument need to be boxed to be passed to the subroutine/function since those are expecting a descriptor. - ```c + ``` func.func @_QMmod1Ps(%arg0: !fir.class>) func.func @_QQmain() { %0 = fir.alloca !fir.type<_QMmod1Tshape{x:i32,y:i32}> {uniq_name = "_QFEsh"} @@ -584,7 +584,7 @@ write(10), x ``` **FIR** -```c +``` %5 = fir.call @_FortranAioBeginUnformattedOutput(%c10_i32, %4, %c56_i32) : (i32, !fir.ref, i32) -> !fir.ref %6 = fir.embox %2 : (!fir.ref>) -> !fir.class> %7 = fir.convert %6 : (!fir.class>) -> !fir.box @@ -608,7 +608,7 @@ finalization with a call the the `@_FortranADestroy` function (`flang/include/flang/Runtime/derived-api.h`). **FIR** -```c +``` %5 = fir.call @_FortranADestroy(%desc) : (!fir.box) -> none ``` @@ -671,7 +671,7 @@ end subroutine **FIR** The call to `get_area` in the `type is (triangle)` guard can be replaced. -```c +``` %3 = fir.dispatch "get_area"(%desc) // Replaced by %3 = fir.call @get_area_triangle(%desc) @@ -716,7 +716,7 @@ allocate(rectangle::shapes(2)%item) ``` **FIR** -```c +``` %0 = fir.address_of(@_QMgeometryE.dt.triangle) : !fir.ref> %1 = fir.convert %item1 : (!fir.ref,base:f32,height:f32>>>) -> !fir.ref> %2 = fir.call @_FortranAAllocatableInitDerived(%1, %0) @@ -742,7 +742,7 @@ deallocate(shapes(2)%item) ``` **FIR** -```c +``` %8 = fir.call @_FortranAAllocatableDeallocate(%desc1) %9 = fir.call @_FortranAAllocatableDeallocate(%desc2) ``` @@ -849,7 +849,7 @@ dynamic type of polymorphic entities. dynamic type of `a` must be copied when it is associated on `b`. **FIR** - ```c + ``` // fir.load must copy the dynamic type from the pointer `a` %0 = fir.address_of(@_QMmod1Ea) : !fir.ref>>> %1 = fir.load %0 : !fir.ref>>> diff --git a/flang/docs/conf.py b/flang/docs/conf.py index a90343ef8e05e..9b45237373747 100644 --- a/flang/docs/conf.py +++ b/flang/docs/conf.py @@ -31,6 +31,7 @@ # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] +myst_heading_anchors = 6 import sphinx diff --git a/flang/include/flang/ISO_Fortran_binding.h b/flang/include/flang/ISO_Fortran_binding.h index 59e31462ab5aa..2893fd46c267d 100644 --- a/flang/include/flang/ISO_Fortran_binding.h +++ b/flang/include/flang/ISO_Fortran_binding.h @@ -127,8 +127,8 @@ namespace cfi_internal { template struct FlexibleArray : T { RT_API_ATTRS T &operator[](int index) { return *(this + index); } const RT_API_ATTRS T &operator[](int index) const { return *(this + index); } - operator T *() { return this; } - operator const T *() const { return this; } + RT_API_ATTRS operator T *() { return this; } + RT_API_ATTRS operator const T *() const { return this; } }; } // namespace cfi_internal #endif @@ -182,19 +182,20 @@ template <> struct CdescStorage<0> : public CFI_cdesc_t {}; #ifdef __cplusplus extern "C" { #endif -void *CFI_address(const CFI_cdesc_t *, const CFI_index_t subscripts[]); -int CFI_allocate(CFI_cdesc_t *, const CFI_index_t lower_bounds[], +RT_API_ATTRS void *CFI_address( + const CFI_cdesc_t *, const CFI_index_t subscripts[]); +RT_API_ATTRS int CFI_allocate(CFI_cdesc_t *, const CFI_index_t lower_bounds[], const CFI_index_t upper_bounds[], size_t elem_len); RT_API_ATTRS int CFI_deallocate(CFI_cdesc_t *); int CFI_establish(CFI_cdesc_t *, void *base_addr, CFI_attribute_t, CFI_type_t, size_t elem_len, CFI_rank_t, const CFI_index_t extents[]); -int CFI_is_contiguous(const CFI_cdesc_t *); +RT_API_ATTRS int CFI_is_contiguous(const CFI_cdesc_t *); RT_API_ATTRS int CFI_section(CFI_cdesc_t *, const CFI_cdesc_t *source, const CFI_index_t lower_bounds[], const CFI_index_t upper_bounds[], const CFI_index_t strides[]); -int CFI_select_part(CFI_cdesc_t *, const CFI_cdesc_t *source, +RT_API_ATTRS int CFI_select_part(CFI_cdesc_t *, const CFI_cdesc_t *source, size_t displacement, size_t elem_len); -int CFI_setpointer( +RT_API_ATTRS int CFI_setpointer( CFI_cdesc_t *, const CFI_cdesc_t *source, const CFI_index_t lower_bounds[]); #ifdef __cplusplus } // extern "C" diff --git a/flang/include/flang/Lower/AbstractConverter.h b/flang/include/flang/Lower/AbstractConverter.h index 477c8164a18ea..c792e75f11464 100644 --- a/flang/include/flang/Lower/AbstractConverter.h +++ b/flang/include/flang/Lower/AbstractConverter.h @@ -212,12 +212,10 @@ class AbstractConverter { /// Register a runtime derived type information object symbol to ensure its /// object will be generated as a global. - virtual void registerRuntimeTypeInfo(mlir::Location loc, - SymbolRef typeInfoSym) = 0; - - virtual void registerDispatchTableInfo( - mlir::Location loc, - const Fortran::semantics::DerivedTypeSpec *typeSpec) = 0; + virtual void + registerTypeInfo(mlir::Location loc, SymbolRef typeInfoSym, + const Fortran::semantics::DerivedTypeSpec &typeSpec, + fir::RecordType type) = 0; //===--------------------------------------------------------------------===// // Locations diff --git a/flang/include/flang/Lower/CallInterface.h b/flang/include/flang/Lower/CallInterface.h index ec025e792349a..579bdcfd89887 100644 --- a/flang/include/flang/Lower/CallInterface.h +++ b/flang/include/flang/Lower/CallInterface.h @@ -418,15 +418,14 @@ mlir::FunctionType translateSignature(const Fortran::evaluate::ProcedureDesignator &, Fortran::lower::AbstractConverter &); -/// Declare or find the mlir::func::FuncOp named \p name. If the -/// mlir::func::FuncOp does not exist yet, declare it with the signature -/// translated from the ProcedureDesignator argument. +/// Declare or find the mlir::func::FuncOp for the procedure designator +/// \p proc. If the mlir::func::FuncOp does not exist yet, declare it with +/// the signature translated from the ProcedureDesignator argument. /// Due to Fortran implicit function typing rules, the returned FuncOp is not /// guaranteed to have the signature from ProcedureDesignator if the FuncOp was /// already declared. mlir::func::FuncOp -getOrDeclareFunction(llvm::StringRef name, - const Fortran::evaluate::ProcedureDesignator &, +getOrDeclareFunction(const Fortran::evaluate::ProcedureDesignator &, Fortran::lower::AbstractConverter &); /// Return the type of an argument that is a dummy procedure. This may be an diff --git a/flang/include/flang/Lower/HlfirIntrinsics.h b/flang/include/flang/Lower/HlfirIntrinsics.h index df1f1ac9a7cf5..088f8bccef4aa 100644 --- a/flang/include/flang/Lower/HlfirIntrinsics.h +++ b/flang/include/flang/Lower/HlfirIntrinsics.h @@ -19,6 +19,8 @@ #define FORTRAN_LOWER_HLFIRINTRINSICS_H #include "flang/Optimizer/Builder/HLFIRTools.h" +#include "flang/Optimizer/Builder/Todo.h" +#include "flang/Optimizer/HLFIR/HLFIROps.h" #include "llvm/ADT/SmallVector.h" #include #include @@ -46,18 +48,71 @@ struct PreparedActualArgument { PreparedActualArgument(hlfir::Entity actual, std::optional isPresent) : actual{actual}, isPresent{isPresent} {} + PreparedActualArgument(hlfir::ElementalAddrOp vectorSubscriptedActual) + : actual{vectorSubscriptedActual}, isPresent{std::nullopt} {} void setElementalIndices(mlir::ValueRange &indices) { oneBasedElementalIndices = &indices; } - hlfir::Entity getActual(mlir::Location loc, - fir::FirOpBuilder &builder) const { - if (oneBasedElementalIndices) - return hlfir::getElementAt(loc, builder, actual, - *oneBasedElementalIndices); - return actual; + + /// Get the prepared actual. If this is an array argument in an elemental + /// call, the current element value will be returned. + hlfir::Entity getActual(mlir::Location loc, fir::FirOpBuilder &builder) const; + + void derefPointersAndAllocatables(mlir::Location loc, + fir::FirOpBuilder &builder) { + if (auto *actualEntity = std::get_if(&actual)) + actual = hlfir::derefPointersAndAllocatables(loc, builder, *actualEntity); + } + + void loadTrivialScalar(mlir::Location loc, fir::FirOpBuilder &builder) { + if (auto *actualEntity = std::get_if(&actual)) + actual = hlfir::loadTrivialScalar(loc, builder, *actualEntity); + } + + /// Ensure an array expression argument is fully evaluated in memory before + /// the call. Useful for impure elemental calls. + hlfir::AssociateOp associateIfArrayExpr(mlir::Location loc, + fir::FirOpBuilder &builder) { + if (auto *actualEntity = std::get_if(&actual)) { + if (!actualEntity->isVariable() && actualEntity->isArray()) { + mlir::Type storageType = actualEntity->getType(); + hlfir::AssociateOp associate = hlfir::genAssociateExpr( + loc, builder, *actualEntity, storageType, "adapt.impure_arg_eval"); + actual = hlfir::Entity{associate}; + return associate; + } + } + return {}; + } + + bool isArray() const { + return std::holds_alternative(actual) || + std::get(actual).isArray(); } - hlfir::Entity getOriginalActual() const { return actual; } - void setOriginalActual(hlfir::Entity newActual) { actual = newActual; } + + mlir::Value genShape(mlir::Location loc, fir::FirOpBuilder &builder) { + if (auto *actualEntity = std::get_if(&actual)) + return hlfir::genShape(loc, builder, *actualEntity); + return std::get(actual).getShape(); + } + + mlir::Value genCharLength(mlir::Location loc, fir::FirOpBuilder &builder) { + if (auto *actualEntity = std::get_if(&actual)) + return hlfir::genCharLength(loc, builder, *actualEntity); + auto typeParams = std::get(actual).getTypeparams(); + assert(typeParams.size() == 1 && + "failed to retrieve vector subscripted character length"); + return typeParams[0]; + } + + /// When the argument is polymorphic, get mold value with the same dynamic + /// type. + mlir::Value getPolymorphicMold(mlir::Location loc) const { + if (auto *actualEntity = std::get_if(&actual)) + return *actualEntity; + TODO(loc, "polymorphic vector subscripts"); + } + bool handleDynamicOptional() const { return isPresent.has_value(); } mlir::Value getIsPresent() const { assert(handleDynamicOptional() && "not a dynamic optional"); @@ -67,7 +122,7 @@ struct PreparedActualArgument { void resetOptionalAspect() { isPresent = std::nullopt; } private: - hlfir::Entity actual; + std::variant actual; mlir::ValueRange *oneBasedElementalIndices{nullptr}; // When the actual may be dynamically optional, "isPresent" // holds a boolean value indicating the presence of the diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h index bba8bc23c26aa..0b36186d68a46 100644 --- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h +++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h @@ -254,11 +254,6 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener { bodyBuilder, linkage); } - /// Create a fir::DispatchTable operation. - fir::DispatchTableOp createDispatchTableOp(mlir::Location loc, - llvm::StringRef name, - llvm::StringRef parentName); - /// Convert a StringRef string into a fir::StringLitOp. fir::StringLitOp createStringLitOp(mlir::Location loc, llvm::StringRef string); diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td index a57add9f73197..cb39619f526e8 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -73,7 +73,7 @@ def fir_AllocaOp : fir_Op<"alloca", [AttrSizedOperandSegments, an optional name. The allocation may have a dynamic repetition count for allocating a sequence of locations for the specified type. - ```mlir + ``` %c = ... : i64 %x = fir.alloca i32 %y = fir.alloca !fir.array<8 x i64> @@ -192,7 +192,7 @@ def fir_AllocMemOp : fir_Op<"allocmem", The memory object is in an undefined state. `allocmem` operations must be paired with `freemem` operations to avoid memory leaks. - ```mlir + ``` %0 = fir.allocmem !fir.array<10 x f32> fir.freemem %0 : !fir.heap> ``` @@ -246,7 +246,7 @@ def fir_FreeMemOp : fir_Op<"freemem", [MemoryEffects<[MemFree]>]> { in the undefined state as undefined behavior. This includes aliasing references, such as the result of an `fir.embox`. - ```mlir + ``` %21 = fir.allocmem !fir.type ... fir.freemem %21 : !fir.heap> @@ -265,7 +265,7 @@ def fir_LoadOp : fir_OneResultOp<"load", []> { Produces an immutable ssa-value of the referent type. A memory reference has type `!fir.ref`, `!fir.heap`, or `!fir.ptr`. - ```mlir + ``` %a = fir.alloca i32 %l = fir.load %a : !fir.ref ``` @@ -293,7 +293,7 @@ def fir_StoreOp : fir_Op<"store", []> { value must be of the same type as the referent type of the memory reference. - ```mlir + ``` %v = ... : f64 %p = ... : !fir.ptr fir.store %v to %p : !fir.ptr @@ -337,7 +337,7 @@ def fir_SaveResultOp : fir_Op<"save_result", [AttrSizedOperandSegments]> { The fir.save_result associated to a function call must immediately follow the call and be in the same block. - ```mlir + ``` %buffer = fir.alloca fir.array, %c100 %shape = fir.shape %c100 %array_result = fir.call @foo() : () -> fir.array @@ -378,7 +378,7 @@ def fir_CharConvertOp : fir_Op<"char_convert", []> { The number of code points copied is specified explicitly as the second argument. The length of the !fir.char type is ignored. - ```mlir + ``` fir.char_convert %1 for %2 to %3 : !fir.ref>, i32, !fir.ref> ``` @@ -410,7 +410,7 @@ def fir_UndefOp : fir_OneResultOp<"undefined", [NoMemoryEffect]> { This operation is typically created internally by the mem2reg conversion pass. An undefined value can be of any type except `!fir.ref`. - ```mlir + ``` %a = fir.undefined !fir.array<10 x !fir.type> ``` @@ -432,7 +432,7 @@ def fir_ZeroOp : fir_OneResultOp<"zero_bits", [NoMemoryEffect]> { Constructs an ssa-value of the specified type with a value of zero for all bits. - ```mlir + ``` %a = fir.zero_bits !fir.box>> ``` @@ -563,7 +563,7 @@ def fir_SelectOp : fir_IntegralSwitchTerminatorOp<"select"> { at least one basic block with a corresponding `unit` match, and that block will be selected when all other conditions fail to match. - ```mlir + ``` fir.select %arg:i32 [1, ^bb1(%0 : i32), 2, ^bb2(%2,%arg,%arg2 : i32,i32,i32), -3, ^bb3(%arg2,%2 : i32,i32), @@ -586,7 +586,7 @@ def fir_SelectRankOp : fir_IntegralSwitchTerminatorOp<"select_rank"> { same as `select`, but `select_rank` determines the rank of the selector variable at runtime to determine the best match. - ```mlir + ``` fir.select_rank %arg:i32 [1, ^bb1(%0 : i32), 2, ^bb2(%2,%arg,%arg2 : i32,i32,i32), 3, ^bb3(%arg2,%2 : i32,i32), @@ -608,7 +608,7 @@ def fir_SelectCaseOp : fir_SwitchTerminatorOp<"select_case"> { the same as `select`, but `select_case` allows for the expression of more complex match conditions. - ```mlir + ``` fir.select_case %arg : i32 [ #fir.point, %0, ^bb1(%0 : i32), #fir.lower, %1, ^bb2(%2,%arg,%arg2,%1 : i32,i32,i32,i32), @@ -651,7 +651,7 @@ def fir_SelectTypeOp : fir_SwitchTerminatorOp<"select_type"> { same as `select`, but `select_type` determines the type of the selector variable at runtime to determine the best match. - ```mlir + ``` fir.select_type %arg : !fir.box<()> [ #fir.type_is>, ^bb1(%0 : i32), #fir.type_is>, ^bb2(%2 : i32), @@ -684,7 +684,7 @@ def fir_UnreachableOp : fir_Op<"unreachable", [Terminator]> { program, for example. This instruction corresponds to the LLVM IR instruction `unreachable`. - ```mlir + ``` fir.unreachable ``` }]; @@ -709,7 +709,7 @@ def fir_HasValueOp : fir_Op<"has_value", [Terminator, HasParent<"GlobalOp">]> { let description = [{ The terminator for a GlobalOp with a body. - ```mlir + ``` global @variable : tuple { %0 = arith.constant 45 : i32 %1 = arith.constant 100.0 : f32 @@ -741,7 +741,7 @@ def fir_EmboxOp : fir_Op<"embox", [NoMemoryEffect, AttrSizedOperandSegments]> { auxiliary information is packaged and abstracted as a value with box type by the calling routine. (In Fortran, these are called descriptors.) - ```mlir + ``` %c1 = arith.constant 1 : index %c10 = arith.constant 10 : index %5 = ... : !fir.ref> @@ -824,7 +824,7 @@ def fir_ReboxOp : fir_Op<"rebox", [NoMemoryEffect, AttrSizedOperandSegments]> { where x is described by a fir.box and has non default lower bounds, and then applying a new 2-dimension shape to this fir.box. - ```mlir + ``` %0 = fir.slice %c10, %c33, %c2 : (index, index, index) -> !fir.slice<1> %1 = fir.shift %c0 : (index) -> !fir.shift<1> %2 = fir.rebox %x(%1) [%0] : (!fir.box>, !fir.shift<1>, !fir.slice<1>) -> !fir.box> @@ -861,7 +861,7 @@ def fir_EmboxCharOp : fir_Op<"emboxchar", [NoMemoryEffect]> { ```fortran CHARACTER(LEN=10) :: var ``` - ```mlir + ``` %4 = ... : !fir.ref>> %5 = arith.constant 10 : i32 %6 = fir.emboxchar %4, %5 : (!fir.ref>>, i32) -> !fir.boxchar<1> @@ -891,7 +891,7 @@ def fir_EmboxProcOp : fir_Op<"emboxproc", [NoMemoryEffect]> { internal procedure or the internal procedure does not need a host context then the form takes only the procedure's symbol. - ```mlir + ``` %f = ... : (i32) -> i32 %0 = fir.emboxproc %f : ((i32) -> i32) -> !fir.boxproc<(i32) -> i32> ``` @@ -902,7 +902,7 @@ def fir_EmboxProcOp : fir_Op<"emboxproc", [NoMemoryEffect]> { context's values accordingly, up to and including inhibiting register promotion of local values. - ```mlir + ``` %4 = ... : !fir.ref, !fir.ref>> %g = ... : (i32) -> i32 %5 = fir.emboxproc %g, %4 : ((i32) -> i32, !fir.ref, !fir.ref>>) -> !fir.boxproc<(i32) -> i32> @@ -927,7 +927,7 @@ def fir_UnboxCharOp : fir_SimpleOp<"unboxchar", [NoMemoryEffect]> { Unboxes a value of `boxchar` type into a pair consisting of a memory reference to the CHARACTER data and the LEN type parameter. - ```mlir + ``` %45 = ... : !fir.boxchar<1> %46:2 = fir.unboxchar %45 : (!fir.boxchar<1>) -> (!fir.ref>, i32) ``` @@ -945,7 +945,7 @@ def fir_UnboxProcOp : fir_SimpleOp<"unboxproc", [NoMemoryEffect]> { Unboxes a value of `boxproc` type into a pair consisting of a procedure pointer and a pointer to a host context. - ```mlir + ``` %47 = ... : !fir.boxproc<() -> i32> %48:2 = fir.unboxproc %47 : (!fir.ref<() -> i32>, !fir.ref>) ``` @@ -967,7 +967,7 @@ def fir_BoxAddrOp : fir_SimpleOneResultOp<"box_addr", [NoMemoryEffect]> { cases, respectively, is the address of the data, the address of the `CHARACTER` data, and the address of the procedure. - ```mlir + ``` %51 = fir.box_addr %box : (!fir.box) -> !fir.ref %52 = fir.box_addr %boxchar : (!fir.boxchar<1>) -> !fir.ref> %53 = fir.box_addr %boxproc : (!fir.boxproc) -> !P @@ -989,7 +989,7 @@ def fir_BoxCharLenOp : fir_SimpleOp<"boxchar_len", [NoMemoryEffect]> { let description = [{ Extracts the LEN type parameter from a `boxchar` value. - ```mlir + ``` %45 = ... : !boxchar<1> // CHARACTER(20) %59 = fir.boxchar_len %45 : (!fir.boxchar<1>) -> i64 // len=20 ``` @@ -1011,7 +1011,7 @@ def fir_BoxDimsOp : fir_Op<"box_dims", [NoMemoryEffect]> { left to right from 0 to rank-1. This operation has undefined behavior if `dim` is out of bounds. - ```mlir + ``` %c1 = arith.constant 0 : i32 %52:3 = fir.box_dims %40, %c1 : (!fir.box>, i32) -> (index, index, index) ``` @@ -1044,7 +1044,7 @@ def fir_BoxEleSizeOp : fir_SimpleOneResultOp<"box_elesize", [NoMemoryEffect]> { Returns the size of an element in an entity of `box` type. This size may not be known until runtime. - ```mlir + ``` %53 = fir.box_elesize %40 : (!fir.box) -> i32 // size=4 %54 = fir.box_elesize %40 : (!fir.box>) -> i32 ``` @@ -1065,7 +1065,7 @@ def fir_BoxTypeCodeOp : fir_SimpleOneResultOp<"box_typecode", [NoMemoryEffect]> let description = [{ Returns the descriptor type code of an entity of `box` type. - ```mlir + ``` %1 = fir.box_typecode %0 : (!fir.box) -> i32 ``` }]; @@ -1083,7 +1083,7 @@ def fir_BoxIsAllocOp : fir_SimpleOp<"box_isalloc", [NoMemoryEffect]> { return true if the originating box value was from a `fir.embox` op with a mem-ref value that had the type !fir.heap. - ```mlir + ``` %r = ... : !fir.heap %b = fir.embox %r : (!fir.heap) -> !fir.box %a = fir.box_isalloc %b : (!fir.box) -> i1 // true @@ -1106,7 +1106,7 @@ def fir_BoxIsArrayOp : fir_SimpleOp<"box_isarray", [NoMemoryEffect]> { true if the originating box value was from a fir.embox with a memory reference value that had the type !fir.array and/or a shape argument. - ```mlir + ``` %r = ... : !fir.ref %c_100 = arith.constant 100 : index %d = fir.shape %c_100 : (index) -> !fir.shape<1> @@ -1126,7 +1126,7 @@ def fir_BoxIsPtrOp : fir_SimpleOp<"box_isptr", [NoMemoryEffect]> { let description = [{ Determine if the boxed value was from a POINTER entity. - ```mlir + ``` %p = ... : !fir.ptr %b = fir.embox %p : (!fir.ptr) -> !fir.box %a = fir.box_isptr %b : (!fir.box) -> i1 // true @@ -1144,7 +1144,7 @@ def fir_BoxProcHostOp : fir_SimpleOp<"boxproc_host", [NoMemoryEffect]> { let description = [{ Extract the host context pointer from a boxproc value. - ```mlir + ``` %8 = ... : !fir.boxproc<(!fir.ref>) -> i32> %9 = fir.boxproc_host %8 : (!fir.boxproc<(!fir.ref>) -> i32>) -> !fir.ref> ``` @@ -1167,7 +1167,7 @@ def fir_BoxRankOp : fir_SimpleOneResultOp<"box_rank", [NoMemoryEffect]> { Return the rank of a value of `box` type. If the value is scalar, the rank is 0. - ```mlir + ``` %57 = fir.box_rank %40 : (!fir.box>) -> i32 %58 = fir.box_rank %41 : (!fir.box) -> i32 ``` @@ -1190,7 +1190,7 @@ def fir_BoxTypeDescOp : fir_SimpleOneResultOp<"box_tdesc", [NoMemoryEffect]> { descriptor is an implementation defined value that fully describes a type to the Fortran runtime. - ```mlir + ``` %7 = fir.box_tdesc %41 : (!fir.box) -> !fir.tdesc ``` }]; @@ -1271,7 +1271,7 @@ def fir_ArrayLoadOp : fir_Op<"array_load", [AttrSizedOperandSegments]> { value while applying a runtime shape, shift, or slice to the memory reference, and its semantics guarantee immutability. - ```mlir + ``` %s = fir.shape_shift %o, %n, %p, %m : (index, index, index, index) -> !fir.shapeshift<2> // load the entire array 'a' %v = fir.array_load %a(%s) : (!fir.ref>, !fir.shapeshift<2>) -> !fir.array @@ -1319,7 +1319,7 @@ def fir_ArrayFetchOp : fir_Op<"array_fetch", [AttrSizedOperandSegments, an array expression as shown above. It can also be used to extract the element `a(r,s+1)` in the second expression. - ```mlir + ``` %s = fir.shape %n, %m : (index, index) -> !fir.shape<2> // load the entire array 'a' %v = fir.array_load %a(%s) : (!fir.ref>, !fir.shape<2>) -> !fir.array @@ -1365,7 +1365,7 @@ def fir_ArrayUpdateOp : fir_Op<"array_update", [AttrSizedOperandSegments, One can use `fir.array_update` to update the (implied) value of `a(i,j)` in an array expression as shown above. - ```mlir + ``` %s = fir.shape %n, %m : (index, index) -> !fir.shape<2> // load the entire array 'a' %v = fir.array_load %a(%s) : (!fir.ref>, !fir.shape<2>) -> !fir.array @@ -1419,7 +1419,7 @@ def fir_ArrayModifyOp : fir_Op<"array_modify", [AttrSizedOperandSegments, One can use `fir.array_modify` to update the (implied) value of `a(i)` in an array expression as shown above. - ```mlir + ``` %s = fir.shape %n : (index) -> !fir.shape<1> // Load the entire array 'a'. %v = fir.array_load %a(%s) : (!fir.ref>, !fir.shape<1>) -> !fir.array @@ -1482,7 +1482,7 @@ def fir_ArrayAccessOp : fir_Op<"array_access", [AttrSizedOperandSegments, be used to recover the reference element `a(r,s+1)` in the second expression. - ```mlir + ``` %s = fir.shape %n, %m : (index, index) -> !fir.shape<2> // load the entire array 'a' %v = fir.array_load %a(%s) : (!fir.ref>, !fir.shape<2>) -> !fir.array @@ -1527,7 +1527,7 @@ def fir_ArrayAmendOp : fir_Op<"array_amend", [NoMemoryEffect]> { log that is used to merge the final result back with an `array_merge_store` operation. - ```mlir + ``` // fetch the value of one of the array value's elements %1 = fir.array_access %v, %i, %j : (!fir.array, index, index) -> !fir.ref // modify the element by storing data using %1 as a reference @@ -1569,7 +1569,7 @@ def fir_ArrayMergeStoreOp : fir_Op<"array_merge_store", One can use `fir.array_merge_store` to merge/copy the value of `a` in an array expression as shown above. - ```mlir + ``` %v = fir.array_load %a(%shape) : ... %r = fir.array_update %v, %f, %i, %j : (!fir.array, f32, index, index) -> !fir.array fir.array_merge_store %v, %r to %a : !fir.ref> @@ -1620,7 +1620,7 @@ def fir_ArrayCoorOp : fir_Op<"array_coor", One can use `fir.array_coor` to determine the address of `a(i,j)`. - ```mlir + ``` %s = fir.shape %n, %m : (index, index) -> !fir.shape<2> %1 = fir.array_coor %a(%s) %i, %j : (!fir.ref>, !fir.shape<2>, index, index) -> !fir.ref ``` @@ -1659,7 +1659,7 @@ def fir_CoordinateOp : fir_Op<"coordinate_of", [NoMemoryEffect]> { Unlike LLVM's GEP instruction, one cannot stride over the outermost reference; therefore, the leading 0 index must be omitted. - ```mlir + ``` %i = ... : index %h = ... : !fir.heap> %p = fir.coordinate_of %h, %i : (!fir.heap>, index) -> !fir.ref @@ -1701,7 +1701,7 @@ def fir_ExtractValueOp : fir_OneResultOp<"extract_value", [NoMemoryEffect]> { Note that the entity ssa-value must be of compile-time known size in order to use this operation. - ```mlir + ``` %f = fir.field_index field, !fir.type %s = ... : !fir.type %v = fir.extract_value %s, %f : (!fir.type, !fir.field) -> i32 @@ -1729,7 +1729,7 @@ def fir_FieldIndexOp : fir_OneResultOp<"field_index", [NoMemoryEffect]> { or `fir.insert_value` instructions to compute (abstract) addresses of subobjects. - ```mlir + ``` %f = fir.field_index field, !fir.type ``` }]; @@ -1764,7 +1764,7 @@ def fir_ShapeOp : fir_Op<"shape", [NoMemoryEffect]> { must be applied to a reified object, so all shape information must be specified. The extent must be nonnegative. - ```mlir + ``` %d = fir.shape %row_sz, %col_sz : (index, index) -> !fir.shape<2> ``` }]; @@ -1796,7 +1796,7 @@ def fir_ShapeShiftOp : fir_Op<"shape_shift", [NoMemoryEffect]> { be applied to a reified object, so all shifted shape information must be specified. The extent must be nonnegative. - ```mlir + ``` %d = fir.shape_shift %lo, %extent : (index, index) -> !fir.shapeshift<1> ``` }]; @@ -1843,7 +1843,7 @@ def fir_ShiftOp : fir_Op<"shift", [NoMemoryEffect]> { must be applied to a reified object, so all shift information must be specified. - ```mlir + ``` %d = fir.shift %row_lb, %col_lb : (index, index) -> !fir.shift<2> ``` }]; @@ -1872,7 +1872,7 @@ def fir_SliceOp : fir_Op<"slice", [NoMemoryEffect, AttrSizedOperandSegments]> { must be applied to a reified object, so all slice information must be specified. The extent must be nonnegative and the stride must not be zero. - ```mlir + ``` %d = fir.slice %lo, %hi, %step : (index, index, index) -> !fir.slice<1> ``` @@ -1880,7 +1880,7 @@ def fir_SliceOp : fir_Op<"slice", [NoMemoryEffect, AttrSizedOperandSegments]> { op can be given a component path (narrowing from the product type of the original array to the specific elemental type of the sliced projection). - ```mlir + ``` %fld = fir.field_index component, !fir.type %d = fir.slice %lo, %hi, %step path %fld : (index, index, index, !fir.field) -> !fir.slice<1> @@ -1889,7 +1889,7 @@ def fir_SliceOp : fir_Op<"slice", [NoMemoryEffect, AttrSizedOperandSegments]> { Projections of `!fir.char` type can be further narrowed to invariant substrings. - ```mlir + ``` %d = fir.slice %lo, %hi, %step substr %offset, %width : (index, index, index, index, index) -> !fir.slice<1> ``` @@ -1935,7 +1935,7 @@ def fir_InsertValueOp : fir_OneResultOp<"insert_value", [NoMemoryEffect]> { Note that the entity ssa-value must be of compile-time known size in order to use this operation. - ```mlir + ``` %a = ... : !fir.array<10xtuple> %f = ... : f32 %o = ... : i32 @@ -1965,7 +1965,7 @@ def fir_InsertOnRangeOp : fir_OneResultOp<"insert_on_range", [NoMemoryEffect]> { row-to-column element order as specified by lower and upper bound coordinates. - ```mlir + ``` %a = fir.undefined !fir.array<10x10xf32> %c = arith.constant 3.0 : f32 %1 = fir.insert_on_range %a, %c from (0, 0) to (7, 2) : (!fir.array<10x10xf32>, f32) -> !fir.array<10x10xf32> @@ -1995,7 +1995,7 @@ def fir_LenParamIndexOp : fir_OneResultOp<"len_param_index", [NoMemoryEffect]> { used with the `fir.coordinate_of` instructions to compute (abstract) addresses of LEN parameters. - ```mlir + ``` %e = fir.len_param_index len1, !fir.type %p = ... : !fir.box> %q = fir.coordinate_of %p, %e : (!fir.box>, !fir.len) -> !fir.ref @@ -2062,7 +2062,7 @@ def fir_DoLoopOp : region_Op<"do_loop", Generalized high-level looping construct. This operation is similar to MLIR's `scf.for`. - ```mlir + ``` %l = arith.constant 0 : index %u = arith.constant 9 : index %s = arith.constant 1 : index @@ -2154,7 +2154,7 @@ def fir_IfOp : region_Op<"if", [DeclareOpInterfaceMethods fir.if %56 { @@ -2218,7 +2218,7 @@ def fir_IterWhileOp : region_Op<"iterate_while", %ok=phi(%okIn,%okNew), and %sh=phi(%shIn,%shNew) from the last executed iteration. - ```mlir + ``` %v:3 = fir.iterate_while (%i = %lo to %up step %c1) and (%ok = %okIn) iter_args(%sh = %shIn) -> (index, i1, i16) { %shNew = fir.call @bar(%sh) : (i16) -> i16 %okNew = fir.call @foo(%sh) : (i16) -> i1 @@ -2304,7 +2304,7 @@ def fir_CallOp : fir_Op<"call", Provides a custom parser and pretty printer to allow a more readable syntax in the FIR dialect, e.g. `fir.call @sub(%12)` or `fir.call %20(%22,%23)`. - ```mlir + ``` %a = fir.call %funcref(%arg0) : (!fir.ref) -> f32 %b = fir.call @function(%arg1, %arg2) : (!fir.ref, !fir.ref) -> f32 ``` @@ -2383,7 +2383,7 @@ def fir_DispatchOp : fir_Op<"dispatch", []> { used to select a dispatch operand other than the first one. The absence of `pass_arg_pos` attribute means nopass. - ```mlir + ``` // fir.dispatch with no attribute. %r = fir.dispatch "methodA"(%o) : (!fir.class) -> i32 @@ -2430,7 +2430,7 @@ def fir_StringLitOp : fir_Op<"string_lit", [NoMemoryEffect]> { to Fortran's CHARACTER type, including a LEN. We support CHARACTER values of different KINDs (different constant sizes). - ```mlir + ``` %1 = fir.string_lit "Hello, World!"(13) : !fir.char<1> // ASCII %2 = fir.string_lit [158, 2345](2) : !fir.char<2> // Wide chars ``` @@ -2572,7 +2572,7 @@ def fir_AddrOfOp : fir_OneResultOp<"address_of", [NoMemoryEffect]> { used in other operations. References to Fortran symbols are distinguished via this operation from other arbitrary constant values. - ```mlir + ``` %p = fir.address_of(@symbol) : !fir.ref ``` }]; @@ -2593,7 +2593,7 @@ def fir_ConvertOp : fir_OneResultOp<"convert", [NoMemoryEffect]> { type, this instruction is a NOP and may be folded away. This also supports integer to pointer conversion and pointer to integer conversion. - ```mlir + ``` %v = ... : i64 %w = fir.convert %v : (i64) -> i32 ``` @@ -2639,7 +2639,7 @@ def fir_TypeDescOp : fir_OneResultOp<"type_desc", [NoMemoryEffect]> { specified type. The meta-type of a type descriptor for the type `T` is `!fir.tdesc`. - ```mlir + ``` %t = fir.type_desc !fir.type<> // returns value of !fir.tdesc ``` }]; @@ -2664,7 +2664,7 @@ def fir_NoReassocOp : fir_OneResultOp<"no_reassoc", example below, this would prevent possibly replacing the multiply and add operations with a single FMA operation. - ```mlir + ``` %98 = arith.mulf %96, %97 : f32 %99 = fir.no_reassoc %98 : f32 %a0 = arith.addf %99, %95 : f32 @@ -2689,7 +2689,7 @@ def fir_GlobalOp : fir_Op<"global", [IsolatedFromAbove, Symbol]> { `@_QV_Mquark_Vvarble` with some initial values. The initializer should conform to the variable's type. - ```mlir + ``` fir.global @_QV_Mquark_Vvarble : tuple { %1 = arith.constant 1 : i32 %2 = arith.constant 2.0 : f32 @@ -2778,6 +2778,10 @@ def fir_GlobalOp : fir_Op<"global", [IsolatedFromAbove, Symbol]> { (*this)->getAttrOfType( mlir::SymbolTable::getSymbolAttrName()).getValue()); } + + bool isInitialized() { + return getInitVal() || hasInitializationBody(); + } }]; } @@ -2788,7 +2792,7 @@ def fir_GlobalLenOp : fir_Op<"global_len", []> { parameter (compile-time) constants associated with the instance's type. These values can be bound to the global instance used `fir.global_len`. - ```mlir + ``` global @g : !fir.type { fir.global_len len1, 10 : i32 %1 = fir.undefined !fir.type @@ -2809,20 +2813,31 @@ def fir_GlobalLenOp : fir_Op<"global_len", []> { def ImplicitFirTerminator : SingleBlockImplicitTerminator<"FirEndOp">; -def fir_DispatchTableOp : fir_Op<"dispatch_table", +def fir_TypeInfoOp : fir_Op<"type_info", [IsolatedFromAbove, Symbol, ImplicitFirTerminator]> { - let summary = "Dispatch table definition"; + let summary = "Derived type information"; let description = [{ - Define a dispatch table for a derived type with type-bound procedures. + Define extra information about a !fir.type<> that represents + a Fortran derived type. - A dispatch table is an untyped symbol that contains a list of associations + The optional dispatch table region defines a dispatch table with the derived + type type-bound procedures. It contains a list of associations between method identifiers and corresponding `FuncOp` symbols. - The ordering of associations in the map is determined by the front end. - ```mlir - fir.dispatch_table @_QDTMquuzTfoo { + The "no_init" flag indicates that this type has no components requiring default + initialization (including setting allocatable component to a clean deallocated + state). + + The "no_destroy" flag indicates that there are no allocatable components + that require deallocation. + + The "no_final" flag indicates that there are no final methods for this type, + for its parents ,or for components. + + ``` + fir.type_info @_QMquuzTfoo noinit nofinal : !fir.type<_QMquuzTfoo{i:i32}> dispatch_table { fir.dt_entry method1, @_QFNMquuzTfooPmethod1AfooR fir.dt_entry method2, @_QFNMquuzTfooPmethod2AfooII } @@ -2831,32 +2846,46 @@ def fir_DispatchTableOp : fir_Op<"dispatch_table", let arguments = (ins SymbolNameAttr:$sym_name, - OptionalAttr:$parent + TypeAttr:$type, + OptionalAttr:$parent_type, + UnitAttr:$no_init, + UnitAttr:$no_destroy, + UnitAttr:$no_final ); - let hasCustomAssemblyFormat = 1; let hasVerifier = 1; - let regions = (region AnyRegion:$region); + let regions = (region MaxSizedRegion<1>:$dispatch_table); - let skipDefaultBuilders = 1; let builders = [ - OpBuilder<(ins "llvm::StringRef":$name, "mlir::Type":$type, - "llvm::StringRef":$parent, + OpBuilder<(ins "fir::RecordType":$type, "fir::RecordType":$parent_type, CArg<"llvm::ArrayRef", "{}">:$attrs)> ]; - let extraClassDeclaration = [{ - static constexpr llvm::StringRef getParentAttrNameStr() { return "parent"; } - static constexpr llvm::StringRef getExtendsKeyword() { return "extends"; } + let assemblyFormat = [{ + $sym_name (`noinit` $no_init^)? (`nodestroy` $no_destroy^)? + (`nofinal` $no_final^)? (`extends` $parent_type^)? attr-dict `:` $type + (`dispatch_table` $dispatch_table^)? + }]; - mlir::Block &getBlock() { - return getRegion().front(); + let extraClassDeclaration = [{ + fir::RecordType getRecordType() { + return mlir::cast(getType()); + } + fir::RecordType getIfParentType() { + if (auto parentType = getParentType()) + return mlir::cast(*parentType); + return {}; + } + std::optional getIfParentName() { + if (auto parentType = getIfParentType()) + return parentType.getName(); + return std::nullopt; } }]; } -def fir_DTEntryOp : fir_Op<"dt_entry", [HasParent<"DispatchTableOp">]> { +def fir_DTEntryOp : fir_Op<"dt_entry", [HasParent<"TypeInfoOp">]> { let summary = "map entry in a dispatch table"; let description = [{ @@ -2866,7 +2895,7 @@ def fir_DTEntryOp : fir_Op<"dt_entry", [HasParent<"DispatchTableOp">]> { and uses the method identifier to select the type-bound procedure to be called. - ```mlir + ``` fir.dt_entry method_name, @uniquedProcedure ``` }]; @@ -2890,7 +2919,7 @@ def fir_AbsentOp : fir_OneResultOp<"absent", [NoMemoryEffect]> { a fir.absent operation. It is undefined to use a value that was created by a fir.absent op in any other operation than fir.call and fir.is_present. - ```mlir + ``` %1 = fir.absent fir.box> fir.call @_QPfoo(%1) : (fir.box>) -> () ``` @@ -2907,7 +2936,7 @@ def fir_IsPresentOp : fir_SimpleOp<"is_present", [NoMemoryEffect]> { let description = [{ Determine if an optional function argument is PRESENT (i.e. that it was not created by a fir.absent op on the caller side). - ```mlir + ``` func @_QPfoo(%arg0: !fir.box>) { %0 = fir.is_present %arg0 : (!fir.box>) -> i1 ... diff --git a/flang/include/flang/Optimizer/Dialect/FIRType.h b/flang/include/flang/Optimizer/Dialect/FIRType.h index 4eea6d2bbb3ee..2abcc6547bbab 100644 --- a/flang/include/flang/Optimizer/Dialect/FIRType.h +++ b/flang/include/flang/Optimizer/Dialect/FIRType.h @@ -336,6 +336,9 @@ bool isAssumedType(mlir::Type ty); /// Return true iff `ty` is the type of an assumed shape array. bool isAssumedShape(mlir::Type ty); +/// Return true iff `ty` is the type of an allocatable array. +bool isAllocatableOrPointerArray(mlir::Type ty); + /// Return true iff `boxTy` wraps a record type or an unlimited polymorphic /// entity. Polymorphic entities with intrinsic type spec do not have addendum inline bool boxHasAddendum(fir::BaseBoxType boxTy) { diff --git a/flang/include/flang/Optimizer/HLFIR/Passes.td b/flang/include/flang/Optimizer/HLFIR/Passes.td index c6e503c3a2760..dae96b3f767ea 100644 --- a/flang/include/flang/Optimizer/HLFIR/Passes.td +++ b/flang/include/flang/Optimizer/HLFIR/Passes.td @@ -13,6 +13,9 @@ include "mlir/Pass/PassBase.td" def ConvertHLFIRtoFIR : Pass<"convert-hlfir-to-fir", "::mlir::ModuleOp"> { let summary = "Lower High-Level FIR to FIR"; let constructor = "hlfir::createConvertHLFIRtoFIRPass()"; + let dependentDialects = [ + "mlir::func::FuncDialect", + ]; } def BufferizeHLFIR : Pass<"bufferize-hlfir", "::mlir::ModuleOp"> { diff --git a/flang/include/flang/Optimizer/Support/Utils.h b/flang/include/flang/Optimizer/Support/Utils.h index ebf506543ebf4..d5b045924f3c0 100644 --- a/flang/include/flang/Optimizer/Support/Utils.h +++ b/flang/include/flang/Optimizer/Support/Utils.h @@ -36,21 +36,22 @@ using BindingTables = llvm::DenseMap; inline void buildBindingTables(BindingTables &bindingTables, mlir::ModuleOp mod) { - // The binding tables are defined in FIR from lowering as fir.dispatch_table - // operation. Go through each binding tables and store the procedure name and + // The binding tables are defined in FIR after lowering inside fir.type_info + // operations. Go through each binding tables and store the procedure name and // binding index for later use by the fir.dispatch conversion pattern. - for (auto dispatchTableOp : mod.getOps()) { + for (auto typeInfo : mod.getOps()) { unsigned bindingIdx = 0; BindingTable bindings; - if (dispatchTableOp.getRegion().empty()) { - bindingTables[dispatchTableOp.getSymName()] = bindings; + if (typeInfo.getDispatchTable().empty()) { + bindingTables[typeInfo.getSymName()] = bindings; continue; } - for (auto dtEntry : dispatchTableOp.getBlock().getOps()) { + for (auto dtEntry : + typeInfo.getDispatchTable().front().getOps()) { bindings[dtEntry.getMethod()] = bindingIdx; ++bindingIdx; } - bindingTables[dispatchTableOp.getSymName()] = bindings; + bindingTables[typeInfo.getSymName()] = bindings; } } diff --git a/flang/include/flang/Optimizer/Transforms/Passes.h b/flang/include/flang/Optimizer/Transforms/Passes.h index 8aeb3e373298e..64882c8ec406b 100644 --- a/flang/include/flang/Optimizer/Transforms/Passes.h +++ b/flang/include/flang/Optimizer/Transforms/Passes.h @@ -80,6 +80,10 @@ std::unique_ptr createOMPFunctionFilteringPass(); std::unique_ptr> createOMPMarkDeclareTargetPass(); +std::unique_ptr createVScaleAttrPass(); +std::unique_ptr +createVScaleAttrPass(std::pair vscaleAttr); + // declarative passes #define GEN_PASS_REGISTRATION #include "flang/Optimizer/Transforms/Passes.h.inc" diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td index 9474edf13ce46..80da485392007 100644 --- a/flang/include/flang/Optimizer/Transforms/Passes.td +++ b/flang/include/flang/Optimizer/Transforms/Passes.td @@ -326,4 +326,18 @@ def OMPFunctionFiltering : Pass<"omp-function-filtering"> { ]; } +def VScaleAttr : Pass<"vscale-attr", "mlir::func::FuncOp"> { + let summary = "Add vscale_range attribute to functions"; + let description = [{ + Set an attribute for the vscale range on functions, to allow scalable + vector operations to be used on processors with variable vector length. + }]; + let options = [ + Option<"vscaleRange", "vscale-range", + "std::pair", /*default=*/"std::pair{}", + "vector scale range">, + ]; + let constructor = "::fir::createVScaleAttrPass()"; +} + #endif // FLANG_OPTIMIZER_TRANSFORMS_PASSES diff --git a/flang/include/flang/Runtime/api-attrs.h b/flang/include/flang/Runtime/api-attrs.h index 7420472aed670..61da2c06d3a4d 100644 --- a/flang/include/flang/Runtime/api-attrs.h +++ b/flang/include/flang/Runtime/api-attrs.h @@ -45,7 +45,7 @@ /* * RT_OFFLOAD_API_GROUP_BEGIN/END pair is placed around definitions * of functions that can be referenced in other modules of Flang - * runtime. For OpenMP offload these functions are made "declare target" + * runtime. For OpenMP offload, these functions are made "declare target" * making sure they are compiled for the target even though direct * references to them from other "declare target" functions may not * be seen. Host-only functions should not be put in between these @@ -54,6 +54,15 @@ #define RT_OFFLOAD_API_GROUP_BEGIN RT_EXT_API_GROUP_BEGIN #define RT_OFFLOAD_API_GROUP_END RT_EXT_API_GROUP_END +/* + * RT_OFFLOAD_VAR_GROUP_BEGIN/END pair is placed around definitions + * of variables (e.g. globals or static class members) that can be + * referenced in functions marked with RT_OFFLOAD_API_GROUP_BEGIN/END. + * For OpenMP offload, these variables are made "declare target". + */ +#define RT_OFFLOAD_VAR_GROUP_BEGIN RT_EXT_API_GROUP_BEGIN +#define RT_OFFLOAD_VAR_GROUP_END RT_EXT_API_GROUP_END + /* * RT_VAR_GROUP_BEGIN/END pair is placed around definitions * of module scope variables referenced by Flang runtime (directly diff --git a/flang/include/flang/Runtime/assign.h b/flang/include/flang/Runtime/assign.h index 779997dab6186..b19c02f44c73b 100644 --- a/flang/include/flang/Runtime/assign.h +++ b/flang/include/flang/Runtime/assign.h @@ -30,23 +30,23 @@ class Descriptor; extern "C" { // API for lowering assignment -void RTNAME(Assign)(Descriptor &to, const Descriptor &from, +void RTDECL(Assign)(Descriptor &to, const Descriptor &from, const char *sourceFile = nullptr, int sourceLine = 0); // This variant has no finalization, defined assignment, or allocatable // reallocation. -void RTNAME(AssignTemporary)(Descriptor &to, const Descriptor &from, +void RTDECL(AssignTemporary)(Descriptor &to, const Descriptor &from, const char *sourceFile = nullptr, int sourceLine = 0); -void RTNAME(CopyOutAssign)(Descriptor &to, const Descriptor &from, +void RTDECL(CopyOutAssign)(Descriptor &to, const Descriptor &from, bool skipToInit, const char *sourceFile = nullptr, int sourceLine = 0); // This variant is for assignments to explicit-length CHARACTER left-hand // sides that might need to handle truncation or blank-fill, and // must maintain the character length even if an allocatable array // is reallocated. -void RTNAME(AssignExplicitLengthCharacter)(Descriptor &to, +void RTDECL(AssignExplicitLengthCharacter)(Descriptor &to, const Descriptor &from, const char *sourceFile = nullptr, int sourceLine = 0); // This variant is assignments to whole polymorphic allocatables. -void RTNAME(AssignPolymorphic)(Descriptor &to, const Descriptor &from, +void RTDECL(AssignPolymorphic)(Descriptor &to, const Descriptor &from, const char *sourceFile = nullptr, int sourceLine = 0); } // extern "C" } // namespace Fortran::runtime diff --git a/flang/include/flang/Runtime/descriptor.h b/flang/include/flang/Runtime/descriptor.h index d26139321227f..c9a3b1b031007 100644 --- a/flang/include/flang/Runtime/descriptor.h +++ b/flang/include/flang/Runtime/descriptor.h @@ -427,11 +427,13 @@ static_assert(sizeof(Descriptor) == sizeof(ISO::CFI_cdesc_t)); template class alignas(Descriptor) StaticDescriptor { public: + RT_OFFLOAD_VAR_GROUP_BEGIN static constexpr int maxRank{MAX_RANK}; static constexpr int maxLengthTypeParameters{MAX_LEN_PARMS}; static constexpr bool hasAddendum{ADDENDUM || MAX_LEN_PARMS > 0}; static constexpr std::size_t byteSize{ Descriptor::SizeInBytes(maxRank, hasAddendum, maxLengthTypeParameters)}; + RT_OFFLOAD_VAR_GROUP_END RT_API_ATTRS Descriptor &descriptor() { return *reinterpret_cast(storage_); diff --git a/flang/include/flang/Tools/CLOptions.inc b/flang/include/flang/Tools/CLOptions.inc index 0b210bec9f785..76d18b73aee20 100644 --- a/flang/include/flang/Tools/CLOptions.inc +++ b/flang/include/flang/Tools/CLOptions.inc @@ -299,6 +299,10 @@ inline void createDefaultFIRCodeGenPassPipeline( fir::addTargetRewritePass(pm); fir::addExternalNameConversionPass(pm, config.Underscoring); fir::createDebugPasses(pm, config.DebugInfo); + + if (config.VScaleMin != 0) + pm.addPass(fir::createVScaleAttrPass({config.VScaleMin, config.VScaleMax})); + fir::addFIRToLLVMPass(pm, config.OptLevel); } diff --git a/flang/include/flang/Tools/CrossToolHelpers.h b/flang/include/flang/Tools/CrossToolHelpers.h index 8453828995ad0..6245a2f1376fc 100644 --- a/flang/include/flang/Tools/CrossToolHelpers.h +++ b/flang/include/flang/Tools/CrossToolHelpers.h @@ -42,6 +42,8 @@ struct MLIRToLLVMPassPipelineConfig { bool LoopVersioning = false; ///< Run the version loop pass. llvm::codegenoptions::DebugInfoKind DebugInfo = llvm::codegenoptions::NoDebugInfo; ///< Debug info generation. + unsigned VScaleMin = 0; ///< SVE vector range minimum. + unsigned VScaleMax = 0; ///< SVE vector range maximum. }; struct OffloadModuleOpts { diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index fa12e37607cf1..73c00c8679c7e 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -695,6 +695,22 @@ void CodeGenAction::lowerHLFIRToFIR() { } } +// TODO: We should get this from TargetInfo. However, that depends on +// too much of clang, so for now, replicate the functionality. +static std::optional> +getVScaleRange(CompilerInstance &ci, + const Fortran::frontend::LangOptions &langOpts) { + if (langOpts.VScaleMin || langOpts.VScaleMax) + return std::pair( + langOpts.VScaleMin ? langOpts.VScaleMin : 1, langOpts.VScaleMax); + + std::string featuresStr = getTargetFeatures(ci); + if (featuresStr.find("+sve") != std::string::npos) + return std::pair(1, 16); + + return std::nullopt; +} + // Lower the previously generated MLIR module into an LLVM IR module void CodeGenAction::generateLLVMIR() { assert(mlirModule && "The MLIR module has not been generated yet."); @@ -715,6 +731,18 @@ void CodeGenAction::generateLLVMIR() { MLIRToLLVMPassPipelineConfig config(level, opts); + const auto targetOpts = ci.getInvocation().getTargetOpts(); + const llvm::Triple triple(targetOpts.triple); + + // Only get the vscale range if AArch64. + if (triple.isAArch64()) { + auto langOpts = ci.getInvocation().getLangOpts(); + if (auto vsr = getVScaleRange(ci, langOpts)) { + config.VScaleMin = vsr->first; + config.VScaleMax = vsr->second; + } + } + // Create the pass pipeline fir::createMLIRToLLVMPassPipeline(pm, config); (void)mlir::applyPassManagerCLOptions(pm); diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index ee838b3b4a546..5ac4d822faaae 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -137,34 +137,41 @@ struct ConstructContext { Fortran::lower::StatementContext &stmtCtx; // construct exit code }; -/// Helper class to generate the runtime type info global data. This data -/// is required to describe the derived type to the runtime so that it can -/// operate over it. It must be ensured this data will be generated for every -/// derived type lowered in the current translated unit. However, this data +/// Helper class to generate the runtime type info global data and the +/// fir.type_info operations that contain the dipatch tables (if any). +/// The type info global data is required to describe the derived type to the +/// runtime so that it can operate over it. +/// It must be ensured these operations will be generated for every derived type +/// lowered in the current translated unit. However, these operations /// cannot be generated before FuncOp have been created for functions since the /// initializers may take their address (e.g for type bound procedures). This -/// class allows registering all the required runtime type info while it is not -/// possible to create globals, and to generate this data after function -/// lowering. -class RuntimeTypeInfoConverter { +/// class allows registering all the required type info while it is not +/// possible to create GlobalOp/TypeInfoOp, and to generate this data afte +/// function lowering. +class TypeInfoConverter { /// Store the location and symbols of derived type info to be generated. /// The location of the derived type instantiation is also stored because - /// runtime type descriptor symbol are compiler generated and cannot be mapped - /// to user code on their own. - struct TypeInfoSymbol { + /// runtime type descriptor symbols are compiler generated and cannot be + /// mapped to user code on their own. + struct TypeInfo { Fortran::semantics::SymbolRef symbol; + const Fortran::semantics::DerivedTypeSpec &typeSpec; + fir::RecordType type; mlir::Location loc; }; public: - void registerTypeInfoSymbol(Fortran::lower::AbstractConverter &converter, - mlir::Location loc, - Fortran::semantics::SymbolRef typeInfoSym) { + void registerTypeInfo(Fortran::lower::AbstractConverter &converter, + mlir::Location loc, + Fortran::semantics::SymbolRef typeInfoSym, + const Fortran::semantics::DerivedTypeSpec &typeSpec, + fir::RecordType type) { if (seen.contains(typeInfoSym)) return; seen.insert(typeInfoSym); if (!skipRegistration) { - registeredTypeInfoSymbols.emplace_back(TypeInfoSymbol{typeInfoSym, loc}); + registeredTypeInfo.emplace_back( + TypeInfo{typeInfoSym, typeSpec, type, loc}); return; } // Once the registration is closed, symbols cannot be added to the @@ -172,67 +179,59 @@ class RuntimeTypeInfoConverter { // However, after registration is closed, it is safe to directly generate // the globals because all FuncOps whose addresses may be required by the // initializers have been generated. - Fortran::lower::createRuntimeTypeInfoGlobal(converter, loc, - typeInfoSym.get()); + createTypeInfoOpAndGlobal(converter, + TypeInfo{typeInfoSym, typeSpec, type, loc}); } - void createTypeInfoGlobals(Fortran::lower::AbstractConverter &converter) { + void createTypeInfo(Fortran::lower::AbstractConverter &converter) { skipRegistration = true; - for (const TypeInfoSymbol &info : registeredTypeInfoSymbols) - Fortran::lower::createRuntimeTypeInfoGlobal(converter, info.loc, - info.symbol.get()); - registeredTypeInfoSymbols.clear(); + for (const TypeInfo &info : registeredTypeInfo) + createTypeInfoOpAndGlobal(converter, info); + registeredTypeInfo.clear(); } private: - /// Store the runtime type descriptors that will be required for the - /// derived type that have been converted to FIR derived types. - llvm::SmallVector registeredTypeInfoSymbols; - /// Create derived type runtime info global immediately without storing the - /// symbol in registeredTypeInfoSymbols. - bool skipRegistration = false; - /// Track symbols symbols processed during and after the registration - /// to avoid infinite loops between type conversions and global variable - /// creation. - llvm::SmallSetVector seen; -}; - -class DispatchTableConverter { - struct DispatchTableInfo { - const Fortran::semantics::DerivedTypeSpec *typeSpec; - mlir::Location loc; - }; - -public: - void registerTypeSpec(Fortran::lower::AbstractConverter &converter, - mlir::Location loc, - const Fortran::semantics::DerivedTypeSpec *typeSpec) { - assert(typeSpec && "type spec is null"); - std::string dtName = converter.mangleName(*typeSpec); - if (seen.contains(dtName) || dtName.find("__fortran") != std::string::npos) - return; - seen.insert(dtName); - registeredDispatchTableInfo.emplace_back(DispatchTableInfo{typeSpec, loc}); - } - - void createDispatchTableOps(Fortran::lower::AbstractConverter &converter) { - for (const DispatchTableInfo &info : registeredDispatchTableInfo) { - std::string dtName = converter.mangleName(*info.typeSpec); - const Fortran::semantics::DerivedTypeSpec *parent = - Fortran::evaluate::GetParentTypeSpec(*info.typeSpec); - fir::FirOpBuilder &builder = converter.getFirOpBuilder(); - fir::DispatchTableOp dt = builder.createDispatchTableOp( - info.loc, dtName, parent ? converter.mangleName(*parent) : ""); - auto insertPt = builder.saveInsertionPoint(); - const Fortran::semantics::Scope *scope = info.typeSpec->scope(); - if (!scope) - scope = info.typeSpec->typeSymbol().scope(); - Fortran::semantics::SymbolVector bindings = - Fortran::semantics::CollectBindings(*scope); - - if (!bindings.empty()) - builder.createBlock(&dt.getRegion()); - + void createTypeInfoOpAndGlobal(Fortran::lower::AbstractConverter &converter, + const TypeInfo &info) { + Fortran::lower::createRuntimeTypeInfoGlobal(converter, info.loc, + info.symbol.get()); + createTypeInfoOp(converter, info); + } + + void createTypeInfoOp(Fortran::lower::AbstractConverter &converter, + const TypeInfo &info) { + fir::RecordType parentType{}; + if (const Fortran::semantics::DerivedTypeSpec *parent = + Fortran::evaluate::GetParentTypeSpec(info.typeSpec)) + parentType = mlir::cast(converter.genType(*parent)); + + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); + mlir::ModuleOp module = builder.getModule(); + fir::TypeInfoOp dt = + module.lookupSymbol(info.type.getName()); + if (dt) + return; // Already created. + auto insertPt = builder.saveInsertionPoint(); + builder.setInsertionPoint(module.getBody(), module.getBody()->end()); + dt = builder.create(info.loc, info.type, parentType); + + if (!info.typeSpec.HasDefaultInitialization(/*ignoreAllocatable=*/false, + /*ignorePointer=*/false)) + dt->setAttr(dt.getNoInitAttrName(), builder.getUnitAttr()); + if (!info.typeSpec.HasDestruction()) + dt->setAttr(dt.getNoDestroyAttrName(), builder.getUnitAttr()); + if (!Fortran::semantics::MayRequireFinalization(info.typeSpec)) + dt->setAttr(dt.getNoFinalAttrName(), builder.getUnitAttr()); + + const Fortran::semantics::Scope *scope = info.typeSpec.scope(); + if (!scope) + scope = info.typeSpec.typeSymbol().scope(); + assert(scope && "failed to find type scope"); + + Fortran::semantics::SymbolVector bindings = + Fortran::semantics::CollectBindings(*scope); + if (!bindings.empty()) { + builder.createBlock(&dt.getDispatchTable()); for (const Fortran::semantics::SymbolRef &binding : bindings) { const auto &details = binding.get().get(); @@ -244,20 +243,21 @@ class DispatchTableConverter { info.loc, mlir::StringAttr::get(builder.getContext(), tbpName), mlir::SymbolRefAttr::get(builder.getContext(), bindingName)); } - if (!bindings.empty()) - builder.create(info.loc); - builder.restoreInsertionPoint(insertPt); + builder.create(info.loc); } - registeredDispatchTableInfo.clear(); + builder.restoreInsertionPoint(insertPt); } -private: - /// Store the semantic DerivedTypeSpec that will be required to generate the - /// dispatch table. - llvm::SmallVector registeredDispatchTableInfo; - - /// Track processed type specs to avoid multiple creation. - llvm::StringSet<> seen; + /// Store the front-end data that will be required to generate the type info + /// for the derived types that have been converted to fir.type<>. + llvm::SmallVector registeredTypeInfo; + /// Create derived type info immediately without storing the + /// symbol in registeredTypeInfo. + bool skipRegistration = false; + /// Track symbols symbols processed during and after the registration + /// to avoid infinite loops between type conversions and global variable + /// creation. + llvm::SmallSetVector seen; }; using IncrementLoopNestInfo = llvm::SmallVector; @@ -334,13 +334,10 @@ class FirConverter : public Fortran::lower::AbstractConverter { /// Once all the code has been translated, create runtime type info /// global data structure for the derived types that have been - /// processed. - createGlobalOutsideOfFunctionLowering( - [&]() { runtimeTypeInfoConverter.createTypeInfoGlobals(*this); }); - - /// Create the dispatch tables for derived types. + /// processed as well as the fir.type_info operations with the + /// dispatch tables. createGlobalOutsideOfFunctionLowering( - [&]() { dispatchTableConverter.createDispatchTableOps(*this); }); + [&]() { typeInfoConverter.createTypeInfo(*this); }); // Create the list of any environment defaults for the runtime to set. The // runtime default list is only created if there is a main program to ensure @@ -875,16 +872,11 @@ class FirConverter : public Fortran::lower::AbstractConverter { hostAssocTuple = val; } - void registerRuntimeTypeInfo( - mlir::Location loc, - Fortran::lower::SymbolRef typeInfoSym) override final { - runtimeTypeInfoConverter.registerTypeInfoSymbol(*this, loc, typeInfoSym); - } - - void registerDispatchTableInfo( - mlir::Location loc, - const Fortran::semantics::DerivedTypeSpec *typeSpec) override final { - dispatchTableConverter.registerTypeSpec(*this, loc, typeSpec); + void registerTypeInfo(mlir::Location loc, + Fortran::lower::SymbolRef typeInfoSym, + const Fortran::semantics::DerivedTypeSpec &typeSpec, + fir::RecordType type) override final { + typeInfoConverter.registerTypeInfo(*this, loc, typeInfoSym, typeSpec, type); } llvm::StringRef @@ -4811,8 +4803,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { Fortran::lower::pft::Evaluation *evalPtr = nullptr; Fortran::lower::SymMap localSymbols; Fortran::parser::CharBlock currentPosition; - RuntimeTypeInfoConverter runtimeTypeInfoConverter; - DispatchTableConverter dispatchTableConverter; + TypeInfoConverter typeInfoConverter; // Stack to manage object deallocation and finalization at construct exits. llvm::SmallVector activeConstructStack; diff --git a/flang/lib/Lower/CallInterface.cpp b/flang/lib/Lower/CallInterface.cpp index 379d9be0e53a3..5299347e561ec 100644 --- a/flang/lib/Lower/CallInterface.cpp +++ b/flang/lib/Lower/CallInterface.cpp @@ -54,10 +54,11 @@ bool Fortran::lower::CallerInterface::hasAlternateReturns() const { return procRef.hasAlternateReturns(); } -std::string Fortran::lower::CallerInterface::getMangledName() const { - const Fortran::evaluate::ProcedureDesignator &proc = procRef.proc(); - // Return the binding label (from BIND(C...)) or the mangled name of the - // symbol. +/// Return the binding label (from BIND(C...)) or the mangled name of the +/// symbol. +static std::string +getProcMangledName(const Fortran::evaluate::ProcedureDesignator &proc, + Fortran::lower::AbstractConverter &converter) { if (const Fortran::semantics::Symbol *symbol = proc.GetSymbol()) return converter.mangleName(symbol->GetUltimate()); assert(proc.GetSpecificIntrinsic() && @@ -65,6 +66,10 @@ std::string Fortran::lower::CallerInterface::getMangledName() const { return proc.GetName(); } +std::string Fortran::lower::CallerInterface::getMangledName() const { + return getProcMangledName(procRef.proc(), converter); +} + const Fortran::semantics::Symbol * Fortran::lower::CallerInterface::getProcedureSymbol() const { return procRef.proc().GetSymbol(); @@ -127,17 +132,25 @@ Fortran::lower::CallerInterface::getIfIndirectCallSymbol() const { return nullptr; } -mlir::Location Fortran::lower::CallerInterface::getCalleeLocation() const { - const Fortran::evaluate::ProcedureDesignator &proc = procRef.proc(); - // FIXME: If the callee is defined in the same file but after the current +static mlir::Location +getProcedureDesignatorLoc(const Fortran::evaluate::ProcedureDesignator &proc, + Fortran::lower::AbstractConverter &converter) { + // Note: If the callee is defined in the same file but after the current // unit we cannot get its location here and the funcOp is created at the // wrong location (i.e, the caller location). + // To prevent this, it is up to the bridge to first declare all functions + // defined in the translation unit before lowering any calls or procedure + // designator references. if (const Fortran::semantics::Symbol *symbol = proc.GetSymbol()) return converter.genLocation(symbol->name()); // Use current location for intrinsics. return converter.getCurrentLocation(); } +mlir::Location Fortran::lower::CallerInterface::getCalleeLocation() const { + return getProcedureDesignatorLoc(procRef.proc(), converter); +} + // Get dummy argument characteristic for a procedure with implicit interface // from the actual argument characteristic. The actual argument may not be a F77 // entity. The attribute must be dropped and the shape, if any, must be made @@ -1341,6 +1354,12 @@ class SignatureBuilder bool isImplicit = forceImplicit || proc.CanBeCalledViaImplicitInterface(); determineInterface(isImplicit, proc); } + SignatureBuilder(const Fortran::evaluate::ProcedureDesignator &procDes, + Fortran::lower::AbstractConverter &c) + : CallInterface{c}, procDesignator{&procDes}, + proc{Fortran::evaluate::characteristics::Procedure::Characterize( + procDes, converter.getFoldingContext()) + .value()} {} /// Does the procedure characteristics being translated have alternate /// returns ? bool hasAlternateReturns() const { @@ -1354,17 +1373,24 @@ class SignatureBuilder /// This is only here to fulfill CRTP dependencies and should not be called. std::string getMangledName() const { - llvm_unreachable("trying to get name from SignatureBuilder"); + if (procDesignator) + return getProcMangledName(*procDesignator, converter); + fir::emitFatalError( + converter.getCurrentLocation(), + "should not query name when only building function type"); } /// This is only here to fulfill CRTP dependencies and should not be called. mlir::Location getCalleeLocation() const { - llvm_unreachable("trying to get callee location from SignatureBuilder"); + if (procDesignator) + return getProcedureDesignatorLoc(*procDesignator, converter); + return converter.getCurrentLocation(); } - /// This is only here to fulfill CRTP dependencies and should not be called. const Fortran::semantics::Symbol *getProcedureSymbol() const { - llvm_unreachable("trying to get callee symbol from SignatureBuilder"); + if (procDesignator) + return procDesignator->GetSymbol(); + return nullptr; }; Fortran::evaluate::characteristics::Procedure characterize() const { @@ -1380,11 +1406,37 @@ class SignatureBuilder return proc; } + /// Set internal procedure attribute on MLIR function. Internal procedure + /// are defined in the current file and will not go through SignatureBuilder. + void setFuncAttrs(mlir::func::FuncOp) const {} + /// This is not the description of an indirect call. static constexpr bool isIndirectCall() { return false; } /// Return the translated signature. - mlir::FunctionType getFunctionType() { return genFunctionType(); } + mlir::FunctionType getFunctionType() { + if (interfaceDetermined) + fir::emitFatalError(converter.getCurrentLocation(), + "SignatureBuilder should only be used once"); + // Most unrestricted intrinsic characteristics have the Elemental attribute + // which triggers CanBeCalledViaImplicitInterface to return false. However, + // using implicit interface rules is just fine here. + bool forceImplicit = + procDesignator && procDesignator->GetSpecificIntrinsic(); + bool isImplicit = forceImplicit || proc.CanBeCalledViaImplicitInterface(); + determineInterface(isImplicit, proc); + interfaceDetermined = true; + return genFunctionType(); + } + + mlir::func::FuncOp getOrCreateFuncOp() { + if (interfaceDetermined) + fir::emitFatalError(converter.getCurrentLocation(), + "SignatureBuilder should only be used once"); + declare(); + interfaceDetermined = true; + return getFuncOp(); + } // Copy of base implementation. static constexpr bool hasHostAssociated() { return false; } @@ -1393,47 +1445,30 @@ class SignatureBuilder } private: - const Fortran::evaluate::characteristics::Procedure &proc; + const Fortran::evaluate::ProcedureDesignator *procDesignator = nullptr; + Fortran::evaluate::characteristics::Procedure proc; + bool interfaceDetermined = false; }; mlir::FunctionType Fortran::lower::translateSignature( const Fortran::evaluate::ProcedureDesignator &proc, Fortran::lower::AbstractConverter &converter) { - std::optional characteristics = - Fortran::evaluate::characteristics::Procedure::Characterize( - proc, converter.getFoldingContext()); - // Most unrestricted intrinsic characteristic has the Elemental attribute - // which triggers CanBeCalledViaImplicitInterface to return false. However, - // using implicit interface rules is just fine here. - bool forceImplicit = proc.GetSpecificIntrinsic(); - return SignatureBuilder{characteristics.value(), converter, forceImplicit} - .getFunctionType(); + return SignatureBuilder{proc, converter}.getFunctionType(); } mlir::func::FuncOp Fortran::lower::getOrDeclareFunction( - llvm::StringRef name, const Fortran::evaluate::ProcedureDesignator &proc, + const Fortran::evaluate::ProcedureDesignator &proc, Fortran::lower::AbstractConverter &converter) { mlir::ModuleOp module = converter.getModuleOp(); + std::string name = getProcMangledName(proc, converter); mlir::func::FuncOp func = fir::FirOpBuilder::getNamedFunction(module, name); if (func) return func; - const Fortran::semantics::Symbol *symbol = proc.GetSymbol(); - assert(symbol && "non user function in getOrDeclareFunction"); // getOrDeclareFunction is only used for functions not defined in the current // program unit, so use the location of the procedure designator symbol, which // is the first occurrence of the procedure in the program unit. - mlir::Location loc = converter.genLocation(symbol->name()); - std::optional characteristics = - Fortran::evaluate::characteristics::Procedure::Characterize( - proc, converter.getFoldingContext()); - mlir::FunctionType ty = SignatureBuilder{characteristics.value(), converter, - /*forceImplicit=*/false} - .getFunctionType(); - mlir::func::FuncOp newFunc = - fir::FirOpBuilder::createFunction(loc, module, name, ty); - addSymbolAttribute(newFunc, *symbol, converter.getMLIRContext()); - return newFunc; + return SignatureBuilder{proc, converter}.getOrCreateFuncOp(); } // Is it required to pass a dummy procedure with \p characteristics as a tuple diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp index 169ef71d005cc..90025ba9c687a 100644 --- a/flang/lib/Lower/ConvertCall.cpp +++ b/flang/lib/Lower/ConvertCall.cpp @@ -29,6 +29,7 @@ #include "flang/Optimizer/Builder/Todo.h" #include "flang/Optimizer/Dialect/FIROpsSupport.h" #include "flang/Optimizer/HLFIR/HLFIROps.h" +#include "mlir/IR/IRMapping.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include @@ -1619,37 +1620,33 @@ class ElementalCallBuilder { for (unsigned i = 0; i < numArgs; ++i) { auto &preparedActual = loweredActuals[i]; if (preparedActual) { - hlfir::Entity actual = preparedActual->getOriginalActual(); // Elemental procedure dummy arguments cannot be pointer/allocatables // (C15100), so it is safe to dereference any pointer or allocatable // actual argument now instead of doing this inside the elemental // region. - actual = hlfir::derefPointersAndAllocatables(loc, builder, actual); + preparedActual->derefPointersAndAllocatables(loc, builder); // Better to load scalars outside of the loop when possible. if (!preparedActual->handleDynamicOptional() && impl().canLoadActualArgumentBeforeLoop(i)) - actual = hlfir::loadTrivialScalar(loc, builder, actual); + preparedActual->loadTrivialScalar(loc, builder); // TODO: merge shape instead of using the first one. - if (!shape && actual.isArray()) { + if (!shape && preparedActual->isArray()) { if (preparedActual->handleDynamicOptional()) optionalWithShape = &*preparedActual; else - shape = hlfir::genShape(loc, builder, actual); + shape = preparedActual->genShape(loc, builder); } // 15.8.3 p1. Elemental procedure with intent(out)/intent(inout) // arguments must be called in element order. if (impl().argMayBeModifiedByCall(i)) mustBeOrdered = true; - // Propagates pointer dereferences and scalar loads. - preparedActual->setOriginalActual(actual); } } if (!shape && optionalWithShape) { // If all array operands appear in optional positions, then none of them // is allowed to be absent as per 15.5.2.12 point 3. (6). Just pick the // first operand. - shape = - hlfir::genShape(loc, builder, optionalWithShape->getOriginalActual()); + shape = optionalWithShape->genShape(loc, builder); // TODO: There is an opportunity to add a runtime check here that // this array is present as required. Also, the optionality of all actual // could be checked and reset given the Fortran requirement. @@ -1663,16 +1660,10 @@ class ElementalCallBuilder { // intent(inout) arguments. Note that the scalar arguments are handled // above. if (mustBeOrdered) { - for (unsigned i = 0; i < numArgs; ++i) { - auto &preparedActual = loweredActuals[i]; + for (auto &preparedActual : loweredActuals) { if (preparedActual) { - hlfir::Entity actual = preparedActual->getOriginalActual(); - if (!actual.isVariable() && actual.isArray()) { - mlir::Type storageType = actual.getType(); - hlfir::AssociateOp associate = hlfir::genAssociateExpr( - loc, builder, actual, storageType, "adapt.impure_arg_eval"); - preparedActual->setOriginalActual(hlfir::Entity{associate}); - + if (hlfir::AssociateOp associate = + preparedActual->associateIfArrayExpr(loc, builder)) { fir::FirOpBuilder *bldr = &builder; callContext.stmtCtx.attachCleanup( [=]() { bldr->create(loc, associate); }); @@ -1852,9 +1843,8 @@ class ElementalIntrinsicCallBuilder if (intrinsic) if (intrinsic->name == "adjustr" || intrinsic->name == "adjustl" || intrinsic->name == "merge") - return hlfir::genCharLength( - callContext.loc, callContext.getBuilder(), - loweredActuals[0].value().getOriginalActual()); + return loweredActuals[0].value().genCharLength( + callContext.loc, callContext.getBuilder()); // Character MIN/MAX is the min/max of the arguments length that are // present. TODO(callContext.loc, @@ -1874,7 +1864,7 @@ class ElementalIntrinsicCallBuilder // the same declared and dynamic types. So any of them can be used // for the mold. assert(!loweredActuals.empty()); - return loweredActuals.front()->getOriginalActual(); + return loweredActuals.front()->getPolymorphicMold(callContext.loc); } return {}; @@ -2137,7 +2127,7 @@ genProcedureRef(CallContext &callContext) { Fortran::lower::CallerInterface caller(callContext.procRef, callContext.converter); mlir::FunctionType callSiteType = caller.genFunctionType(); - + const bool isElemental = callContext.isElementalProcWithArrayArgs(); Fortran::lower::PreparedActualArguments loweredActuals; // Lower the actual arguments for (const Fortran::lower::CallInterface< @@ -2162,6 +2152,21 @@ genProcedureRef(CallContext &callContext) { } } + if (isElemental && !arg.hasValueAttribute() && + Fortran::evaluate::IsVariable(*expr) && + Fortran::evaluate::HasVectorSubscript(*expr)) { + // Vector subscripted arguments are copied in calls, except in elemental + // calls without VALUE attribute where Fortran 2018 15.5.2.4 point 21 + // does not apply and the address of each element must be passed. + hlfir::ElementalAddrOp elementalAddr = + Fortran::lower::convertVectorSubscriptedExprToElementalAddr( + loc, callContext.converter, *expr, callContext.symMap, + callContext.stmtCtx); + loweredActuals.emplace_back( + Fortran::lower::PreparedActualArgument{elementalAddr}); + continue; + } + auto loweredActual = Fortran::lower::convertExprToHLFIR( loc, callContext.converter, *expr, callContext.symMap, callContext.stmtCtx); @@ -2178,7 +2183,7 @@ genProcedureRef(CallContext &callContext) { // Optional dummy argument for which there is no actual argument. loweredActuals.emplace_back(std::nullopt); } - if (callContext.isElementalProcWithArrayArgs()) { + if (isElemental) { bool isImpure = false; if (const Fortran::semantics::Symbol *procSym = callContext.procRef.proc().GetSymbol()) @@ -2189,6 +2194,27 @@ genProcedureRef(CallContext &callContext) { return genUserCall(loweredActuals, caller, callSiteType, callContext); } +hlfir::Entity Fortran::lower::PreparedActualArgument::getActual( + mlir::Location loc, fir::FirOpBuilder &builder) const { + if (auto *actualEntity = std::get_if(&actual)) { + if (oneBasedElementalIndices) + return hlfir::getElementAt(loc, builder, *actualEntity, + *oneBasedElementalIndices); + return *actualEntity; + } + assert(oneBasedElementalIndices && "expect elemental context"); + hlfir::ElementalAddrOp elementalAddr = + std::get(actual); + mlir::IRMapping mapper; + auto alwaysFalse = [](hlfir::ElementalOp) -> bool { return false; }; + mlir::Value addr = hlfir::inlineElementalOp( + loc, builder, elementalAddr, *oneBasedElementalIndices, mapper, + /*mustRecursivelyInline=*/alwaysFalse); + assert(elementalAddr.getCleanup().empty() && "no clean-up expected"); + elementalAddr.erase(); + return hlfir::Entity{addr}; +} + bool Fortran::lower::isIntrinsicModuleProcRef( const Fortran::evaluate::ProcedureRef &procRef) { const Fortran::semantics::Symbol *symbol = procRef.proc().GetSymbol(); diff --git a/flang/lib/Lower/ConvertConstant.cpp b/flang/lib/Lower/ConvertConstant.cpp index 940e70da511c2..6e7a60e42abfe 100644 --- a/flang/lib/Lower/ConvertConstant.cpp +++ b/flang/lib/Lower/ConvertConstant.cpp @@ -388,37 +388,38 @@ static mlir::Value genInlinedStructureCtorLitImpl( // Special handling for scalar c_ptr/c_funptr constants. The array constant // must fall through to genConstantValue() below. - if (Fortran::semantics::IsBuiltinCPtr(sym) && sym->Rank() == 0) { - // Builtin c_ptr and c_funptr have special handling because initial - // values are handled for them as an extension. + if (Fortran::semantics::IsBuiltinCPtr(sym) && sym->Rank() == 0 && + (Fortran::evaluate::GetLastSymbol(expr.value()) || + Fortran::evaluate::IsNullPointer(expr.value()))) { + // Builtin c_ptr and c_funptr have special handling because designators + // and NULL() are handled as initial values for them as an extension + // (otherwise only c_ptr_null/c_funptr_null are allowed and these are + // replaced by structure constructors by semantics, so GetLastSymbol + // returns nothing). + + // The Ev::Expr is an initializer that is a pointer target (e.g., 'x' or + // NULL()) that must be inserted into an intermediate cptr record value's + // address field, which ought to be an intptr_t on the target. mlir::Value addr = fir::getBase(Fortran::lower::genExtAddrInInitializer( converter, loc, expr.value())); - if (addr.getType() == componentTy) { - // Do nothing. The Ev::Expr was returned as a value that can be - // inserted directly to the component without an intermediary. - } else { - // The Ev::Expr returned is an initializer that is a pointer (e.g., - // null) that must be inserted into an intermediate cptr record - // value's address field, which ought to be an intptr_t on the target. - if (addr.getType().isa()) - addr = builder.create(loc, addr); - assert((fir::isa_ref_type(addr.getType()) || - addr.getType().isa()) && - "expect reference type for address field"); - assert(fir::isa_derived(componentTy) && - "expect C_PTR, C_FUNPTR to be a record"); - auto cPtrRecTy = componentTy.cast(); - llvm::StringRef addrFieldName = Fortran::lower::builtin::cptrFieldName; - mlir::Type addrFieldTy = cPtrRecTy.getType(addrFieldName); - auto addrField = builder.create( - loc, fieldTy, addrFieldName, componentTy, - /*typeParams=*/mlir::ValueRange{}); - mlir::Value castAddr = builder.createConvert(loc, addrFieldTy, addr); - auto undef = builder.create(loc, componentTy); - addr = builder.create( - loc, componentTy, undef, castAddr, - builder.getArrayAttr(addrField.getAttributes())); - } + if (addr.getType().isa()) + addr = builder.create(loc, addr); + assert((fir::isa_ref_type(addr.getType()) || + addr.getType().isa()) && + "expect reference type for address field"); + assert(fir::isa_derived(componentTy) && + "expect C_PTR, C_FUNPTR to be a record"); + auto cPtrRecTy = componentTy.cast(); + llvm::StringRef addrFieldName = Fortran::lower::builtin::cptrFieldName; + mlir::Type addrFieldTy = cPtrRecTy.getType(addrFieldName); + auto addrField = builder.create( + loc, fieldTy, addrFieldName, componentTy, + /*typeParams=*/mlir::ValueRange{}); + mlir::Value castAddr = builder.createConvert(loc, addrFieldTy, addr); + auto undef = builder.create(loc, componentTy); + addr = builder.create( + loc, componentTy, undef, castAddr, + builder.getArrayAttr(addrField.getAttributes())); res = builder.create( loc, recTy, res, addr, builder.getArrayAttr(field.getAttributes())); continue; diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp index bc98fdd917d41..44c9eb1e9123b 100644 --- a/flang/lib/Lower/ConvertExprToHLFIR.cpp +++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp @@ -1414,7 +1414,6 @@ struct UnaryOp< hlfir::Entity lhs) { if constexpr (TC1 == Fortran::common::TypeCategory::Character && TC2 == TC1) { - // TODO(loc, "character conversion in HLFIR"); auto kindMap = builder.getKindMap(); mlir::Type fromTy = lhs.getFortranElementType(); mlir::Value origBufferSize = genCharLength(loc, builder, lhs); @@ -1435,8 +1434,12 @@ struct UnaryOp< // allocate space on the stack for toBuffer auto dest = builder.create(loc, toTy, mlir::ValueRange{bufferSize}); - builder.create(loc, lhs.getFirBase(), origBufferSize, - dest); + auto src = hlfir::convertToAddress(loc, builder, lhs, + lhs.getFortranElementType()); + builder.create(loc, src.first.getCharBox()->getAddr(), + origBufferSize, dest); + if (src.second.has_value()) + src.second.value()(); return hlfir::EntityWithAttributes{builder.create( loc, dest, "ctor.temp", /*shape=*/nullptr, diff --git a/flang/lib/Lower/ConvertProcedureDesignator.cpp b/flang/lib/Lower/ConvertProcedureDesignator.cpp index aa5a7fe0ce5c5..20ade1a04049f 100644 --- a/flang/lib/Lower/ConvertProcedureDesignator.cpp +++ b/flang/lib/Lower/ConvertProcedureDesignator.cpp @@ -62,11 +62,11 @@ fir::ExtendedValue Fortran::lower::convertProcedureDesignator( std::tie(funcPtr, funcPtrResultLength) = fir::factory::extractCharacterProcedureTuple(builder, loc, funcPtr); } else { - std::string name = converter.mangleName(*symbol); mlir::func::FuncOp func = - Fortran::lower::getOrDeclareFunction(name, proc, converter); - funcPtr = builder.create(loc, func.getFunctionType(), - builder.getSymbolRefAttr(name)); + Fortran::lower::getOrDeclareFunction(proc, converter); + mlir::SymbolRefAttr nameAttr = builder.getSymbolRefAttr(func.getSymName()); + funcPtr = + builder.create(loc, func.getFunctionType(), nameAttr); } if (Fortran::lower::mustPassLengthWithDummyProcedure(proc, converter)) { // The result length, if available here, must be propagated along the diff --git a/flang/lib/Lower/ConvertType.cpp b/flang/lib/Lower/ConvertType.cpp index efaeba29b762a..22b83efe8678b 100644 --- a/flang/lib/Lower/ConvertType.cpp +++ b/flang/lib/Lower/ConvertType.cpp @@ -426,14 +426,12 @@ struct TypeBuilderImpl { } LLVM_DEBUG(llvm::dbgs() << "derived type: " << rec << '\n'); - converter.registerDispatchTableInfo(loc, &tySpec); - // Generate the type descriptor object if any if (const Fortran::semantics::Scope *derivedScope = tySpec.scope() ? tySpec.scope() : tySpec.typeSymbol().scope()) if (const Fortran::semantics::Symbol *typeInfoSym = derivedScope->runtimeDerivedTypeDescription()) - converter.registerRuntimeTypeInfo(loc, *typeInfoSym); + converter.registerTypeInfo(loc, *typeInfoSym, tySpec, rec); return rec; } diff --git a/flang/lib/Lower/DirectivesCommon.h b/flang/lib/Lower/DirectivesCommon.h index 906bf355e9ea7..535ec1c03b54d 100644 --- a/flang/lib/Lower/DirectivesCommon.h +++ b/flang/lib/Lower/DirectivesCommon.h @@ -800,15 +800,14 @@ genBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc, } } if (!ubound) { - mlir::Value ext = - fir::factory::readExtent(builder, loc, dataExv, dimension); + extent = fir::factory::readExtent(builder, loc, dataExv, dimension); if (defaultLb) { // ub = extent - 1 - ubound = builder.create(loc, ext, one); + ubound = builder.create(loc, extent, one); } else { // ub = baseLb + extent - 1 mlir::Value lbExt = - builder.create(loc, ext, baseLb); + builder.create(loc, extent, baseLb); ubound = builder.create(loc, lbExt, one); } } diff --git a/flang/lib/Lower/HlfirIntrinsics.cpp b/flang/lib/Lower/HlfirIntrinsics.cpp index 20e570044e8d4..9f764b6142522 100644 --- a/flang/lib/Lower/HlfirIntrinsics.cpp +++ b/flang/lib/Lower/HlfirIntrinsics.cpp @@ -152,7 +152,7 @@ mlir::Value HlfirTransformationalIntrinsic::loadBoxAddress( if (!arg) return mlir::Value{}; - hlfir::Entity actual = arg->getOriginalActual(); + hlfir::Entity actual = arg->getActual(loc, builder); if (!arg->handleDynamicOptional()) { if (actual.isMutableBox()) { @@ -193,7 +193,7 @@ llvm::SmallVector HlfirTransformationalIntrinsic::getOperandVector( operands.emplace_back(); continue; } - hlfir::Entity actual = arg->getOriginalActual(); + hlfir::Entity actual = arg->getActual(loc, builder); mlir::Value valArg; if (!argLowering) { diff --git a/flang/lib/Lower/IO.cpp b/flang/lib/Lower/IO.cpp index 48f2baa2e4f4e..94135bb570ffb 100644 --- a/flang/lib/Lower/IO.cpp +++ b/flang/lib/Lower/IO.cpp @@ -362,17 +362,14 @@ getNonTbpDefinedIoTableAddr(Fortran::lower::AbstractConverter &converter, Fortran::evaluate::ProcedureDesignator{*procSym}}, stmtCtx)))); } else { - std::string procName = converter.mangleName(*procSym); - mlir::func::FuncOp procDef = builder.getNamedFunction(procName); - if (!procDef) - procDef = Fortran::lower::getOrDeclareFunction( - procName, Fortran::evaluate::ProcedureDesignator{*procSym}, - converter); - insert( - builder.createConvert(loc, refTy, - builder.create( - loc, procDef.getFunctionType(), - builder.getSymbolRefAttr(procName)))); + mlir::func::FuncOp procDef = Fortran::lower::getOrDeclareFunction( + Fortran::evaluate::ProcedureDesignator{*procSym}, converter); + mlir::SymbolRefAttr nameAttr = + builder.getSymbolRefAttr(procDef.getSymName()); + insert(builder.createConvert( + loc, refTy, + builder.create(loc, procDef.getFunctionType(), + nameAttr))); } } else { insert(builder.createNullConstant(loc, refTy)); diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp index 84ce4cde94200..9a8e4da0d61ef 100644 --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -356,6 +356,19 @@ fir::ShapeOp genShapeOp(mlir::OpBuilder &builder, fir::SequenceType seqTy, return builder.create(loc, extents); } +/// Return the nested sequence type if any. +static mlir::Type extractSequenceType(mlir::Type ty) { + if (mlir::isa(ty)) + return ty; + if (auto boxTy = mlir::dyn_cast(ty)) + return extractSequenceType(boxTy.getEleTy()); + if (auto heapTy = mlir::dyn_cast(ty)) + return extractSequenceType(heapTy.getEleTy()); + if (auto ptrTy = mlir::dyn_cast(ty)) + return extractSequenceType(ptrTy.getEleTy()); + return mlir::Type{}; +} + template static void genPrivateLikeInitRegion(mlir::OpBuilder &builder, RecipeOp recipe, mlir::Type ty, mlir::Location loc) { @@ -369,19 +382,30 @@ static void genPrivateLikeInitRegion(mlir::OpBuilder &builder, RecipeOp recipe, retVal = declareOp.getBase(); } else if (auto seqTy = mlir::dyn_cast_or_null( refTy.getEleTy())) { - if (seqTy.hasDynamicExtents()) - TODO(loc, "private recipe of array with dynamic extents"); if (fir::isa_trivial(seqTy.getEleTy())) { - auto alloca = builder.create(loc, seqTy); - auto shapeOp = genShapeOp(builder, seqTy, loc); + mlir::Value shape; + llvm::SmallVector extents; + if (seqTy.hasDynamicExtents()) { + // Extents are passed as block arguments. First argument is the + // original value. + for (unsigned i = 1; i < recipe.getInitRegion().getArguments().size(); + ++i) + extents.push_back(recipe.getInitRegion().getArgument(i)); + shape = builder.create(loc, extents); + } else { + shape = genShapeOp(builder, seqTy, loc); + } + auto alloca = builder.create( + loc, seqTy, /*typeparams=*/mlir::ValueRange{}, extents); auto declareOp = builder.create( - loc, alloca, accPrivateInitName, shapeOp, + loc, alloca, accPrivateInitName, shape, llvm::ArrayRef{}, fir::FortranVariableFlagsAttr{}); retVal = declareOp.getBase(); } } } else if (auto boxTy = mlir::dyn_cast_or_null(ty)) { - if (!mlir::isa(boxTy.getEleTy())) + mlir::Type innerTy = extractSequenceType(boxTy); + if (!innerTy) TODO(loc, "Unsupported boxed type in OpenACC privatization"); fir::FirOpBuilder firBuilder{builder, recipe.getOperation()}; hlfir::Entity source = hlfir::Entity{retVal}; @@ -404,8 +428,22 @@ Fortran::lower::createOrGetPrivateRecipe(mlir::OpBuilder &builder, mlir::OpBuilder modBuilder(mod.getBodyRegion()); auto recipe = modBuilder.create(loc, recipeName, ty); + llvm::SmallVector argsTy{ty}; + llvm::SmallVector argsLoc{loc}; + if (auto refTy = mlir::dyn_cast_or_null(ty)) { + if (auto seqTy = + mlir::dyn_cast_or_null(refTy.getEleTy())) { + if (seqTy.hasDynamicExtents()) { + mlir::Type idxTy = builder.getIndexType(); + for (unsigned i = 0; i < seqTy.getDimension(); ++i) { + argsTy.push_back(idxTy); + argsLoc.push_back(loc); + } + } + } + } builder.createBlock(&recipe.getInitRegion(), recipe.getInitRegion().end(), - {ty}, {loc}); + argsTy, argsLoc); builder.setInsertionPointToEnd(&recipe.getInitRegion().back()); genPrivateLikeInitRegion(builder, recipe, ty, loc); @@ -540,6 +578,29 @@ mlir::Type getTypeFromBounds(llvm::SmallVector &bounds, return ty; } +/// Check if the DataBoundsOp is a constant bound (lb and ub are constants or +/// extent is a constant). +bool isConstantBound(mlir::acc::DataBoundsOp &op) { + if (op.getLowerbound() && fir::getIntIfConstant(op.getLowerbound()) && + op.getUpperbound() && fir::getIntIfConstant(op.getUpperbound())) + return true; + if (op.getExtent() && fir::getIntIfConstant(op.getExtent())) + return true; + return false; +} + +/// Return true iff all the bounds are expressed with constant values. +bool areAllBoundConstant(llvm::SmallVector &bounds) { + for (auto bound : bounds) { + auto dataBound = + mlir::dyn_cast(bound.getDefiningOp()); + assert(dataBound && "Must be DataBoundOp operation"); + if (!isConstantBound(dataBound)) + return false; + } + return true; +} + template static void genPrivatizations(const Fortran::parser::AccObjectList &objectList, @@ -669,29 +730,6 @@ static R getReductionInitValue(mlir::acc::ReductionOperator op, mlir::Type ty) { llvm_unreachable("OpenACC reduction unsupported type"); } -/// Check if the DataBoundsOp is a constant bound (lb and ub are constants or -/// extent is a constant). -bool isConstantBound(mlir::acc::DataBoundsOp &op) { - if (op.getLowerbound() && fir::getIntIfConstant(op.getLowerbound()) && - op.getUpperbound() && fir::getIntIfConstant(op.getUpperbound())) - return true; - if (op.getExtent() && fir::getIntIfConstant(op.getExtent())) - return true; - return false; -} - -/// Return true iff all the bounds are expressed with constant values. -bool areAllBoundConstant(llvm::SmallVector &bounds) { - for (auto bound : bounds) { - auto dataBound = - mlir::dyn_cast(bound.getDefiningOp()); - assert(dataBound && "Must be DataBoundOp operation"); - if (!isConstantBound(dataBound)) - return false; - } - return true; -} - /// Return a constant with the initial value for the reduction operator and /// type combination. static mlir::Value getReductionInitValue(fir::FirOpBuilder &builder, @@ -742,6 +780,12 @@ static mlir::Value getReductionInitValue(fir::FirOpBuilder &builder, if (auto boxTy = mlir::dyn_cast(ty)) return getReductionInitValue(builder, loc, boxTy.getEleTy(), op); + if (auto heapTy = mlir::dyn_cast(ty)) + return getReductionInitValue(builder, loc, heapTy.getEleTy(), op); + + if (auto ptrTy = mlir::dyn_cast(ty)) + return getReductionInitValue(builder, loc, ptrTy.getEleTy(), op); + llvm::report_fatal_error("Unsupported OpenACC reduction type"); } @@ -788,7 +832,8 @@ static mlir::Value genReductionInitRegion(fir::FirOpBuilder &builder, return declareOp.getBase(); } } else if (auto boxTy = mlir::dyn_cast_or_null(ty)) { - if (!mlir::isa(boxTy.getEleTy())) + mlir::Type innerTy = extractSequenceType(boxTy); + if (!mlir::isa(innerTy)) TODO(loc, "Unsupported boxed type for reduction"); // Create the private copy from the initial fir.box. hlfir::Entity source = hlfir::Entity{builder.getBlock()->getArgument(0)}; @@ -993,8 +1038,9 @@ static void genCombiner(fir::FirOpBuilder &builder, mlir::Location loc, builder.setInsertionPointAfter(loops[0]); } else if (auto boxTy = mlir::dyn_cast(ty)) { llvm::SmallVector tripletArgs; + mlir::Type innerTy = extractSequenceType(boxTy); fir::SequenceType seqTy = - mlir::dyn_cast_or_null(boxTy.getEleTy()); + mlir::dyn_cast_or_null(innerTy); if (!seqTy) TODO(loc, "Unsupported boxed type in OpenACC reduction"); @@ -1110,6 +1156,19 @@ mlir::acc::ReductionRecipeOp Fortran::lower::createOrGetReductionRecipe( return recipe; } +static bool isSupportedReductionType(mlir::Type ty) { + ty = fir::unwrapRefType(ty); + if (auto boxTy = mlir::dyn_cast(ty)) + return isSupportedReductionType(boxTy.getEleTy()); + if (auto seqTy = mlir::dyn_cast(ty)) + return isSupportedReductionType(seqTy.getEleTy()); + if (auto heapTy = mlir::dyn_cast(ty)) + return isSupportedReductionType(heapTy.getEleTy()); + if (auto ptrTy = mlir::dyn_cast(ty)) + return isSupportedReductionType(ptrTy.getEleTy()); + return fir::isa_trivial(ty); +} + static void genReductions(const Fortran::parser::AccObjectListWithReduction &objectList, Fortran::lower::AbstractConverter &converter, @@ -1135,10 +1194,7 @@ genReductions(const Fortran::parser::AccObjectListWithReduction &objectList, if (auto seqTy = mlir::dyn_cast(reductionTy)) reductionTy = seqTy.getEleTy(); - if (!fir::isa_trivial(reductionTy) && - ((fir::isAllocatableType(reductionTy) || - fir::isPointerType(reductionTy)) && - !bounds.empty())) + if (!isSupportedReductionType(reductionTy)) TODO(operandLocation, "reduction with unsupported type"); auto op = createDataEntryOp( @@ -1146,13 +1202,16 @@ genReductions(const Fortran::parser::AccObjectListWithReduction &objectList, /*structured=*/true, /*implicit=*/false, mlir::acc::DataClause::acc_reduction, baseAddr.getType()); mlir::Type ty = op.getAccPtr().getType(); + if (!areAllBoundConstant(bounds) || + fir::isAssumedShape(baseAddr.getType()) || + fir::isAllocatableOrPointerArray(baseAddr.getType())) + ty = baseAddr.getType(); std::string suffix = areAllBoundConstant(bounds) ? getBoundsString(bounds) : ""; std::string recipeName = fir::getTypeAsString( ty, converter.getKindMap(), ("reduction_" + stringifyReductionOperator(mlirOp)).str() + suffix); - if (!areAllBoundConstant(bounds) || fir::isAssumedShape(baseAddr.getType())) - ty = baseAddr.getType(); + mlir::acc::ReductionRecipeOp recipe = Fortran::lower::createOrGetReductionRecipe( builder, recipeName, operandLocation, ty, mlirOp, bounds); @@ -2977,20 +3036,17 @@ genACC(Fortran::lower::AbstractConverter &converter, funcName = funcOp.getName(); } - mlir::OpBuilder modBuilder(mod.getBodyRegion()); - std::stringstream routineOpName; - routineOpName << accRoutinePrefix.str() << routineCounter++; - auto routineOp = modBuilder.create( - loc, routineOpName.str(), funcName, mlir::StringAttr{}, mlir::UnitAttr{}, - mlir::UnitAttr{}, mlir::UnitAttr{}, mlir::UnitAttr{}, mlir::UnitAttr{}, - mlir::UnitAttr{}, mlir::IntegerAttr{}); + bool hasSeq = false, hasGang = false, hasWorker = false, hasVector = false, + hasNohost = false; + std::optional bindName = std::nullopt; + std::optional gangDim = std::nullopt; for (const Fortran::parser::AccClause &clause : clauses.v) { if (std::get_if(&clause.u)) { - routineOp.setSeqAttr(builder.getUnitAttr()); + hasSeq = true; } else if (const auto *gangClause = std::get_if(&clause.u)) { - routineOp.setGangAttr(builder.getUnitAttr()); + hasGang = true; if (gangClause->v) { const Fortran::parser::AccGangArgList &x = *gangClause->v; for (const Fortran::parser::AccGangArg &gangArg : x.v) { @@ -3001,36 +3057,60 @@ genACC(Fortran::lower::AbstractConverter &converter, if (!dimValue) mlir::emitError(loc, "dim value must be a constant positive integer"); - routineOp.setGangDimAttr( - builder.getIntegerAttr(builder.getIntegerType(32), *dimValue)); + gangDim = *dimValue; } } } } else if (std::get_if(&clause.u)) { - routineOp.setVectorAttr(builder.getUnitAttr()); + hasVector = true; } else if (std::get_if(&clause.u)) { - routineOp.setWorkerAttr(builder.getUnitAttr()); + hasWorker = true; } else if (std::get_if(&clause.u)) { - routineOp.setNohostAttr(builder.getUnitAttr()); + hasNohost = true; } else if (const auto *bindClause = std::get_if(&clause.u)) { if (const auto *name = std::get_if(&bindClause->v.u)) { - routineOp.setBindName( - builder.getStringAttr(converter.mangleName(*name->symbol))); + bindName = converter.mangleName(*name->symbol); } else if (const auto charExpr = std::get_if( &bindClause->v.u)) { - const std::optional bindName = + const std::optional name = Fortran::semantics::GetConstExpr(semanticsContext, *charExpr); - if (!bindName) - routineOp.emitError("Could not retrieve the bind name"); - routineOp.setBindName(builder.getStringAttr(*bindName)); + if (!name) + mlir::emitError(loc, "Could not retrieve the bind name"); + bindName = *name; } } } + mlir::OpBuilder modBuilder(mod.getBodyRegion()); + std::stringstream routineOpName; + routineOpName << accRoutinePrefix.str() << routineCounter++; + + for (auto routineOp : mod.getOps()) { + if (routineOp.getFuncName().str().compare(funcName) == 0) { + // If the routine is already specified with the same clauses, just skip + // the operation creation. + if (routineOp.getBindName() == bindName && + routineOp.getGang() == hasGang && + routineOp.getWorker() == hasWorker && + routineOp.getVector() == hasVector && routineOp.getSeq() == hasSeq && + routineOp.getNohost() == hasNohost && + routineOp.getGangDim() == gangDim) + return; + mlir::emitError(loc, "Routine already specified with different clauses"); + } + } + + modBuilder.create( + loc, routineOpName.str(), funcName, + bindName ? builder.getStringAttr(*bindName) : mlir::StringAttr{}, hasGang, + hasWorker, hasVector, hasSeq, hasNohost, /*implicit=*/false, + gangDim ? builder.getIntegerAttr(builder.getIntegerType(32), *gangDim) + : mlir::IntegerAttr{}); + if (funcOp) attachRoutineInfo(funcOp, builder.getSymbolRefAttr(routineOpName.str())); else diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp index 4dde918af7fa6..9010553e70f0e 100644 --- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -18,6 +18,7 @@ #include "flang/Optimizer/Dialect/FIROpsSupport.h" #include "flang/Optimizer/Support/FatalError.h" #include "flang/Optimizer/Support/InternalNames.h" +#include "mlir/Dialect/OpenACC/OpenACC.h" #include "mlir/Dialect/OpenMP/OpenMPDialect.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringExtras.h" @@ -200,9 +201,17 @@ mlir::Value fir::FirOpBuilder::allocateLocal( /// Get the block for adding Allocas. mlir::Block *fir::FirOpBuilder::getAllocaBlock() { - auto iface = - getRegion().getParentOfType(); - return iface ? iface.getAllocaBlock() : getEntryBlock(); + if (auto ompOutlineableIface = + getRegion() + .getParentOfType()) { + return ompOutlineableIface.getAllocaBlock(); + } + if (auto accRecipeIface = + getRegion().getParentOfType()) { + return accRecipeIface.getAllocaBlock(getRegion()); + } + + return getEntryBlock(); } mlir::Value fir::FirOpBuilder::createTemporaryAlloc( @@ -299,18 +308,6 @@ fir::GlobalOp fir::FirOpBuilder::createGlobal( return glob; } -fir::DispatchTableOp fir::FirOpBuilder::createDispatchTableOp( - mlir::Location loc, llvm::StringRef name, llvm::StringRef parentName) { - auto module = getModule(); - auto insertPt = saveInsertionPoint(); - if (auto dt = module.lookupSymbol(name)) - return dt; - setInsertionPoint(module.getBody(), module.getBody()->end()); - auto dt = create(loc, name, mlir::Type{}, parentName); - restoreInsertionPoint(insertPt); - return dt; -} - mlir::Value fir::FirOpBuilder::convertWithSemantics(mlir::Location loc, mlir::Type toTy, mlir::Value val, @@ -1273,6 +1270,15 @@ static bool recordTypeCanBeMemCopied(fir::RecordType recordType) { return true; } +static bool mayHaveFinalizer(fir::RecordType recordType, + fir::FirOpBuilder &builder) { + if (auto typeInfo = builder.getModule().lookupSymbol( + recordType.getName())) + return !typeInfo.getNoFinal(); + // No info, be pessimistic. + return true; +} + void fir::factory::genRecordAssignment(fir::FirOpBuilder &builder, mlir::Location loc, const fir::ExtendedValue &lhs, @@ -1289,7 +1295,8 @@ void fir::factory::genRecordAssignment(fir::FirOpBuilder &builder, fir::getBase(rhs).getType().isa(); auto recTy = baseTy.dyn_cast(); assert(recTy && "must be a record type"); - if (hasBoxOperands || !recordTypeCanBeMemCopied(recTy)) { + if ((needFinalization && mayHaveFinalizer(recTy, builder)) || + hasBoxOperands || !recordTypeCanBeMemCopied(recTy)) { auto to = fir::getBase(builder.createBox(loc, lhs)); auto from = fir::getBase(builder.createBox(loc, rhs)); // The runtime entry point may modify the LHS descriptor if it is @@ -1306,12 +1313,6 @@ void fir::factory::genRecordAssignment(fir::FirOpBuilder &builder, return; } - // Finalize LHS on intrinsic assignment. - if (needFinalization) { - mlir::Value box = builder.createBox(loc, lhs); - fir::runtime::genDerivedTypeDestroy(builder, loc, box); - } - // Otherwise, the derived type has compile time constant size and for which // the component by component assignment can be replaced by a memory copy. // Since we do not know the size of the derived type in lowering, do a diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index d1b7f3de93b46..5bf6b87615c68 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -1026,14 +1026,15 @@ struct ConvertOpConversion : public FIROpConversion { } }; -/// `fir.disptach_table` operation has no specific CodeGen. The operation is -/// only used to carry information during FIR to FIR passes. -struct DispatchTableOpConversion - : public FIROpConversion { +/// `fir.type_info` operation has no specific CodeGen. The operation is +/// only used to carry information during FIR to FIR passes. It may be used +/// in the future to generate the runtime type info data structures instead +/// of generating them in lowering. +struct TypeInfoOpConversion : public FIROpConversion { using FIROpConversion::FIROpConversion; mlir::LogicalResult - matchAndRewrite(fir::DispatchTableOp op, OpAdaptor, + matchAndRewrite(fir::TypeInfoOp op, OpAdaptor, mlir::ConversionPatternRewriter &rewriter) const override { rewriter.eraseOp(op); return mlir::success(); @@ -3787,19 +3788,19 @@ class FIRToLLVMLowering BoxProcHostOpConversion, BoxRankOpConversion, BoxTypeCodeOpConversion, BoxTypeDescOpConversion, CallOpConversion, CmpcOpConversion, ConstcOpConversion, ConvertOpConversion, CoordinateOpConversion, - DispatchTableOpConversion, DTEntryOpConversion, DivcOpConversion, - EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion, - ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion, - FreeMemOpConversion, GlobalLenOpConversion, GlobalOpConversion, - HasValueOpConversion, InsertOnRangeOpConversion, - InsertValueOpConversion, IsPresentOpConversion, - LenParamIndexOpConversion, LoadOpConversion, MulcOpConversion, - NegcOpConversion, NoReassocOpConversion, SelectCaseOpConversion, - SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion, - ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion, - SliceOpConversion, StoreOpConversion, StringLitOpConversion, - SubcOpConversion, TypeDescOpConversion, UnboxCharOpConversion, - UnboxProcOpConversion, UndefOpConversion, UnreachableOpConversion, + DTEntryOpConversion, DivcOpConversion, EmboxOpConversion, + EmboxCharOpConversion, EmboxProcOpConversion, ExtractValueOpConversion, + FieldIndexOpConversion, FirEndOpConversion, FreeMemOpConversion, + GlobalLenOpConversion, GlobalOpConversion, HasValueOpConversion, + InsertOnRangeOpConversion, InsertValueOpConversion, + IsPresentOpConversion, LenParamIndexOpConversion, LoadOpConversion, + MulcOpConversion, NegcOpConversion, NoReassocOpConversion, + SelectCaseOpConversion, SelectOpConversion, SelectRankOpConversion, + SelectTypeOpConversion, ShapeOpConversion, ShapeShiftOpConversion, + ShiftOpConversion, SliceOpConversion, StoreOpConversion, + StringLitOpConversion, SubcOpConversion, TypeDescOpConversion, + TypeInfoOpConversion, UnboxCharOpConversion, UnboxProcOpConversion, + UndefOpConversion, UnreachableOpConversion, UnrealizedConversionCastOpConversion, XArrayCoorOpConversion, XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(typeConverter, options); diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp index 962b87acd5a80..d60e5e9657ea0 100644 --- a/flang/lib/Optimizer/Dialect/FIROps.cpp +++ b/flang/lib/Optimizer/Dialect/FIROps.cpp @@ -1161,76 +1161,37 @@ mlir::FunctionType fir::DispatchOp::getFunctionType() { } //===----------------------------------------------------------------------===// -// DispatchTableOp +// TypeInfoOp //===----------------------------------------------------------------------===// -mlir::ParseResult fir::DispatchTableOp::parse(mlir::OpAsmParser &parser, - mlir::OperationState &result) { - // Parse the name as a symbol reference attribute. - mlir::StringAttr nameAttr; - if (parser.parseSymbolName(nameAttr, mlir::SymbolTable::getSymbolAttrName(), - result.attributes)) - return mlir::failure(); - - if (!failed(parser.parseOptionalKeyword(getExtendsKeyword()))) { - mlir::StringAttr parent; - if (parser.parseLParen() || - parser.parseAttribute(parent, getParentAttrNameStr(), - result.attributes) || - parser.parseRParen()) - return mlir::failure(); - } - - // Parse the optional table body. - mlir::Region *body = result.addRegion(); - mlir::OptionalParseResult parseResult = parser.parseOptionalRegion(*body); - if (parseResult.has_value() && failed(*parseResult)) - return mlir::failure(); - - fir::DispatchTableOp::ensureTerminator(*body, parser.getBuilder(), - result.location); - return mlir::success(); +void fir::TypeInfoOp::build(mlir::OpBuilder &builder, + mlir::OperationState &result, fir::RecordType type, + fir::RecordType parentType, + llvm::ArrayRef attrs) { + result.addRegion(); + result.addAttribute(mlir::SymbolTable::getSymbolAttrName(), + builder.getStringAttr(type.getName())); + result.addAttribute(getTypeAttrName(result.name), mlir::TypeAttr::get(type)); + if (parentType) + result.addAttribute(getParentTypeAttrName(result.name), + mlir::TypeAttr::get(parentType)); + result.addAttributes(attrs); } -void fir::DispatchTableOp::print(mlir::OpAsmPrinter &p) { - p << ' '; - p.printSymbolName(getSymName()); - if (getParent()) - p << ' ' << getExtendsKeyword() << '(' - << (*this)->getAttr(getParentAttrNameStr()) << ')'; +mlir::LogicalResult fir::TypeInfoOp::verify() { + if (!getDispatchTable().empty()) + for (auto &op : getDispatchTable().front().without_terminator()) + if (!mlir::isa(op)) + return op.emitOpError("dispatch table must contain dt_entry"); - mlir::Region &body = getOperation()->getRegion(0); - if (!body.empty()) { - p << ' '; - p.printRegion(body, /*printEntryBlockArgs=*/false, - /*printBlockTerminators=*/false); - } -} + if (!mlir::isa(getType())) + return emitOpError("type must be a fir.type"); -mlir::LogicalResult fir::DispatchTableOp::verify() { - if (getRegion().empty()) - return mlir::success(); - for (auto &op : getBlock()) - if (!mlir::isa(op)) - return op.emitOpError("dispatch table must contain dt_entry"); + if (getParentType() && !mlir::isa(*getParentType())) + return emitOpError("parent_type must be a fir.type"); return mlir::success(); } -void fir::DispatchTableOp::build(mlir::OpBuilder &builder, - mlir::OperationState &result, - llvm::StringRef name, mlir::Type type, - llvm::StringRef parent, - llvm::ArrayRef attrs) { - result.addRegion(); - result.addAttribute(mlir::SymbolTable::getSymbolAttrName(), - builder.getStringAttr(name)); - if (!parent.empty()) - result.addAttribute(getParentAttrNameStr(), builder.getStringAttr(parent)); - // result.addAttribute(getSymbolAttrNameStr(), - // mlir::SymbolRefAttr::get(builder.getContext(), name)); - result.addAttributes(attrs); -} - //===----------------------------------------------------------------------===// // EmboxOp //===----------------------------------------------------------------------===// diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp index bc35f9b44e73e..323b589cc7f2e 100644 --- a/flang/lib/Optimizer/Dialect/FIRType.cpp +++ b/flang/lib/Optimizer/Dialect/FIRType.cpp @@ -318,6 +318,18 @@ bool isAssumedShape(mlir::Type ty) { return false; } +bool isAllocatableOrPointerArray(mlir::Type ty) { + if (auto refTy = fir::dyn_cast_ptrEleTy(ty)) + ty = refTy; + if (auto boxTy = mlir::dyn_cast(ty)) { + if (auto heapTy = mlir::dyn_cast(boxTy.getEleTy())) + return mlir::isa(heapTy.getEleTy()); + if (auto ptrTy = mlir::dyn_cast(boxTy.getEleTy())) + return mlir::isa(ptrTy.getEleTy()); + } + return false; +} + bool isPolymorphicType(mlir::Type ty) { if (auto refTy = fir::dyn_cast_ptrEleTy(ty)) ty = refTy; diff --git a/flang/lib/Optimizer/Transforms/CMakeLists.txt b/flang/lib/Optimizer/Transforms/CMakeLists.txt index 3d2b7e5eaeade..428c4c2a1e644 100644 --- a/flang/lib/Optimizer/Transforms/CMakeLists.txt +++ b/flang/lib/Optimizer/Transforms/CMakeLists.txt @@ -19,6 +19,7 @@ add_flang_library(FIRTransforms OMPEarlyOutlining.cpp OMPFunctionFiltering.cpp OMPMarkDeclareTarget.cpp + VScaleAttr.cpp DEPENDS FIRDialect diff --git a/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp b/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp index f5d0602c270cc..93efea434cb12 100644 --- a/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp +++ b/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp @@ -70,7 +70,7 @@ class SelectTypeConv : public OpConversionPattern { mlir::PatternRewriter &rewriter, fir::KindMapping &kindMap) const; - llvm::SmallSet collectAncestors(fir::DispatchTableOp dt, + llvm::SmallSet collectAncestors(fir::TypeInfoOp dt, mlir::ModuleOp mod) const; // Mutex used to guard insertion of mlir::func::FuncOp in the module. @@ -305,7 +305,7 @@ mlir::LogicalResult SelectTypeConv::matchAndRewrite( if (auto a = typeGuards[t].dyn_cast()) { if (auto recTy = a.getType().dyn_cast()) { - auto dt = mod.lookupSymbol(recTy.getName()); + auto dt = mod.lookupSymbol(recTy.getName()); assert(dt && "dispatch table not found"); llvm::SmallSet ancestors = collectAncestors(dt, mod); @@ -462,14 +462,12 @@ SelectTypeConv::genTypeDescCompare(mlir::Location loc, mlir::Value selector, } llvm::SmallSet -SelectTypeConv::collectAncestors(fir::DispatchTableOp dt, - mlir::ModuleOp mod) const { +SelectTypeConv::collectAncestors(fir::TypeInfoOp dt, mlir::ModuleOp mod) const { llvm::SmallSet ancestors; - if (!dt.getParent().has_value()) - return ancestors; - while (dt.getParent().has_value()) { - ancestors.insert(*dt.getParent()); - dt = mod.lookupSymbol(*dt.getParent()); + while (auto parentName = dt.getIfParentName()) { + ancestors.insert(*parentName); + dt = mod.lookupSymbol(*parentName); + assert(dt && "parent type info not generated"); } return ancestors; } diff --git a/flang/lib/Optimizer/Transforms/VScaleAttr.cpp b/flang/lib/Optimizer/Transforms/VScaleAttr.cpp new file mode 100644 index 0000000000000..601a937de37be --- /dev/null +++ b/flang/lib/Optimizer/Transforms/VScaleAttr.cpp @@ -0,0 +1,90 @@ +//===- VScaleAttr.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +/// \file +/// This pass adds a `vscale_range` attribute to function definitions. +/// The attribute is used for scalable vector operations on Arm processors +/// and should only be run on processors that support this feature. [It is +/// likely harmless to run it on something else, but it is also not valuable]. +//===----------------------------------------------------------------------===// + +#include "flang/ISO_Fortran_binding_wrapper.h" +#include "flang/Optimizer/Builder/BoxValue.h" +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/Runtime/Inquiry.h" +#include "flang/Optimizer/Dialect/FIRDialect.h" +#include "flang/Optimizer/Dialect/FIROps.h" +#include "flang/Optimizer/Dialect/FIRType.h" +#include "flang/Optimizer/Dialect/Support/FIRContext.h" +#include "flang/Optimizer/Dialect/Support/KindMapping.h" +#include "flang/Optimizer/Transforms/Passes.h" +#include "mlir/Dialect/LLVMIR/LLVMAttrs.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/IR/Matchers.h" +#include "mlir/IR/TypeUtilities.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Transforms/DialectConversion.h" +#include "mlir/Transforms/GreedyPatternRewriteDriver.h" +#include "mlir/Transforms/RegionUtils.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +#include + +namespace fir { +#define GEN_PASS_DECL_VSCALEATTR +#define GEN_PASS_DEF_VSCALEATTR +#include "flang/Optimizer/Transforms/Passes.h.inc" +} // namespace fir + +#define DEBUG_TYPE "vscale-attr" + +namespace { + +class VScaleAttrPass : public fir::impl::VScaleAttrBase { +public: + VScaleAttrPass(const fir::VScaleAttrOptions &options) { + vscaleRange = options.vscaleRange; + } + VScaleAttrPass() {} + void runOnOperation() override; +}; + +} // namespace + +void VScaleAttrPass::runOnOperation() { + LLVM_DEBUG(llvm::dbgs() << "=== Begin " DEBUG_TYPE " ===\n"); + mlir::func::FuncOp func = getOperation(); + + LLVM_DEBUG(llvm::dbgs() << "Func-name:" << func.getSymName() << "\n"); + + auto context = &getContext(); + + auto intTy = mlir::IntegerType::get(context, 32); + + assert(vscaleRange.first && "VScaleRange minimum should be non-zero"); + + func->setAttr("vscale_range", + mlir::LLVM::VScaleRangeAttr::get( + context, mlir::IntegerAttr::get(intTy, vscaleRange.first), + mlir::IntegerAttr::get(intTy, vscaleRange.second))); + + LLVM_DEBUG(llvm::dbgs() << "=== End " DEBUG_TYPE " ===\n"); +} + +std::unique_ptr +fir::createVScaleAttrPass(std::pair vscaleAttr) { + VScaleAttrOptions opts; + opts.vscaleRange = vscaleAttr; + return std::make_unique(opts); +} + +std::unique_ptr fir::createVScaleAttrPass() { + return std::make_unique(); +} diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 4cb100a302445..b642cb7678c67 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -2166,6 +2166,7 @@ CHECK_SIMPLE_CLAUSE(Compare, OMPC_compare) CHECK_SIMPLE_CLAUSE(CancellationConstructType, OMPC_cancellation_construct_type) CHECK_SIMPLE_CLAUSE(Doacross, OMPC_doacross) CHECK_SIMPLE_CLAUSE(OmpxAttribute, OMPC_ompx_attribute) +CHECK_SIMPLE_CLAUSE(OmpxBare, OMPC_ompx_bare) CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize) CHECK_REQ_SCALAR_INT_CLAUSE(NumTasks, OMPC_num_tasks) diff --git a/flang/runtime/CMakeLists.txt b/flang/runtime/CMakeLists.txt index e7d416749219e..f75daa373705f 100644 --- a/flang/runtime/CMakeLists.txt +++ b/flang/runtime/CMakeLists.txt @@ -150,10 +150,16 @@ option(FLANG_EXPERIMENTAL_CUDA_RUNTIME # List of files that are buildable for all devices. set(supported_files + ISO_Fortran_binding.cpp + assign.cpp + derived.cpp descriptor.cpp + stat.cpp terminator.cpp + tools.cpp transformational.cpp type-code.cpp + type-info.cpp ) if (FLANG_EXPERIMENTAL_CUDA_RUNTIME) diff --git a/flang/runtime/ISO_Fortran_binding.cpp b/flang/runtime/ISO_Fortran_binding.cpp index 45b4d0ae3f569..15743be88d1be 100644 --- a/flang/runtime/ISO_Fortran_binding.cpp +++ b/flang/runtime/ISO_Fortran_binding.cpp @@ -19,7 +19,9 @@ namespace Fortran::ISO { extern "C" { -void *CFI_address( +RT_EXT_API_GROUP_BEGIN + +RT_API_ATTRS void *CFI_address( const CFI_cdesc_t *descriptor, const CFI_index_t subscripts[]) { char *p{static_cast(descriptor->base_addr)}; const CFI_rank_t rank{descriptor->rank}; @@ -30,8 +32,9 @@ void *CFI_address( return p; } -int CFI_allocate(CFI_cdesc_t *descriptor, const CFI_index_t lower_bounds[], - const CFI_index_t upper_bounds[], std::size_t elem_len) { +RT_API_ATTRS int CFI_allocate(CFI_cdesc_t *descriptor, + const CFI_index_t lower_bounds[], const CFI_index_t upper_bounds[], + std::size_t elem_len) { if (!descriptor) { return CFI_INVALID_DESCRIPTOR; } @@ -81,7 +84,7 @@ int CFI_allocate(CFI_cdesc_t *descriptor, const CFI_index_t lower_bounds[], return CFI_SUCCESS; } -int CFI_deallocate(CFI_cdesc_t *descriptor) { +RT_API_ATTRS int CFI_deallocate(CFI_cdesc_t *descriptor) { if (!descriptor) { return CFI_INVALID_DESCRIPTOR; } @@ -101,7 +104,7 @@ int CFI_deallocate(CFI_cdesc_t *descriptor) { return CFI_SUCCESS; } -int CFI_establish(CFI_cdesc_t *descriptor, void *base_addr, +RT_API_ATTRS int CFI_establish(CFI_cdesc_t *descriptor, void *base_addr, CFI_attribute_t attribute, CFI_type_t type, std::size_t elem_len, CFI_rank_t rank, const CFI_index_t extents[]) { int cfiStatus{VerifyEstablishParameters(descriptor, base_addr, attribute, @@ -121,7 +124,7 @@ int CFI_establish(CFI_cdesc_t *descriptor, void *base_addr, return CFI_SUCCESS; } -int CFI_is_contiguous(const CFI_cdesc_t *descriptor) { +RT_API_ATTRS int CFI_is_contiguous(const CFI_cdesc_t *descriptor) { CFI_index_t bytes = descriptor->elem_len; for (int j{0}; j < descriptor->rank; ++j) { if (bytes != descriptor->dim[j].sm) { @@ -132,7 +135,7 @@ int CFI_is_contiguous(const CFI_cdesc_t *descriptor) { return 1; } -int CFI_section(CFI_cdesc_t *result, const CFI_cdesc_t *source, +RT_API_ATTRS int CFI_section(CFI_cdesc_t *result, const CFI_cdesc_t *source, const CFI_index_t lower_bounds[], const CFI_index_t upper_bounds[], const CFI_index_t strides[]) { CFI_index_t extent[CFI_MAX_RANK]; @@ -208,7 +211,7 @@ int CFI_section(CFI_cdesc_t *result, const CFI_cdesc_t *source, return CFI_SUCCESS; } -int CFI_select_part(CFI_cdesc_t *result, const CFI_cdesc_t *source, +RT_API_ATTRS int CFI_select_part(CFI_cdesc_t *result, const CFI_cdesc_t *source, std::size_t displacement, std::size_t elem_len) { if (!result || !source) { return CFI_INVALID_DESCRIPTOR; @@ -243,7 +246,7 @@ int CFI_select_part(CFI_cdesc_t *result, const CFI_cdesc_t *source, return CFI_SUCCESS; } -int CFI_setpointer(CFI_cdesc_t *result, const CFI_cdesc_t *source, +RT_API_ATTRS int CFI_setpointer(CFI_cdesc_t *result, const CFI_cdesc_t *source, const CFI_index_t lower_bounds[]) { if (!result) { return CFI_INVALID_DESCRIPTOR; @@ -285,5 +288,7 @@ int CFI_setpointer(CFI_cdesc_t *result, const CFI_cdesc_t *source, } return CFI_SUCCESS; } + +RT_EXT_API_GROUP_END } // extern "C" } // namespace Fortran::ISO diff --git a/flang/runtime/assign-impl.h b/flang/runtime/assign-impl.h index 0cc3aab432fc2..f07a501d1d126 100644 --- a/flang/runtime/assign-impl.h +++ b/flang/runtime/assign-impl.h @@ -17,7 +17,8 @@ class Terminator; // Note that if allocate object and source expression have the same rank, the // value of the allocate object becomes the value provided; otherwise the value // of each element of allocate object becomes the value provided (9.7.1.2(7)). -void DoFromSourceAssign(Descriptor &, const Descriptor &, Terminator &); +RT_API_ATTRS void DoFromSourceAssign( + Descriptor &, const Descriptor &, Terminator &); } // namespace Fortran::runtime #endif // FORTRAN_RUNTIME_ASSIGN_IMPL_H_ diff --git a/flang/runtime/assign.cpp b/flang/runtime/assign.cpp index 3a7ade9421ccf..237acb0c89fc2 100644 --- a/flang/runtime/assign.cpp +++ b/flang/runtime/assign.cpp @@ -30,7 +30,7 @@ enum AssignFlags { // Predicate: is the left-hand side of an assignment an allocated allocatable // that must be deallocated? -static inline bool MustDeallocateLHS( +static inline RT_API_ATTRS bool MustDeallocateLHS( Descriptor &to, const Descriptor &from, Terminator &terminator, int flags) { // Top-level assignments to allocatable variables (*not* components) // may first deallocate existing content if there's about to be a @@ -83,7 +83,7 @@ static inline bool MustDeallocateLHS( // Utility: allocate the allocatable left-hand side, either because it was // originally deallocated or because it required reallocation -static int AllocateAssignmentLHS( +static RT_API_ATTRS int AllocateAssignmentLHS( Descriptor &to, const Descriptor &from, Terminator &terminator, int flags) { to.raw().type = from.raw().type; if (!(flags & ExplicitLengthCharacterLHS)) { @@ -118,7 +118,7 @@ static int AllocateAssignmentLHS( } // least <= 0, most >= 0 -static void MaximalByteOffsetRange( +static RT_API_ATTRS void MaximalByteOffsetRange( const Descriptor &desc, std::int64_t &least, std::int64_t &most) { least = most = 0; if (desc.ElementBytes() == 0) { @@ -140,15 +140,15 @@ static void MaximalByteOffsetRange( most += desc.ElementBytes() - 1; } -static inline bool RangesOverlap(const char *aStart, const char *aEnd, - const char *bStart, const char *bEnd) { +static inline RT_API_ATTRS bool RangesOverlap(const char *aStart, + const char *aEnd, const char *bStart, const char *bEnd) { return aEnd >= bStart && bEnd >= aStart; } // Predicate: could the left-hand and right-hand sides of the assignment // possibly overlap in memory? Note that the descriptors themeselves // are included in the test. -static bool MayAlias(const Descriptor &x, const Descriptor &y) { +static RT_API_ATTRS bool MayAlias(const Descriptor &x, const Descriptor &y) { const char *xBase{x.OffsetElement()}; const char *yBase{y.OffsetElement()}; if (!xBase || !yBase) { @@ -176,7 +176,7 @@ static bool MayAlias(const Descriptor &x, const Descriptor &y) { return true; } -static void DoScalarDefinedAssignment(const Descriptor &to, +static RT_API_ATTRS void DoScalarDefinedAssignment(const Descriptor &to, const Descriptor &from, const typeInfo::SpecialBinding &special) { bool toIsDesc{special.IsArgDescriptor(0)}; bool fromIsDesc{special.IsArgDescriptor(1)}; @@ -200,7 +200,7 @@ static void DoScalarDefinedAssignment(const Descriptor &to, } } -static void DoElementalDefinedAssignment(const Descriptor &to, +static RT_API_ATTRS void DoElementalDefinedAssignment(const Descriptor &to, const Descriptor &from, const typeInfo::DerivedType &derived, const typeInfo::SpecialBinding &special) { SubscriptValue toAt[maxRank], fromAt[maxRank]; @@ -221,15 +221,16 @@ static void DoElementalDefinedAssignment(const Descriptor &to, } template -static void BlankPadCharacterAssignment(Descriptor &to, const Descriptor &from, - SubscriptValue toAt[], SubscriptValue fromAt[], std::size_t elements, - std::size_t toElementBytes, std::size_t fromElementBytes) { +static RT_API_ATTRS void BlankPadCharacterAssignment(Descriptor &to, + const Descriptor &from, SubscriptValue toAt[], SubscriptValue fromAt[], + std::size_t elements, std::size_t toElementBytes, + std::size_t fromElementBytes) { std::size_t padding{(toElementBytes - fromElementBytes) / sizeof(CHAR)}; std::size_t copiedCharacters{fromElementBytes / sizeof(CHAR)}; for (; elements-- > 0; to.IncrementSubscripts(toAt), from.IncrementSubscripts(fromAt)) { CHAR *p{to.Element(toAt)}; - std::memmove( + Fortran::runtime::memmove( p, from.Element>(fromAt), fromElementBytes); p += copiedCharacters; for (auto n{padding}; n-- > 0;) { @@ -249,7 +250,7 @@ static void BlankPadCharacterAssignment(Descriptor &to, const Descriptor &from, // of elements, but their shape need not to conform (the assignment is done in // element sequence order). This facilitates some internal usages, like when // dealing with array constructors. -static void Assign( +RT_API_ATTRS static void Assign( Descriptor &to, const Descriptor &from, Terminator &terminator, int flags) { bool mustDeallocateLHS{(flags & DeallocateLHS) || MustDeallocateLHS(to, from, terminator, flags)}; @@ -262,10 +263,12 @@ static void Assign( } std::size_t toElementBytes{to.ElementBytes()}; std::size_t fromElementBytes{from.ElementBytes()}; - auto isSimpleMemmove{[&]() { + // The following lambda definition violates the conding style, + // but cuda-11.8 nvcc hits an internal error with the brace initialization. + auto isSimpleMemmove = [&]() { return !toDerived && to.rank() == from.rank() && to.IsContiguous() && from.IsContiguous() && toElementBytes == fromElementBytes; - }}; + }; StaticDescriptor deferredDeallocStatDesc; Descriptor *deferDeallocation{nullptr}; if (MayAlias(to, from)) { @@ -418,7 +421,7 @@ static void Assign( std::size_t componentByteSize{comp.SizeInBytes(to)}; for (std::size_t j{0}; j < toElements; ++j, to.IncrementSubscripts(toAt), from.IncrementSubscripts(fromAt)) { - std::memmove(to.Element(toAt) + comp.offset(), + Fortran::runtime::memmove(to.Element(toAt) + comp.offset(), from.Element(fromAt) + comp.offset(), componentByteSize); } @@ -428,7 +431,7 @@ static void Assign( std::size_t componentByteSize{comp.SizeInBytes(to)}; for (std::size_t j{0}; j < toElements; ++j, to.IncrementSubscripts(toAt), from.IncrementSubscripts(fromAt)) { - std::memmove(to.Element(toAt) + comp.offset(), + Fortran::runtime::memmove(to.Element(toAt) + comp.offset(), from.Element(fromAt) + comp.offset(), componentByteSize); } @@ -479,14 +482,14 @@ static void Assign( *procPtrDesc.ZeroBasedIndexedElement(k)}; for (std::size_t j{0}; j < toElements; ++j, to.IncrementSubscripts(toAt), from.IncrementSubscripts(fromAt)) { - std::memmove(to.Element(toAt) + procPtr.offset, + Fortran::runtime::memmove(to.Element(toAt) + procPtr.offset, from.Element(fromAt) + procPtr.offset, sizeof(typeInfo::ProcedurePointer)); } } } else { // intrinsic type, intrinsic assignment if (isSimpleMemmove()) { - std::memmove(to.raw().base_addr, from.raw().base_addr, + Fortran::runtime::memmove(to.raw().base_addr, from.raw().base_addr, toElements * toElementBytes); } else if (toElementBytes > fromElementBytes) { // blank padding switch (to.type().raw()) { @@ -510,8 +513,8 @@ static void Assign( } else { // elemental copies, possibly with character truncation for (std::size_t n{toElements}; n-- > 0; to.IncrementSubscripts(toAt), from.IncrementSubscripts(fromAt)) { - std::memmove(to.Element(toAt), from.Element(fromAt), - toElementBytes); + Fortran::runtime::memmove(to.Element(toAt), + from.Element(fromAt), toElementBytes); } } } @@ -523,7 +526,9 @@ static void Assign( } } -void DoFromSourceAssign( +RT_OFFLOAD_API_GROUP_BEGIN + +RT_API_ATTRS void DoFromSourceAssign( Descriptor &alloc, const Descriptor &source, Terminator &terminator) { if (alloc.rank() > 0 && source.rank() == 0) { // The value of each element of allocate object becomes the value of source. @@ -542,8 +547,8 @@ void DoFromSourceAssign( } else { // intrinsic type for (std::size_t n{alloc.Elements()}; n-- > 0; alloc.IncrementSubscripts(allocAt)) { - std::memmove(alloc.Element(allocAt), source.raw().base_addr, - alloc.ElementBytes()); + Fortran::runtime::memmove(alloc.Element(allocAt), + source.raw().base_addr, alloc.ElementBytes()); } } } else { @@ -551,8 +556,12 @@ void DoFromSourceAssign( } } +RT_OFFLOAD_API_GROUP_END + extern "C" { -void RTNAME(Assign)(Descriptor &to, const Descriptor &from, +RT_EXT_API_GROUP_BEGIN + +void RTDEF(Assign)(Descriptor &to, const Descriptor &from, const char *sourceFile, int sourceLine) { Terminator terminator{sourceFile, sourceLine}; // All top-level defined assignments can be recognized in semantics and @@ -562,7 +571,7 @@ void RTNAME(Assign)(Descriptor &to, const Descriptor &from, MaybeReallocate | NeedFinalization | ComponentCanBeDefinedAssignment); } -void RTNAME(AssignTemporary)(Descriptor &to, const Descriptor &from, +void RTDEF(AssignTemporary)(Descriptor &to, const Descriptor &from, const char *sourceFile, int sourceLine) { Terminator terminator{sourceFile, sourceLine}; // Initialize the "to" if it is of derived type that needs initialization. @@ -591,7 +600,7 @@ void RTNAME(AssignTemporary)(Descriptor &to, const Descriptor &from, Assign(to, from, terminator, PolymorphicLHS); } -void RTNAME(CopyOutAssign)(Descriptor &to, const Descriptor &from, +void RTDEF(CopyOutAssign)(Descriptor &to, const Descriptor &from, bool skipToInit, const char *sourceFile, int sourceLine) { Terminator terminator{sourceFile, sourceLine}; // Initialize the "to" if it is of derived type that needs initialization. @@ -613,7 +622,7 @@ void RTNAME(CopyOutAssign)(Descriptor &to, const Descriptor &from, Assign(to, from, terminator, NoAssignFlags); } -void RTNAME(AssignExplicitLengthCharacter)(Descriptor &to, +void RTDEF(AssignExplicitLengthCharacter)(Descriptor &to, const Descriptor &from, const char *sourceFile, int sourceLine) { Terminator terminator{sourceFile, sourceLine}; Assign(to, from, terminator, @@ -621,12 +630,14 @@ void RTNAME(AssignExplicitLengthCharacter)(Descriptor &to, ExplicitLengthCharacterLHS); } -void RTNAME(AssignPolymorphic)(Descriptor &to, const Descriptor &from, +void RTDEF(AssignPolymorphic)(Descriptor &to, const Descriptor &from, const char *sourceFile, int sourceLine) { Terminator terminator{sourceFile, sourceLine}; Assign(to, from, terminator, MaybeReallocate | NeedFinalization | ComponentCanBeDefinedAssignment | PolymorphicLHS); } + +RT_EXT_API_GROUP_END } // extern "C" } // namespace Fortran::runtime diff --git a/flang/runtime/derived.cpp b/flang/runtime/derived.cpp index 6e87e010df2ed..8a0d0ab2bb783 100644 --- a/flang/runtime/derived.cpp +++ b/flang/runtime/derived.cpp @@ -15,8 +15,11 @@ namespace Fortran::runtime { -int Initialize(const Descriptor &instance, const typeInfo::DerivedType &derived, - Terminator &terminator, bool hasStat, const Descriptor *errMsg) { +RT_OFFLOAD_API_GROUP_BEGIN + +RT_API_ATTRS int Initialize(const Descriptor &instance, + const typeInfo::DerivedType &derived, Terminator &terminator, bool hasStat, + const Descriptor *errMsg) { const Descriptor &componentDesc{derived.component()}; std::size_t elements{instance.Elements()}; int stat{StatOk}; @@ -114,7 +117,7 @@ int Initialize(const Descriptor &instance, const typeInfo::DerivedType &derived, return stat; } -static const typeInfo::SpecialBinding *FindFinal( +static RT_API_ATTRS const typeInfo::SpecialBinding *FindFinal( const typeInfo::DerivedType &derived, int rank) { if (const auto *ranked{derived.FindSpecialBinding( typeInfo::SpecialBinding::RankFinal(rank))}) { @@ -128,7 +131,7 @@ static const typeInfo::SpecialBinding *FindFinal( } } -static void CallFinalSubroutine(const Descriptor &descriptor, +static RT_API_ATTRS void CallFinalSubroutine(const Descriptor &descriptor, const typeInfo::DerivedType &derived, Terminator *terminator) { if (const auto *special{FindFinal(derived, descriptor.rank())}) { if (special->which() == typeInfo::SpecialBinding::Which::ElementalFinal) { @@ -193,7 +196,7 @@ static void CallFinalSubroutine(const Descriptor &descriptor, } // Fortran 2018 subclause 7.5.6.2 -void Finalize(const Descriptor &descriptor, +RT_API_ATTRS void Finalize(const Descriptor &descriptor, const typeInfo::DerivedType &derived, Terminator *terminator) { if (derived.noFinalizationNeeded() || !descriptor.IsAllocated()) { return; @@ -285,7 +288,7 @@ void Finalize(const Descriptor &descriptor, // elementwise finalization of non-parent components taking place // before parent component finalization, and with all finalization // preceding any deallocation. -void Destroy(const Descriptor &descriptor, bool finalize, +RT_API_ATTRS void Destroy(const Descriptor &descriptor, bool finalize, const typeInfo::DerivedType &derived, Terminator *terminator) { if (derived.noDestructionNeeded() || !descriptor.IsAllocated()) { return; @@ -313,7 +316,7 @@ void Destroy(const Descriptor &descriptor, bool finalize, } } -bool HasDynamicComponent(const Descriptor &descriptor) { +RT_API_ATTRS bool HasDynamicComponent(const Descriptor &descriptor) { if (const DescriptorAddendum * addendum{descriptor.Addendum()}) { if (const auto *derived = addendum->derivedType()) { const Descriptor &componentDesc{derived->component()}; @@ -331,4 +334,5 @@ bool HasDynamicComponent(const Descriptor &descriptor) { return false; } +RT_OFFLOAD_API_GROUP_END } // namespace Fortran::runtime diff --git a/flang/runtime/freestanding-tools.h b/flang/runtime/freestanding-tools.h index 6acfb8a532d30..28248f76e882a 100644 --- a/flang/runtime/freestanding-tools.h +++ b/flang/runtime/freestanding-tools.h @@ -10,7 +10,9 @@ #define FORTRAN_RUNTIME_FREESTANDING_TOOLS_H_ #include "flang/Runtime/api-attrs.h" +#include "flang/Runtime/c-or-cpp.h" #include +#include // The file defines a set of utilities/classes that might be // used to get reduce the dependency on external libraries (e.g. libstdc++). @@ -20,6 +22,21 @@ #define STD_FILL_N_UNSUPPORTED 1 #endif +#if !defined(STD_MEMMOVE_UNSUPPORTED) && \ + (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__) +#define STD_MEMMOVE_UNSUPPORTED 1 +#endif + +#if !defined(STD_STRLEN_UNSUPPORTED) && \ + (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__) +#define STD_STRLEN_UNSUPPORTED 1 +#endif + +#if !defined(STD_MEMCMP_UNSUPPORTED) && \ + (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__) +#define STD_MEMCMP_UNSUPPORTED 1 +#endif + namespace Fortran::runtime { #if STD_FILL_N_UNSUPPORTED @@ -28,16 +45,78 @@ namespace Fortran::runtime { template static inline RT_API_ATTRS void fill_n( A *start, std::size_t count, const A &value) { -#if STD_FILL_N_UNSUPPORTED - for (std::size_t j{0}; j < count; ++j) + for (std::size_t j{0}; j < count; ++j) { start[j] = value; -#else - std::fill_n(start, count, value); -#endif + } } #else // !STD_FILL_N_UNSUPPORTED using std::fill_n; #endif // !STD_FILL_N_UNSUPPORTED +#if STD_MEMMOVE_UNSUPPORTED +// Provides alternative implementation for std::memmove(), if +// it is not supported. +static inline RT_API_ATTRS void memmove( + void *dest, const void *src, std::size_t count) { + char *to{reinterpret_cast(dest)}; + const char *from{reinterpret_cast(src)}; + + if (to == from) { + return; + } + if (to + count <= from || from + count <= to) { + std::memcpy(dest, src, count); + } else if (to < from) { + while (count--) { + *to++ = *from++; + } + } else { + to += count; + from += count; + while (count--) { + *--to = *--from; + } + } +} +#else // !STD_MEMMOVE_UNSUPPORTED +using std::memmove; +#endif // !STD_MEMMOVE_UNSUPPORTED + +#if STD_STRLEN_UNSUPPORTED +// Provides alternative implementation for std::strlen(), if +// it is not supported. +static inline RT_API_ATTRS std::size_t strlen(const char *str) { + if (!str) { + // Return 0 for nullptr. + return 0; + } + const char *end = str; + for (; *end != '\0'; ++end) + ; + return end - str; +} +#else // !STD_STRLEN_UNSUPPORTED +using std::strlen; +#endif // !STD_STRLEN_UNSUPPORTED + +#if STD_MEMCMP_UNSUPPORTED +// Provides alternative implementation for std::memcmp(), if +// it is not supported. +static inline RT_API_ATTRS int memcmp( + const void *RESTRICT lhs, const void *RESTRICT rhs, std::size_t count) { + auto m1{reinterpret_cast(lhs)}; + auto m2{reinterpret_cast(rhs)}; + for (; count--; ++m1, ++m2) { + int diff = *m1 - *m2; + if (diff != 0) { + return diff; + } + } + return 0; +} +#else // !STD_MEMCMP_UNSUPPORTED +using std::memcmp; +#endif // !STD_MEMCMP_UNSUPPORTED + } // namespace Fortran::runtime #endif // FORTRAN_RUNTIME_FREESTANDING_TOOLS_H_ diff --git a/flang/runtime/stat.cpp b/flang/runtime/stat.cpp index 63284bbea7f23..24368fa6a1ae1 100644 --- a/flang/runtime/stat.cpp +++ b/flang/runtime/stat.cpp @@ -8,10 +8,13 @@ #include "stat.h" #include "terminator.h" +#include "tools.h" #include "flang/Runtime/descriptor.h" namespace Fortran::runtime { -const char *StatErrorString(int stat) { +RT_OFFLOAD_API_GROUP_BEGIN + +RT_API_ATTRS const char *StatErrorString(int stat) { switch (stat) { case StatOk: return "No error"; @@ -68,14 +71,14 @@ const char *StatErrorString(int stat) { } } -int ToErrmsg(const Descriptor *errmsg, int stat) { +RT_API_ATTRS int ToErrmsg(const Descriptor *errmsg, int stat) { if (stat != StatOk && errmsg && errmsg->raw().base_addr && errmsg->type() == TypeCode(TypeCategory::Character, 1) && errmsg->rank() == 0) { if (const char *msg{StatErrorString(stat)}) { char *buffer{errmsg->OffsetElement()}; std::size_t bufferLength{errmsg->ElementBytes()}; - std::size_t msgLength{std::strlen(msg)}; + std::size_t msgLength{Fortran::runtime::strlen(msg)}; if (msgLength >= bufferLength) { std::memcpy(buffer, msg, bufferLength); } else { @@ -87,7 +90,7 @@ int ToErrmsg(const Descriptor *errmsg, int stat) { return stat; } -int ReturnError( +RT_API_ATTRS int ReturnError( Terminator &terminator, int stat, const Descriptor *errmsg, bool hasStat) { if (stat == StatOk || hasStat) { return ToErrmsg(errmsg, stat); @@ -98,4 +101,6 @@ int ReturnError( } return stat; } + +RT_OFFLOAD_API_GROUP_END } // namespace Fortran::runtime diff --git a/flang/runtime/stat.h b/flang/runtime/stat.h index 7ba797c374186..e2b0658b122c9 100644 --- a/flang/runtime/stat.h +++ b/flang/runtime/stat.h @@ -12,6 +12,7 @@ #ifndef FORTRAN_RUNTIME_STAT_H_ #define FORTRAN_RUNTIME_STAT_H_ #include "flang/ISO_Fortran_binding_wrapper.h" +#include "flang/Runtime/api-attrs.h" #include "flang/Runtime/magic-numbers.h" namespace Fortran::runtime { @@ -52,9 +53,9 @@ enum Stat { FORTRAN_RUNTIME_STAT_MOVE_ALLOC_SAME_ALLOCATABLE, }; -const char *StatErrorString(int); -int ToErrmsg(const Descriptor *errmsg, int stat); // returns stat -int ReturnError(Terminator &, int stat, const Descriptor *errmsg = nullptr, - bool hasStat = false); +RT_API_ATTRS const char *StatErrorString(int); +RT_API_ATTRS int ToErrmsg(const Descriptor *errmsg, int stat); // returns stat +RT_API_ATTRS int ReturnError(Terminator &, int stat, + const Descriptor *errmsg = nullptr, bool hasStat = false); } // namespace Fortran::runtime #endif // FORTRAN_RUNTIME_STAT_H diff --git a/flang/runtime/tools.cpp b/flang/runtime/tools.cpp index 36cfa456a0823..a027559d9f4a7 100644 --- a/flang/runtime/tools.cpp +++ b/flang/runtime/tools.cpp @@ -15,14 +15,16 @@ namespace Fortran::runtime { -std::size_t TrimTrailingSpaces(const char *s, std::size_t n) { +RT_OFFLOAD_API_GROUP_BEGIN + +RT_API_ATTRS std::size_t TrimTrailingSpaces(const char *s, std::size_t n) { while (n > 0 && s[n - 1] == ' ') { --n; } return n; } -OwningPtr SaveDefaultCharacter( +RT_API_ATTRS OwningPtr SaveDefaultCharacter( const char *s, std::size_t length, const Terminator &terminator) { if (s) { auto *p{static_cast(AllocateMemoryOrCrash(terminator, length + 1))}; @@ -34,7 +36,7 @@ OwningPtr SaveDefaultCharacter( } } -static bool CaseInsensitiveMatch( +static RT_API_ATTRS bool CaseInsensitiveMatch( const char *value, std::size_t length, const char *possibility) { for (; length-- > 0; ++possibility) { char ch{*value++}; @@ -57,7 +59,7 @@ static bool CaseInsensitiveMatch( return *possibility == '\0'; } -int IdentifyValue( +RT_API_ATTRS int IdentifyValue( const char *value, std::size_t length, const char *possibilities[]) { if (value) { for (int j{0}; possibilities[j]; ++j) { @@ -69,9 +71,9 @@ int IdentifyValue( return -1; } -void ToFortranDefaultCharacter( +RT_API_ATTRS void ToFortranDefaultCharacter( char *to, std::size_t toLength, const char *from) { - std::size_t len{std::strlen(from)}; + std::size_t len{Fortran::runtime::strlen(from)}; if (len < toLength) { std::memcpy(to, from, len); std::memset(to + len, ' ', toLength - len); @@ -80,7 +82,7 @@ void ToFortranDefaultCharacter( } } -void CheckConformability(const Descriptor &to, const Descriptor &x, +RT_API_ATTRS void CheckConformability(const Descriptor &to, const Descriptor &x, Terminator &terminator, const char *funcName, const char *toName, const char *xName) { if (x.rank() == 0) { @@ -104,14 +106,15 @@ void CheckConformability(const Descriptor &to, const Descriptor &x, } } -void CheckIntegerKind(Terminator &terminator, int kind, const char *intrinsic) { +RT_API_ATTRS void CheckIntegerKind( + Terminator &terminator, int kind, const char *intrinsic) { if (kind < 1 || kind > 16 || (kind & (kind - 1)) != 0) { terminator.Crash( "not yet implemented: %s: KIND=%d argument", intrinsic, kind); } } -void ShallowCopyDiscontiguousToDiscontiguous( +RT_API_ATTRS void ShallowCopyDiscontiguousToDiscontiguous( const Descriptor &to, const Descriptor &from) { SubscriptValue toAt[maxRank], fromAt[maxRank]; to.GetLowerBounds(toAt); @@ -124,7 +127,7 @@ void ShallowCopyDiscontiguousToDiscontiguous( } } -void ShallowCopyDiscontiguousToContiguous( +RT_API_ATTRS void ShallowCopyDiscontiguousToContiguous( const Descriptor &to, const Descriptor &from) { char *toAt{to.OffsetElement()}; SubscriptValue fromAt[maxRank]; @@ -136,7 +139,7 @@ void ShallowCopyDiscontiguousToContiguous( } } -void ShallowCopyContiguousToDiscontiguous( +RT_API_ATTRS void ShallowCopyContiguousToDiscontiguous( const Descriptor &to, const Descriptor &from) { SubscriptValue toAt[maxRank]; to.GetLowerBounds(toAt); @@ -148,7 +151,7 @@ void ShallowCopyContiguousToDiscontiguous( } } -void ShallowCopy(const Descriptor &to, const Descriptor &from, +RT_API_ATTRS void ShallowCopy(const Descriptor &to, const Descriptor &from, bool toIsContiguous, bool fromIsContiguous) { if (toIsContiguous) { if (fromIsContiguous) { @@ -166,7 +169,9 @@ void ShallowCopy(const Descriptor &to, const Descriptor &from, } } -void ShallowCopy(const Descriptor &to, const Descriptor &from) { +RT_API_ATTRS void ShallowCopy(const Descriptor &to, const Descriptor &from) { ShallowCopy(to, from, to.IsContiguous(), from.IsContiguous()); } + +RT_OFFLOAD_API_GROUP_END } // namespace Fortran::runtime diff --git a/flang/runtime/tools.h b/flang/runtime/tools.h index 34ee8c56aa962..ea659190e1439 100644 --- a/flang/runtime/tools.h +++ b/flang/runtime/tools.h @@ -23,20 +23,20 @@ namespace Fortran::runtime { class Terminator; -std::size_t TrimTrailingSpaces(const char *, std::size_t); +RT_API_ATTRS std::size_t TrimTrailingSpaces(const char *, std::size_t); -OwningPtr SaveDefaultCharacter( +RT_API_ATTRS OwningPtr SaveDefaultCharacter( const char *, std::size_t, const Terminator &); // For validating and recognizing default CHARACTER values in a // case-insensitive manner. Returns the zero-based index into the // null-terminated array of upper-case possibilities when the value is valid, // or -1 when it has no match. -int IdentifyValue( +RT_API_ATTRS int IdentifyValue( const char *value, std::size_t length, const char *possibilities[]); // Truncates or pads as necessary -void ToFortranDefaultCharacter( +RT_API_ATTRS void ToFortranDefaultCharacter( char *to, std::size_t toLength, const char *from); // Utility for dealing with elemental LOGICAL arguments @@ -59,8 +59,8 @@ RT_API_ATTRS void CheckConformability(const Descriptor &to, const Descriptor &x, // Helper to store integer value in result[at]. template struct StoreIntegerAt { - void operator()(const Fortran::runtime::Descriptor &result, std::size_t at, - std::int64_t value) const { + RT_API_ATTRS void operator()(const Fortran::runtime::Descriptor &result, + std::size_t at, std::int64_t value) const { *result.ZeroBasedIndexedElement>(at) = value; } @@ -71,7 +71,8 @@ RT_API_ATTRS void CheckIntegerKind( Terminator &, int kind, const char *intrinsic); template -inline void PutContiguousConverted(TO *to, FROM *from, std::size_t count) { +inline RT_API_ATTRS void PutContiguousConverted( + TO *to, FROM *from, std::size_t count) { while (count-- > 0) { *to++ = *from++; } @@ -94,7 +95,7 @@ static inline RT_API_ATTRS std::int64_t GetInt64( } template -inline bool SetInteger(INT &x, int kind, std::int64_t value) { +inline RT_API_ATTRS bool SetInteger(INT &x, int kind, std::int64_t value) { switch (kind) { case 1: reinterpret_cast &>(x) = value; @@ -300,8 +301,8 @@ inline RT_API_ATTRS RESULT ApplyLogicalKind( } // Calculate result type of (X op Y) for *, //, DOT_PRODUCT, &c. -std::optional> inline constexpr GetResultType( - TypeCategory xCat, int xKind, TypeCategory yCat, int yKind) { +std::optional> inline constexpr RT_API_ATTRS +GetResultType(TypeCategory xCat, int xKind, TypeCategory yCat, int yKind) { int maxKind{std::max(xKind, yKind)}; switch (xCat) { case TypeCategory::Integer: @@ -379,7 +380,7 @@ using AccumulationType = CppTypeFor -static inline const CHAR *FindCharacter( +static inline RT_API_ATTRS const CHAR *FindCharacter( const CHAR *data, CHAR ch, std::size_t chars) { const CHAR *end{data + chars}; for (const CHAR *p{data}; p < end; ++p) { @@ -391,7 +392,8 @@ static inline const CHAR *FindCharacter( } template <> -inline const char *FindCharacter(const char *data, char ch, std::size_t chars) { +inline RT_API_ATTRS const char *FindCharacter( + const char *data, char ch, std::size_t chars) { return reinterpret_cast( std::memchr(data, static_cast(ch), chars)); } @@ -399,15 +401,15 @@ inline const char *FindCharacter(const char *data, char ch, std::size_t chars) { // Copy payload data from one allocated descriptor to another. // Assumes element counts and element sizes match, and that both // descriptors are allocated. -void ShallowCopyDiscontiguousToDiscontiguous( +RT_API_ATTRS void ShallowCopyDiscontiguousToDiscontiguous( const Descriptor &to, const Descriptor &from); -void ShallowCopyDiscontiguousToContiguous( +RT_API_ATTRS void ShallowCopyDiscontiguousToContiguous( const Descriptor &to, const Descriptor &from); -void ShallowCopyContiguousToDiscontiguous( +RT_API_ATTRS void ShallowCopyContiguousToDiscontiguous( const Descriptor &to, const Descriptor &from); -void ShallowCopy(const Descriptor &to, const Descriptor &from, +RT_API_ATTRS void ShallowCopy(const Descriptor &to, const Descriptor &from, bool toIsContiguous, bool fromIsContiguous); -void ShallowCopy(const Descriptor &to, const Descriptor &from); +RT_API_ATTRS void ShallowCopy(const Descriptor &to, const Descriptor &from); } // namespace Fortran::runtime #endif // FORTRAN_RUNTIME_TOOLS_H_ diff --git a/flang/runtime/type-info.cpp b/flang/runtime/type-info.cpp index 5bd0258cbbf7f..baf446e0c79d3 100644 --- a/flang/runtime/type-info.cpp +++ b/flang/runtime/type-info.cpp @@ -8,11 +8,14 @@ #include "type-info.h" #include "terminator.h" +#include "tools.h" #include namespace Fortran::runtime::typeInfo { -std::optional Value::GetValue( +RT_OFFLOAD_API_GROUP_BEGIN + +RT_API_ATTRS std::optional Value::GetValue( const Descriptor *descriptor) const { switch (genre_) { case Genre::Explicit: @@ -29,7 +32,8 @@ std::optional Value::GetValue( } } -std::size_t Component::GetElementByteSize(const Descriptor &instance) const { +RT_API_ATTRS std::size_t Component::GetElementByteSize( + const Descriptor &instance) const { switch (category()) { case TypeCategory::Integer: case TypeCategory::Real: @@ -51,7 +55,8 @@ std::size_t Component::GetElementByteSize(const Descriptor &instance) const { return 0; } -std::size_t Component::GetElements(const Descriptor &instance) const { +RT_API_ATTRS std::size_t Component::GetElements( + const Descriptor &instance) const { std::size_t elements{1}; if (int rank{rank_}) { if (const Value * boundValues{bounds()}) { @@ -73,7 +78,8 @@ std::size_t Component::GetElements(const Descriptor &instance) const { return elements; } -std::size_t Component::SizeInBytes(const Descriptor &instance) const { +RT_API_ATTRS std::size_t Component::SizeInBytes( + const Descriptor &instance) const { if (genre() == Genre::Data) { return GetElementByteSize(instance) * GetElements(instance); } else if (category() == TypeCategory::Derived) { @@ -85,7 +91,7 @@ std::size_t Component::SizeInBytes(const Descriptor &instance) const { } } -void Component::EstablishDescriptor(Descriptor &descriptor, +RT_API_ATTRS void Component::EstablishDescriptor(Descriptor &descriptor, const Descriptor &container, Terminator &terminator) const { ISO::CFI_attribute_t attribute{static_cast( genre_ == Genre::Allocatable ? CFI_attribute_allocatable @@ -128,7 +134,7 @@ void Component::EstablishDescriptor(Descriptor &descriptor, } } -void Component::CreatePointerDescriptor(Descriptor &descriptor, +RT_API_ATTRS void Component::CreatePointerDescriptor(Descriptor &descriptor, const Descriptor &container, Terminator &terminator, const SubscriptValue *subscripts) const { RUNTIME_CHECK(terminator, genre_ == Genre::Data); @@ -141,7 +147,7 @@ void Component::CreatePointerDescriptor(Descriptor &descriptor, descriptor.raw().attribute = CFI_attribute_pointer; } -const DerivedType *DerivedType::GetParentType() const { +RT_API_ATTRS const DerivedType *DerivedType::GetParentType() const { if (hasParent_) { const Descriptor &compDesc{component()}; const Component &component{*compDesc.OffsetElement()}; @@ -151,7 +157,7 @@ const DerivedType *DerivedType::GetParentType() const { } } -const Component *DerivedType::FindDataComponent( +RT_API_ATTRS const Component *DerivedType::FindDataComponent( const char *compName, std::size_t compNameLen) const { const Descriptor &compDesc{component()}; std::size_t n{compDesc.Elements()}; @@ -162,7 +168,8 @@ const Component *DerivedType::FindDataComponent( INTERNAL_CHECK(component != nullptr); const Descriptor &nameDesc{component->name()}; if (nameDesc.ElementBytes() == compNameLen && - std::memcmp(compName, nameDesc.OffsetElement(), compNameLen) == 0) { + Fortran::runtime::memcmp( + compName, nameDesc.OffsetElement(), compNameLen) == 0) { return component; } } @@ -170,6 +177,8 @@ const Component *DerivedType::FindDataComponent( return parent ? parent->FindDataComponent(compName, compNameLen) : nullptr; } +RT_OFFLOAD_API_GROUP_END + static void DumpScalarCharacter( FILE *f, const Descriptor &desc, const char *what) { if (desc.raw().version == CFI_VERSION && diff --git a/flang/test/Fir/array-value-copy-cam4.fir b/flang/test/Fir/array-value-copy-cam4.fir index 3b3b0082743ce..3bb465cfaa59f 100644 --- a/flang/test/Fir/array-value-copy-cam4.fir +++ b/flang/test/Fir/array-value-copy-cam4.fir @@ -98,5 +98,5 @@ module { return } func.func private @_QPinit(!fir.ref>) - fir.dispatch_table @_QMcam4Tpbuf_fld + fir.type_info @_QMcam4Tpbuf_fld : !fir.type<_QMcam4Tpbuf_fld{fld_ptr:!fir.box>>}> } diff --git a/flang/test/Fir/convert-to-llvm-invalid.fir b/flang/test/Fir/convert-to-llvm-invalid.fir index fcd042f83bd03..9f003e4eb7d59 100644 --- a/flang/test/Fir/convert-to-llvm-invalid.fir +++ b/flang/test/Fir/convert-to-llvm-invalid.fir @@ -2,12 +2,6 @@ // RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" --verify-diagnostics %s -// Verify that `fir.dt_entry` requires a parent op - -// expected-error@+1{{'fir.dt_entry' op expects parent op 'fir.dispatch_table'}} -fir.dt_entry "method", @method_impl - -// ----- // Test `fir.shape` conversion failure because the op has uses. @@ -82,11 +76,28 @@ func.func @bar_select_type(%arg : !fir.class>) -> i3 // Verify that `fir.dt_entry` requires a parent op -// expected-error@+1{{'fir.dt_entry' op expects parent op 'fir.dispatch_table'}} +// expected-error@+1{{'fir.dt_entry' op expects parent op 'fir.type_info'}} fir.dt_entry "method", @method_impl // ----- +// expected-error@+1{{'fir.type_info' op type must be a fir.type}} +fir.type_info @bad : i32 + +// ----- + +// expected-error@+1{{'fir.type_info' op parent_type must be a fir.type}} +fir.type_info @bad extends f32 : !fir.type + +// ----- + +fir.type_info @bad : !fir.type dispatch_table { + // expected-error@+1{{dispatch table must contain dt_entry}} + %zero = arith.constant 0 : i32 +} + +// ----- + // `fir.coordinate_of` - dynamically sized arrays are not supported func.func @coordinate_of_dynamic_array(%arg0: !fir.ref>>, %arg1: index) { // expected-error@+2{{fir.coordinate_of with a dynamic element size is unsupported}} diff --git a/flang/test/Fir/dispatch.f90 b/flang/test/Fir/dispatch.f90 index 933c769d3e169..ce60939410de6 100644 --- a/flang/test/Fir/dispatch.f90 +++ b/flang/test/Fir/dispatch.f90 @@ -308,10 +308,10 @@ program test_type_to_class ! Check the layout of the binding table. This is easier to do in FIR than in ! LLVM IR. -! BT-LABEL: fir.dispatch_table @_QMdispatch1Tty_kindK10K20 -! BT-LABEL: fir.dispatch_table @_QMdispatch1Tty_kind_exK10K20 extends("_QMdispatch1Tty_kindK10K20") +! BT-LABEL: fir.type_info @_QMdispatch1Tty_kindK10K20 +! BT-LABEL: fir.type_info @_QMdispatch1Tty_kind_exK10K20 {{.*}}extends !fir.type<_QMdispatch1Tty_kindK10K20{{.*}}> -! BT-LABEL: fir.dispatch_table @_QMdispatch1Tp1 { +! BT-LABEL: fir.type_info @_QMdispatch1Tp1 ! BT: fir.dt_entry "aproc", @_QMdispatch1Paproc ! BT: fir.dt_entry "display1", @_QMdispatch1Pdisplay1_p1 ! BT: fir.dt_entry "display2", @_QMdispatch1Pdisplay2_p1 @@ -321,15 +321,15 @@ program test_type_to_class ! BT: fir.dt_entry "proc_with_values", @_QMdispatch1Pproc_p1 ! BT: } -! BT-LABEL: fir.dispatch_table @_QMdispatch1Ta1 { +! BT-LABEL: fir.type_info @_QMdispatch1Ta1 ! BT: fir.dt_entry "a1_proc", @_QMdispatch1Pa1_proc ! BT: } -! BT-LABEL: fir.dispatch_table @_QMdispatch1Ta2 extends("_QMdispatch1Ta1") { +! BT-LABEL: fir.type_info @_QMdispatch1Ta2 {{.*}}extends !fir.type<_QMdispatch1Ta1{{.*}}> ! BT: fir.dt_entry "a1_proc", @_QMdispatch1Pa2_proc ! BT: } -! BT-LABEL: fir.dispatch_table @_QMdispatch1Tp2 extends("_QMdispatch1Tp1") { +! BT-LABEL: fir.type_info @_QMdispatch1Tp2 {{.*}}extends !fir.type<_QMdispatch1Tp1{{.*}}> ! BT: fir.dt_entry "aproc", @_QMdispatch1Paproc ! BT: fir.dt_entry "display1", @_QMdispatch1Pdisplay1_p2 ! BT: fir.dt_entry "display2", @_QMdispatch1Pdisplay2_p2 diff --git a/flang/test/Fir/fir-ops.fir b/flang/test/Fir/fir-ops.fir index f2175ce5fb5ae..dd0fbb3be36c4 100644 --- a/flang/test/Fir/fir-ops.fir +++ b/flang/test/Fir/fir-ops.fir @@ -450,13 +450,16 @@ fir.global linkonce_odr @global_linkonce_odr : i32 { fir.has_value %0 : i32 } -// CHECK-LABEL: fir.dispatch_table @dispatch_tbl { +// CHECK-LABEL: fir.type_info @dispatch_tbl : !fir.type dispatch_table { // CHECK: fir.dt_entry "method", @method_impl // CHECK: } -fir.dispatch_table @dispatch_tbl { +fir.type_info @dispatch_tbl : !fir.type dispatch_table { fir.dt_entry "method", @method_impl } +// CHECK-LABEL: fir.type_info @test_type_info noinit nodestroy nofinal extends !fir.type : !fir.type +fir.type_info @test_type_info noinit nodestroy nofinal extends !fir.type : !fir.type + // CHECK-LABEL: func @compare_complex( // CHECK-SAME: [[VAL_151:%.*]]: !fir.complex<16>, [[VAL_152:%.*]]: !fir.complex<16>) { func.func @compare_complex(%a : !fir.complex<16>, %b : !fir.complex<16>) { diff --git a/flang/test/HLFIR/assign-codegen-derived.fir b/flang/test/HLFIR/assign-codegen-derived.fir new file mode 100644 index 0000000000000..c45c118ed46c5 --- /dev/null +++ b/flang/test/HLFIR/assign-codegen-derived.fir @@ -0,0 +1,29 @@ +// Test hlfir.assign code generation to FIR of derived type requiring +// or not finalization. + +// RUN: fir-opt %s -convert-hlfir-to-fir | FileCheck %s + +!t_simple = !fir.type +fir.type_info @simple noinit nodestroy nofinal : !t_simple + +func.func @test_simple(%a: !fir.ref, %b: !fir.ref) { + hlfir.assign %b to %a : !fir.ref, !fir.ref + return +} +// CHECK-LABEL: func.func @test_simple( +// CHECK-NOT: Destroy +// CHECK: %[[VAL_1:.*]] = fir.coordinate_of %{{.*}}, %{{.*}} : (!fir.ref>, !fir.field) -> !fir.ref +// CHECK: %[[VAL_3:.*]] = fir.coordinate_of %{{.*}}, %{{.*}} : (!fir.ref>, !fir.field) -> !fir.ref +// CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_1]] : !fir.ref +// CHECK: fir.store %[[VAL_4]] to %[[VAL_3]] : !fir.ref + + +!t_with_final = !fir.type +fir.type_info @with_final noinit : !t_with_final + +func.func @test_with_final(%a: !fir.ref, %b: !fir.ref) { + hlfir.assign %b to %a : !fir.ref, !fir.ref + return +} +// CHECK-LABEL: func.func @test_with_final( +// CHECK: fir.call @_FortranAAssign diff --git a/flang/test/HLFIR/assign-codegen.fir b/flang/test/HLFIR/assign-codegen.fir index 5474ef5393df4..2211676eac580 100644 --- a/flang/test/HLFIR/assign-codegen.fir +++ b/flang/test/HLFIR/assign-codegen.fir @@ -347,21 +347,21 @@ func.func @_QFPtest_scalar_lhs_finalization(%arg0: !fir.ref> {fir.bindc_name = "s1"}, // CHECK-SAME: %[[VAL_1:.*]]: !fir.ref> {fir.bindc_name = "s2"}) { +// CHECK: %[[BOX:.*]] = fir.alloca !fir.box> // CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_0]] {uniq_name = "_QFFtest_scalar_lhs_finalizationEs1"} : (!fir.ref>) -> !fir.ref> // CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_1]] {uniq_name = "_QFFtest_scalar_lhs_finalizationEs2"} : (!fir.ref>) -> !fir.ref> + // CHECK: %[[VAL_4:.*]] = fir.embox %[[VAL_2]] : (!fir.ref>) -> !fir.box> -// CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (!fir.box>) -> !fir.box -// CHECK: %[[VAL_6:.*]] = fir.call @_FortranADestroy(%[[VAL_5]]) : (!fir.box) -> none -// CHECK: %[[VAL_7:.*]] = fir.field_index val, !fir.type<_QMa8vTt1{val:i32}> -// CHECK: %[[VAL_8:.*]] = fir.coordinate_of %[[VAL_3]], %[[VAL_7]] : (!fir.ref>, !fir.field) -> !fir.ref -// CHECK: %[[VAL_9:.*]] = fir.field_index val, !fir.type<_QMa8vTt1{val:i32}> -// CHECK: %[[VAL_10:.*]] = fir.coordinate_of %[[VAL_2]], %[[VAL_9]] : (!fir.ref>, !fir.field) -> !fir.ref -// CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_8]] : !fir.ref -// CHECK: fir.store %[[VAL_11]] to %[[VAL_10]] : !fir.ref +// CHECK: %[[VAL_5:.*]] = fir.embox %[[VAL_3]] : (!fir.ref>) -> !fir.box> +// CHECK: fir.store %[[VAL_4]] to %[[BOX]] : !fir.ref>> +// CHECK: %[[VAL_10:.*]] = fir.convert %[[BOX]] : (!fir.ref>>) -> !fir.ref> +// CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_5]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_12:.*]] = fir.convert %{{.*}} : (!fir.ref>) -> !fir.ref +// CHECK: %[[VAL_13:.*]] = fir.call @_FortranAAssign(%[[VAL_10]], %[[VAL_11]], %[[VAL_12]], %{{.*}}) : (!fir.ref>, !fir.box, !fir.ref, i32) -> none // CHECK: return // CHECK: } -// Check that Destroy() is not called for temporary LHS. +// Check that Assign() or Destroy() is not called for temporary LHS. func.func @_QFPtest_scalar_temp_lhs_no_finalization(%arg0: !fir.ref> {fir.bindc_name = "s1"}, %arg1: !fir.ref> {fir.bindc_name = "s2"}) { %0:2 = hlfir.declare %arg0 {uniq_name = "_QFFtest_scalar_lhs_finalizationEs1"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) %1:2 = hlfir.declare %arg1 {uniq_name = "_QFFtest_scalar_lhs_finalizationEs2"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) @@ -369,6 +369,7 @@ func.func @_QFPtest_scalar_temp_lhs_no_finalization(%arg0: !fir.ref> {fir.bindc_name = "y"}) { diff --git a/flang/test/HLFIR/c-null-ptr-init.f90 b/flang/test/HLFIR/c-null-ptr-init.f90 new file mode 100644 index 0000000000000..379b8ccbe855c --- /dev/null +++ b/flang/test/HLFIR/c-null-ptr-init.f90 @@ -0,0 +1,19 @@ +! Test lowering of C_NULL_PTR in structure constructor initial value. +! RUN: bbc -emit-hlfir -o - %s | FileCheck %s +subroutine test + use, intrinsic :: iso_c_binding, only : c_ptr, c_null_ptr + type t + type(c_ptr) :: ptr + end type t + type(t) :: x = t(c_null_ptr) +end subroutine +! CHECK-LABEL: fir.global internal @_QFtestEx : !fir.type<_QFtestTt{ptr:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}> { +! CHECK: %[[VAL_0:.*]] = fir.undefined !fir.type<_QFtestTt{ptr:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}> +! CHECK: %[[VAL_1:.*]] = fir.field_index ptr, !fir.type<_QFtestTt{ptr:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}> +! CHECK: %[[VAL_2:.*]] = fir.undefined !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}> +! CHECK: %[[VAL_3:.*]] = fir.field_index __address, !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}> +! CHECK: %[[VAL_4:.*]] = arith.constant 0 : i64 +! CHECK: %[[VAL_5:.*]] = fir.insert_value %[[VAL_2]], %[[VAL_4]], ["__address", !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>] : (!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>, i64) -> !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}> +! CHECK: %[[VAL_6:.*]] = fir.insert_value %[[VAL_0]], %[[VAL_5]], ["ptr", !fir.type<_QFtestTt{ptr:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>] : (!fir.type<_QFtestTt{ptr:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>, !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>) -> !fir.type<_QFtestTt{ptr:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}> +! CHECK: fir.has_value %[[VAL_6]] : !fir.type<_QFtestTt{ptr:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}> +! CHECK: } diff --git a/flang/test/HLFIR/convert-assign-inside-openacc-recipe.fir b/flang/test/HLFIR/convert-assign-inside-openacc-recipe.fir new file mode 100644 index 0000000000000..5a272bb95cc27 --- /dev/null +++ b/flang/test/HLFIR/convert-assign-inside-openacc-recipe.fir @@ -0,0 +1,51 @@ +// Check that hlfir.assign codegen is able to insert fir.alloca's inside +// the regions of the OpenACC recipe. +// RUN: fir-opt %s -convert-hlfir-to-fir | FileCheck %s + +acc.reduction.recipe @reduction_add_box_heap_Uxi32 : !fir.box>> reduction_operator init { +^bb0(%arg0: !fir.box>>): + %c0_i32 = arith.constant 0 : i32 + %c0 = arith.constant 0 : index + %0:3 = fir.box_dims %arg0, %c0 : (!fir.box>>, index) -> (index, index, index) + %1 = fir.shape %0#1 : (index) -> !fir.shape<1> + %2 = fir.allocmem !fir.array, %0#1 {bindc_name = ".tmp", uniq_name = ""} + %3:2 = hlfir.declare %2(%1) {uniq_name = ".tmp"} : (!fir.heap>, !fir.shape<1>) -> (!fir.box>, !fir.heap>) + hlfir.assign %c0_i32 to %3#0 : i32, !fir.box> + acc.yield %3#0 : !fir.box> +} combiner { +^bb0(%arg0: !fir.box>>, %arg1: !fir.box>>, %arg2: index, %arg3: index, %arg4: index): + %c1 = arith.constant 1 : index + %c0 = arith.constant 0 : index + %0 = arith.subi %arg3, %arg2 : index + %1 = arith.addi %0, %c1 : index + %2 = arith.divsi %1, %arg4 : index + %3 = arith.cmpi sgt, %2, %c0 : index + %4 = arith.select %3, %2, %c0 : index + %5 = fir.shape %4 : (index) -> !fir.shape<1> + %6 = hlfir.designate %arg0 (%arg2:%arg3:%arg4) shape %5 : (!fir.box>>, index, index, index, !fir.shape<1>) -> !fir.box>> + %7 = hlfir.designate %arg1 (%arg2:%arg3:%arg4) shape %5 : (!fir.box>>, index, index, index, !fir.shape<1>) -> !fir.box>> + %8 = fir.allocmem !fir.array, %4 {bindc_name = ".tmp.array", uniq_name = ""} + %9:2 = hlfir.declare %8(%5) {uniq_name = ".tmp.array"} : (!fir.heap>, !fir.shape<1>) -> (!fir.box>, !fir.heap>) + %true = arith.constant true + %c1_0 = arith.constant 1 : index + fir.do_loop %arg5 = %c1_0 to %4 step %c1_0 unordered { + %13 = hlfir.designate %6 (%arg5) : (!fir.box>>, index) -> !fir.ref + %14 = hlfir.designate %7 (%arg5) : (!fir.box>>, index) -> !fir.ref + %15 = fir.load %13 : !fir.ref + %16 = fir.load %14 : !fir.ref + %17 = arith.addi %15, %16 : i32 + %18 = hlfir.designate %9#0 (%arg5) : (!fir.box>, index) -> !fir.ref + hlfir.assign %17 to %18 temporary_lhs : i32, !fir.ref + } + %10 = fir.undefined tuple>, i1> + %11 = fir.insert_value %10, %true, [1 : index] : (tuple>, i1>, i1) -> tuple>, i1> + %12 = fir.insert_value %11, %9#0, [0 : index] : (tuple>, i1>, !fir.box>) -> tuple>, i1> + hlfir.assign %9#0 to %arg0 : !fir.box>, !fir.box>> + acc.yield %arg0 : !fir.box>> +} +// CHECK-LABEL: acc.reduction.recipe @reduction_add_box_heap_Uxi32 : !fir.box>> reduction_operator init { +// CHECK: ^bb0(%[[VAL_0:.*]]: !fir.box>>): +// CHECK: %[[VAL_1:.*]] = fir.alloca !fir.box> +// CHECK-LABEL: } combiner { +// CHECK: ^bb0(%[[VAL_0:.*]]: !fir.box>>, %[[VAL_1:.*]]: !fir.box>>, %[[VAL_2:.*]]: index, %[[VAL_3:.*]]: index, %[[VAL_4:.*]]: index): +// CHECK: %[[VAL_5:.*]] = fir.alloca !fir.box>> diff --git a/flang/test/Lower/Arm/arm-sve-vector-bits-vscale-range.f90 b/flang/test/Lower/Arm/arm-sve-vector-bits-vscale-range.f90 new file mode 100644 index 0000000000000..9e09a41198626 --- /dev/null +++ b/flang/test/Lower/Arm/arm-sve-vector-bits-vscale-range.f90 @@ -0,0 +1,24 @@ +! REQUIRES: aarch64-registered-target +! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=1 -mvscale-max=1 -emit-llvm -o - %s | FileCheck %s -D#VBITS=1 +! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=2 -mvscale-max=2 -emit-llvm -o - %s | FileCheck %s -D#VBITS=2 +! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=4 -mvscale-max=4 -emit-llvm -o - %s | FileCheck %s -D#VBITS=4 +! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=8 -mvscale-max=8 -emit-llvm -o - %s | FileCheck %s -D#VBITS=8 +! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=16 -mvscale-max=16 -emit-llvm -o - %s | FileCheck %s -D#VBITS=16 +! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve2 -mvscale-min=1 -mvscale-max=1 -emit-llvm -o - %s | FileCheck %s -D#VBITS=1 +! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve2 -mvscale-min=2 -mvscale-max=2 -emit-llvm -o - %s | FileCheck %s -D#VBITS=2 +! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=1 -emit-llvm -o - %s | FileCheck %s -D#VBITS=1 --check-prefix=CHECK-NOMAX +! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=2 -emit-llvm -o - %s | FileCheck %s -D#VBITS=2 --check-prefix=CHECK-NOMAX +! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=4 -emit-llvm -o - %s | FileCheck %s -D#VBITS=4 --check-prefix=CHECK-NOMAX +! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=8 -emit-llvm -o - %s | FileCheck %s -D#VBITS=8 --check-prefix=CHECK-NOMAX +! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=16 -emit-llvm -o - %s | FileCheck %s -D#VBITS=16 --check-prefix=CHECK-NOMAX +! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve2 -mvscale-min=1 -mvscale-max=0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-UNBOUNDED +! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=1 -mvscale-max=0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-UNBOUNDED +! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-NONE + +! CHECK-LABEL: @func_() #0 +! CHECK: attributes #0 = {{{.*}} vscale_range([[#VBITS]],[[#VBITS]]) {{.*}}} +! CHECK-NOMAX: attributes #0 = {{{.*}} vscale_range([[#VBITS]],0) {{.*}}} +! CHECK-UNBOUNDED: attributes #0 = {{{.*}} vscale_range(1,0) {{.*}}} +! CHECK-NONE: attributes #0 = {{{.*}} vscale_range(1,16) {{.*}}} +subroutine func +end subroutine func diff --git a/flang/test/Lower/HLFIR/charconvert.f90 b/flang/test/Lower/HLFIR/charconvert.f90 new file mode 100644 index 0000000000000..9b9c8670077dd --- /dev/null +++ b/flang/test/Lower/HLFIR/charconvert.f90 @@ -0,0 +1,71 @@ +! Test lowering of character concatenation to HLFIR +! RUN: bbc -emit-hlfir -o - %s 2>&1 | FileCheck %s + +subroutine charconvert1(c,n) + character(*,4),intent(in) :: c(:) + integer,intent(in) :: n + interface + subroutine callee(c) + character(*),intent(in) :: c(:) + end subroutine callee + end interface + call show([character(n)::c]) +end subroutine charconvert1 + +! CHECK-LABEL: func.func @_QPcharconvert1 +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFcharconvert1Ec"} : (!fir.box>>) -> (!fir.box>>, !fir.box>>) +! CHECK: ^bb0(%[[ARG2:.*]]: index): +! CHECK: %[[VAL_37:.*]] = fir.box_elesize %[[VAL_2]]#1 : (!fir.box>>) -> index +! CHECK: %[[C4_4:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_38:.*]] = arith.divsi %[[VAL_37]], %[[C4_4]] : index +! CHECK: %[[VAL_39:.*]] = hlfir.designate %[[VAL_2]]#0 (%[[ARG2]]) typeparams %[[VAL_38]] : (!fir.box>>, index, index) -> !fir.boxchar<4> +! CHECK: %[[C4_5:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_40:.*]] = arith.muli %[[VAL_38]], %[[C4_5]] : index +! CHECK: %[[VAL_41:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_40]] : index) +! CHECK: %[[VAL_42:.*]]:2 = fir.unboxchar %[[VAL_39]] : (!fir.boxchar<4>) -> (!fir.ref>, index) +! CHECK: fir.char_convert %[[VAL_42]]#0 for %[[VAL_38:.*]] to %[[VAL_41]] : !fir.ref>, index, !fir.ref> + +subroutine charconvert2(x) + integer,intent(in) :: x + character(kind=4) :: cx + cx = achar(x) +end subroutine charconvert2 +! CHECK-LABEL: func.func @_QPcharconvert2 +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref +! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.char<1> +! CHECK: %[[C1:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.char<4> {bindc_name = "cx", uniq_name = "_QFcharconvert2Ecx"} +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] typeparams %[[C1]] {uniq_name = "_QFcharconvert2Ecx"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[ARG0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFcharconvert2Ex"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref +! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i32) -> i64 +! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (i64) -> i8 +! CHECK: %[[VAL_7:.*]] = fir.undefined !fir.char<1> +! CHECK: %[[VAL_8:.*]] = fir.insert_value %[[VAL_7]], %[[VAL_6]], [0 : index] : (!fir.char<1>, i8) -> !fir.char<1> +! CHECK: fir.store %[[VAL_8:.*]] to %[[VAL_0]] : !fir.ref> +! CHECK: %[[FALSE:.*]] = arith.constant false +! CHECK: %[[VAL_9:.*]] = hlfir.as_expr %[[VAL_0]] move %[[FALSE]] : (!fir.ref>, i1) -> !hlfir.expr> +! CHECK: %[[C1_0:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_10:.*]] = fir.alloca !fir.char<4,?>(%[[C1_0]] : index) +! CHECK: fir.char_convert %[[VAL_0:.*]] for %[[C1_0]] to %[[VAL_10]] : !fir.ref>, index, !fir.ref> + +subroutine charconvert3(c, c4) + character(kind=1, len=*) :: c + character(kind=4, len=*) :: c4 + c4 = c // c +end subroutine + +! CHECK-LABEL: func.func @_QPcharconvert3 +! CHECK-SAME: %[[ARG0:.*]]: !fir.boxchar<1> {{.*}}, %[[ARG1:.*]]: !fir.boxchar<4> +! CHECK: %[[VAL_0:.*]]:2 = fir.unboxchar %[[ARG0]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]]#0 typeparams %[[VAL_0]]#1 {uniq_name = "_QFcharconvert3Ec"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) +! CHECK: %[[VAL_2:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<4>) -> (!fir.ref>, index) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]]#0 typeparams %[[VAL_2]]#1 {uniq_name = "_QFcharconvert3Ec4"} : (!fir.ref>, index) -> (!fir.boxchar<4>, !fir.ref>) +! CHECK: %[[VAL_4:.*]] = arith.addi %[[VAL_0]]#1, %[[VAL_0]]#1 : index +! CHECK: %[[VAL_5:.*]] = hlfir.concat %[[VAL_1]]#0, %[[VAL_1]]#0 len %[[VAL_4]] : (!fir.boxchar<1>, !fir.boxchar<1>, index) -> !hlfir.expr> +! CHECK: %[[VAL_6:.*]] = fir.alloca !fir.char<4,?>(%[[VAL_4]] : index) +! CHECK: %[[VAL_7:.*]]:3 = hlfir.associate %[[VAL_5]] typeparams %[[VAL_4]] {uniq_name = "adapt.valuebyref"} : (!hlfir.expr>, index) -> (!fir.boxchar<1>, !fir.ref>, i1) +! CHECK: fir.char_convert %[[VAL_7]]#1 for %[[VAL_4:.*]] to %[[VAL_6]] : !fir.ref>, index, !fir.ref> +! CHECK: hlfir.end_associate %[[VAL_7]]#1, %[[VAL_7]]#2 : !fir.ref>, i1 +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_6]] typeparams %[[VAL_4]] {uniq_name = "ctor.temp"} : (!fir.ref>, index) -> (!fir.boxchar<4>, !fir.ref>) +! CHECK: hlfir.assign %[[VAL_8]]#0 to %[[VAL_3]]#0 : !fir.boxchar<4>, !fir.boxchar<4> \ No newline at end of file diff --git a/flang/test/Lower/HLFIR/elemental-call-vector-subscripts.f90 b/flang/test/Lower/HLFIR/elemental-call-vector-subscripts.f90 new file mode 100644 index 0000000000000..b8f7ee9338fbd --- /dev/null +++ b/flang/test/Lower/HLFIR/elemental-call-vector-subscripts.f90 @@ -0,0 +1,93 @@ +! Test passing of vector subscripted entities inside elemental +! procedures. +! RUN: bbc --emit-hlfir -o - %s | FileCheck %s + +subroutine test() + interface + elemental subroutine foo(x, y) + real, intent(in) :: x + real, value :: y + end subroutine + end interface + real :: x(10) + call foo(x([1,3,7]), 0.) +end subroutine +! CHECK-LABEL: func.func @_QPtest() { +! CHECK: %[[VAL_0:.*]] = arith.constant 10 : index +! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.array<10xf32> {bindc_name = "x", uniq_name = "_QFtestEx"} +! CHECK: %[[VAL_2:.*]] = fir.shape %[[VAL_0]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]](%[[VAL_2]]) {uniq_name = "_QFtestEx"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_4:.*]] = fir.address_of(@_QQro.3xi8.0) : !fir.ref> +! CHECK: %[[VAL_5:.*]] = arith.constant 3 : index +! CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_5]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_4]](%[[VAL_6]]) +! CHECK: %[[VAL_8:.*]] = arith.constant 3 : index +! CHECK: %[[VAL_9:.*]] = arith.constant 0.000000e+00 : f32 +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : index +! CHECK: fir.do_loop %[[VAL_11:.*]] = %[[VAL_10]] to %[[VAL_8]] step %[[VAL_10]] unordered { +! CHECK: %[[VAL_12:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_11]]) : (!fir.ref>, index) -> !fir.ref +! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_12]] : !fir.ref +! CHECK: %[[VAL_14:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_13]]) : (!fir.ref>, i64) -> !fir.ref +! CHECK: fir.call @_QPfoo(%[[VAL_14]], %[[VAL_9]]) {{.*}}: (!fir.ref, f32) -> () +! CHECK: } +! CHECK: return +! CHECK: } + +subroutine test_value() + interface + elemental subroutine foo_value(x, y) + real, value :: x + real, value :: y + end subroutine + end interface + real :: x(10) + call foo_value(x([1,3,7]), 0.) +end subroutine + +! CHECK-LABEL: func.func @_QPtest_value() { +! CHECK: %[[VAL_0:.*]] = arith.constant 10 : index +! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.array<10xf32> {bindc_name = "x", uniq_name = "_QFtest_valueEx"} +! CHECK: %[[VAL_2:.*]] = fir.shape %[[VAL_0]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]](%[[VAL_2]]) {uniq_name = "_QFtest_valueEx"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_4:.*]] = fir.address_of(@_QQro.3xi8.0) : !fir.ref> +! CHECK: %[[VAL_5:.*]] = arith.constant 3 : index +! CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_5]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_4]](%[[VAL_6]]) +! CHECK: %[[VAL_8:.*]] = arith.constant 3 : index +! CHECK: %[[VAL_9:.*]] = fir.shape %[[VAL_8]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_10:.*]] = hlfir.elemental %[[VAL_9]] unordered : (!fir.shape<1>) -> !hlfir.expr<3xf32> { +! CHECK: ^bb0(%[[VAL_11:.*]]: index): +! CHECK: %[[VAL_12:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_11]]) : (!fir.ref>, index) -> !fir.ref +! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_12]] : !fir.ref +! CHECK: %[[VAL_14:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_13]]) : (!fir.ref>, i64) -> !fir.ref +! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_14]] : !fir.ref +! CHECK: hlfir.yield_element %[[VAL_15]] : f32 +! CHECK: } +! CHECK: %[[VAL_16:.*]] = arith.constant 0.000000e+00 : f32 +! CHECK: %[[VAL_17:.*]] = arith.constant 1 : index +! CHECK: fir.do_loop %[[VAL_18:.*]] = %[[VAL_17]] to %[[VAL_8]] step %[[VAL_17]] unordered { +! CHECK: %[[VAL_19:.*]] = hlfir.apply %[[VAL_10]], %[[VAL_18]] : (!hlfir.expr<3xf32>, index) -> f32 +! CHECK: fir.call @_QPfoo_value(%[[VAL_19]], %[[VAL_16]]) {{.*}}: (f32, f32) -> () +! CHECK: } +! CHECK: hlfir.destroy %[[VAL_10]] : !hlfir.expr<3xf32> +! CHECK: return + +subroutine test_not_a_variable(i) + interface + elemental subroutine foo2(j) + integer(8), intent(in) :: j + end subroutine + end interface + integer(8) :: i(:) + call foo2((i(i))) +end subroutine +! CHECK-LABEL: func.func @_QPtest_not_a_variable( +! CHECK: hlfir.elemental +! CHECK: %[[VAL_16:.*]] = hlfir.elemental +! CHECK: %[[VAL_20:.*]] = arith.constant 1 : index +! CHECK: fir.do_loop %[[VAL_21:.*]] = {{.*}} +! CHECK: %[[VAL_22:.*]] = hlfir.apply %[[VAL_16]], %[[VAL_21]] : (!hlfir.expr, index) -> i64 +! CHECK: %[[VAL_23:.*]]:3 = hlfir.associate %[[VAL_22]] {uniq_name = "adapt.valuebyref"} : (i64) -> (!fir.ref, !fir.ref, i1) +! CHECK: fir.call @_QPfoo2(%[[VAL_23]]#1){{.*}}: (!fir.ref) -> () +! CHECK: hlfir.end_associate %[[VAL_23]]#1, %[[VAL_23]]#2 : !fir.ref, i1 +! CHECK: } diff --git a/flang/test/Lower/HLFIR/procedure-designators-arg-attrs.f90 b/flang/test/Lower/HLFIR/procedure-designators-arg-attrs.f90 new file mode 100644 index 0000000000000..091d4185b5095 --- /dev/null +++ b/flang/test/Lower/HLFIR/procedure-designators-arg-attrs.f90 @@ -0,0 +1,17 @@ +! Ensure that func.func arguments are given the Fortran attributes +! even if their first use is in a procedure designator reference +! and not a call. + +! RUN: bbc -emit-hlfir -o - %s | FileCheck %s + +subroutine test(x) + interface + subroutine foo(x) + integer, optional, target :: x + end subroutine + end interface + integer, optional, target :: x + call takes_proc(foo) + call foo(x) +end subroutine +! CHECK: func.func private @_QPfoo(!fir.ref {fir.optional, fir.target}) diff --git a/flang/test/Lower/HLFIR/type-info.f90 b/flang/test/Lower/HLFIR/type-info.f90 new file mode 100644 index 0000000000000..e0716fd069020 --- /dev/null +++ b/flang/test/Lower/HLFIR/type-info.f90 @@ -0,0 +1,60 @@ +! Test generation of noinit, nofinal, and nodestroy fir.type_info attributes +! RUN: bbc -emit-hlfir %s -o - | FileCheck %s + +module tyinfo + type boring_type + end type + + type needs_final + contains + final :: needs_final_final + end type + + type needs_init1 + integer :: i =0 + end type + + type needs_init_and_destroy + integer, allocatable :: x + end type + + type needs_all + type(needs_final) :: x + type(needs_init_and_destroy) :: y + end type + + type, extends(needs_final) :: inherits_final + end type + type, extends(needs_init1) :: inherits_init + end type + type, extends(needs_init_and_destroy) :: inherits_init_and_destroy + end type + type, extends(needs_all) :: inherits_all + end type + + interface + subroutine needs_final_final(x) + type(needs_final), intent(inout) :: x + end subroutine + end interface + + type(boring_type) :: x1 + type(needs_final) :: x2 + type(needs_init1) :: x3 + type(needs_init_and_destroy) :: x4 + type(needs_all) :: x5 + type(inherits_final) :: x6 + type(inherits_init) :: x7 + type(inherits_init_and_destroy) :: x8 + type(inherits_all) :: x9 +end module + +! CHECK-DAG: fir.type_info @_QMtyinfoTboring_type noinit nodestroy nofinal : !fir.type<_QMtyinfoTboring_type> +! CHECK-DAG: fir.type_info @_QMtyinfoTneeds_final noinit : !fir.type<_QMtyinfoTneeds_final> +! CHECK-DAG: fir.type_info @_QMtyinfoTneeds_init1 nodestroy nofinal : !fir.type<_QMtyinfoTneeds_init1{i:i32}> +! CHECK-DAG: fir.type_info @_QMtyinfoTneeds_init_and_destroy nofinal : !fir.type<_QMtyinfoTneeds_init_and_destroy{x:!fir.box>}> +! CHECK-DAG: fir.type_info @_QMtyinfoTneeds_all : !fir.type<_QMtyinfoTneeds_all{x:!fir.type<_QMtyinfoTneeds_final>,y:!fir.type<_QMtyinfoTneeds_init_and_destroy{x:!fir.box>}>}> +! CHECK-DAG: fir.type_info @_QMtyinfoTinherits_final noinit extends !fir.type<_QMtyinfoTneeds_final> : !fir.type<_QMtyinfoTinherits_final> +! CHECK-DAG: fir.type_info @_QMtyinfoTinherits_init nodestroy nofinal extends !fir.type<_QMtyinfoTneeds_init1{i:i32}> : !fir.type<_QMtyinfoTinherits_init{i:i32}> +! CHECK-DAG: fir.type_info @_QMtyinfoTinherits_init_and_destroy nofinal extends !fir.type<_QMtyinfoTneeds_init_and_destroy{x:!fir.box>}> : !fir.type<_QMtyinfoTinherits_init_and_destroy{x:!fir.box>}> +! CHECK-DAG: fir.type_info @_QMtyinfoTinherits_all extends !fir.type<_QMtyinfoTneeds_all{x:!fir.type<_QMtyinfoTneeds_final>,y:!fir.type<_QMtyinfoTneeds_init_and_destroy{x:!fir.box>}>}> : !fir.type<_QMtyinfoTinherits_all{x:!fir.type<_QMtyinfoTneeds_final>,y:!fir.type<_QMtyinfoTneeds_init_and_destroy{x:!fir.box>}>}> diff --git a/flang/test/Lower/OpenACC/acc-enter-data.f90 b/flang/test/Lower/OpenACC/acc-enter-data.f90 index 21847d462c2e1..93418a1fca3ec 100644 --- a/flang/test/Lower/OpenACC/acc-enter-data.f90 +++ b/flang/test/Lower/OpenACC/acc-enter-data.f90 @@ -179,7 +179,7 @@ subroutine acc_enter_data !CHECK: %[[ONE:.*]] = arith.constant 1 : index !CHECK: %[[LB1:.*]] = arith.constant 0 : index !CHECK: %[[UB1:.*]] = arith.subi %c10{{.*}}, %[[ONE]] : index -!CHECK: %[[BOUND1:.*]] = acc.bounds lowerbound(%[[LB1]] : index) upperbound(%[[UB1]] : index) stride(%[[ONE]] : index) startIdx(%c1{{.*}} : index) +!CHECK: %[[BOUND1:.*]] = acc.bounds lowerbound(%[[LB1]] : index) upperbound(%[[UB1]] : index) extent(%c10{{.*}} : index) stride(%[[ONE]] : index) startIdx(%c1{{.*}} : index) !CHECK: %[[LB2:.*]] = arith.constant 0 : index !CHECK: %[[UB2:.*]] = arith.constant 4 : index !CHECK: %[[BOUND2:.*]] = acc.bounds lowerbound(%[[LB2]] : index) upperbound(%[[UB2]] : index) stride(%[[ONE]] : index) startIdx(%c1{{.*}} : index) @@ -203,9 +203,9 @@ subroutine acc_enter_data !CHECK: %[[LB:.*]] = arith.constant 0 : index !CHECK: %[[ONE:.*]] = arith.constant 1 : index !CHECK: %[[UB:.*]] = arith.subi %c10{{.*}}, %[[ONE]] : index -!CHECK: %[[BOUND1:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[ONE]] : index) -!CHECK: %[[UB:.*]] = arith.subi %{{.*}}, %[[ONE]] : index -!CHECK: %[[BOUND2:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[ONE]] : index) +!CHECK: %[[BOUND1:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) extent(%c10{{.*}} : index) stride(%[[ONE]] : index) startIdx(%[[ONE]] : index) +!CHECK: %[[UB:.*]] = arith.subi %c10{{.*}}, %[[ONE]] : index +!CHECK: %[[BOUND2:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) extent(%c10{{.*}} : index) stride(%[[ONE]] : index) startIdx(%[[ONE]] : index) !FIR: %[[COPYIN_A:.*]] = acc.copyin varPtr(%[[A]] : !fir.ref>) bounds(%[[BOUND1]], %[[BOUND2]]) -> !fir.ref> {name = "a(:,:)", structured = false} !HLFIR: %[[COPYIN_A:.*]] = acc.copyin varPtr(%[[DECLA]]#1 : !fir.ref>) bounds(%[[BOUND1]], %[[BOUND2]]) -> !fir.ref> {name = "a(:,:)", structured = false} end subroutine acc_enter_data @@ -282,7 +282,7 @@ subroutine acc_enter_data_dummy(a, b, n, m) !CHECK: %[[LB:.*]] = arith.subi %[[CONVERT_N]], %[[N_IDX]] : index !CHECK: %[[LBEXT:.*]] = arith.addi %[[EXT_B]], %[[N_IDX]] : index !CHECK: %[[UB:.*]] = arith.subi %[[LBEXT:.*]], %[[ONE]] : index -!CHECK: %[[BOUND1:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[N_IDX]] : index) +!CHECK: %[[BOUND1:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) extent(%[[EXT_B]] : index) stride(%[[ONE]] : index) startIdx(%[[N_IDX]] : index) !FIR: %[[CREATE1:.*]] = acc.create varPtr(%[[B]] : !fir.ref>) bounds(%[[BOUND1]]) -> !fir.ref> {name = "b(n:)", structured = false} !HLFIR: %[[CREATE1:.*]] = acc.create varPtr(%[[DECLB]]#1 : !fir.ref>) bounds(%[[BOUND1]]) -> !fir.ref> {name = "b(n:)", structured = false} !CHECK: acc.enter_data dataOperands(%[[CREATE1]] : !fir.ref>) @@ -291,7 +291,7 @@ subroutine acc_enter_data_dummy(a, b, n, m) !CHECK: %[[ONE:.*]] = arith.constant 1 : index !CHECK: %[[LBEXT:.*]] = arith.addi %[[EXT_B]], %[[N_IDX]] : index !CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[ONE]] : index -!CHECK: %[[BOUND1:.*]] = acc.bounds lowerbound(%[[N_IDX]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[N_IDX]] : index) +!CHECK: %[[BOUND1:.*]] = acc.bounds lowerbound(%[[N_IDX]] : index) upperbound(%[[UB]] : index) extent(%[[EXT_B]] : index) stride(%[[ONE]] : index) startIdx(%[[N_IDX]] : index) !FIR: %[[CREATE1:.*]] = acc.create varPtr(%[[B]] : !fir.ref>) bounds(%[[BOUND1]]) -> !fir.ref> {name = "b(:)", structured = false} !HLFIR: %[[CREATE1:.*]] = acc.create varPtr(%[[DECLB]]#1 : !fir.ref>) bounds(%[[BOUND1]]) -> !fir.ref> {name = "b(:)", structured = false} !CHECK: acc.enter_data dataOperands(%[[CREATE1]] : !fir.ref>) @@ -326,7 +326,7 @@ subroutine acc_enter_data_non_default_lb() !CHECK: %[[ONE:.*]] = arith.constant 1 : index !CHECK: %[[LBEXT:.*]] = arith.addi %[[EXTENT_C10]], %[[BASELB]] : index !CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[ONE]] : index -!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[BASELB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[BASELB]] : index) +!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[BASELB]] : index) upperbound(%[[UB]] : index) extent(%[[EXTENT_C10]] : index) stride(%[[ONE]] : index) startIdx(%[[BASELB]] : index) !FIR: %[[CREATE:.*]] = acc.create varPtr(%[[A]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "a(:)", structured = false} !HLFIR: %[[CREATE:.*]] = acc.create varPtr(%[[DECLA]]#1 : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "a(:)", structured = false} !CHECK: acc.enter_data dataOperands(%[[CREATE]] : !fir.ref>) @@ -346,7 +346,7 @@ subroutine acc_enter_data_non_default_lb() !CHECK: %[[LB:.*]] = arith.subi %[[SECTIONLB]], %[[BASELB]] : index !CHECK: %[[LBEXT:.*]] = arith.addi %[[EXTENT_C10]], %[[BASELB]] : index !CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[ONE]] : index -!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[BASELB]] : index) +!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) extent(%[[EXTENT_C10]] : index) stride(%[[ONE]] : index) startIdx(%[[BASELB]] : index) !FIR: %[[CREATE:.*]] = acc.create varPtr(%[[A]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "a(4:)", structured = false} !HLFIR: %[[CREATE:.*]] = acc.create varPtr(%[[DECLA]]#1 : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "a(4:)", structured = false} !CHECK: acc.enter_data dataOperands(%[[CREATE]] : !fir.ref>) @@ -400,7 +400,7 @@ subroutine acc_enter_data_assumed(a, b, n, m) !FIR: %[[DIMS1:.*]]:3 = fir.box_dims %[[A]], %[[C0]] : (!fir.box>, index) -> (index, index, index) !HLFIR: %[[DIMS1:.*]]:3 = fir.box_dims %[[DECLA]]#1, %[[C0]] : (!fir.box>, index) -> (index, index, index) !CHECK: %[[UB:.*]] = arith.subi %[[DIMS1]]#1, %[[ONE]] : index -!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[DIMS0]]#2 : index) startIdx(%[[ONE]] : index) {strideInBytes = true} +!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) extent(%[[DIMS1]]#1 : index) stride(%[[DIMS0]]#2 : index) startIdx(%[[ONE]] : index) {strideInBytes = true} !FIR: %[[BOX_ADDR:.*]] = fir.box_addr %[[A]] : (!fir.box>) -> !fir.ref> !HLFIR: %[[BOX_ADDR:.*]] = fir.box_addr %[[DECLA]]#1 : (!fir.box>) -> !fir.ref> !CHECK: %[[CREATE:.*]] = acc.create varPtr(%[[BOX_ADDR]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "a(:)", structured = false} @@ -416,7 +416,7 @@ subroutine acc_enter_data_assumed(a, b, n, m) !FIR: %[[DIMS1:.*]]:3 = fir.box_dims %[[A]], %[[C0]] : (!fir.box>, index) -> (index, index, index) !HLFIR: %[[DIMS1:.*]]:3 = fir.box_dims %[[DECLA]]#1, %[[C0]] : (!fir.box>, index) -> (index, index, index) !CHECK: %[[UB:.*]] = arith.subi %[[DIMS1]]#1, %[[ONE]] : index -!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[DIMS0]]#2 : index) startIdx(%[[ONE]] : index) {strideInBytes = true} +!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) extent(%[[DIMS1]]#1 : index) stride(%[[DIMS0]]#2 : index) startIdx(%[[ONE]] : index) {strideInBytes = true} !FIR: %[[BOX_ADDR:.*]] = fir.box_addr %[[A]] : (!fir.box>) -> !fir.ref> !HLFIR: %[[BOX_ADDR:.*]] = fir.box_addr %[[DECLA]]#1 : (!fir.box>) -> !fir.ref> !CHECK: %[[CREATE:.*]] = acc.create varPtr(%[[BOX_ADDR]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "a(2:)", structured = false} @@ -461,7 +461,7 @@ subroutine acc_enter_data_assumed(a, b, n, m) !FIR: %[[DIMS:.*]]:3 = fir.box_dims %[[A]], %[[C0]] : (!fir.box>, index) -> (index, index, index) !HLFIR: %[[DIMS:.*]]:3 = fir.box_dims %[[DECLA]]#1, %[[C0]] : (!fir.box>, index) -> (index, index, index) !CHECK: %[[UB:.*]] = arith.subi %[[DIMS]]#1, %[[ONE]] : index -!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[DIMS0]]#2 : index) startIdx(%[[ONE]] : index) {strideInBytes = true} +!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) extent(%[[DIMS]]#1 : index) stride(%[[DIMS0]]#2 : index) startIdx(%[[ONE]] : index) {strideInBytes = true} !FIR: %[[BOX_ADDR:.*]] = fir.box_addr %[[A]] : (!fir.box>) -> !fir.ref> !HLFIR: %[[BOX_ADDR:.*]] = fir.box_addr %[[DECLA]]#1 : (!fir.box>) -> !fir.ref> !CHECK: %[[CREATE:.*]] = acc.create varPtr(%[[BOX_ADDR]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "a(n:)", structured = false} @@ -613,7 +613,7 @@ subroutine acc_enter_data_allocatable() !CHECK: %[[DIMS2:.*]]:3 = fir.box_dims %[[BOX_A_1]], %[[C0]] : (!fir.box>>, index) -> (index, index, index) !CHECK: %[[LBEXT:.*]] = arith.addi %[[DIMS2:.*]]#1, %[[DIMS0]]#0 : index !CHECK: %[[UB:.*]] = arith.subi %[[LBEXT]], %[[ONE]] : index -!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[DIMS1]]#2 : index) startIdx(%[[DIMS0]]#0 : index) {strideInBytes = true} +!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) extent(%[[DIMS2]]#1 : index) stride(%[[DIMS1]]#2 : index) startIdx(%[[DIMS0]]#0 : index) {strideInBytes = true} !CHECK: %[[BOX_ADDR:.*]] = fir.box_addr %[[BOX_A_0]] : (!fir.box>>) -> !fir.heap> !CHECK: %[[CREATE:.*]] = acc.create varPtr(%[[BOX_ADDR]] : !fir.heap>) bounds(%[[BOUND]]) -> !fir.heap> {name = "a(3:)", structured = false} !CHECK: acc.enter_data dataOperands(%[[CREATE]] : !fir.heap>) @@ -715,7 +715,7 @@ subroutine acc_enter_data_derived_type() !CHECK: %[[LB:.*]] = arith.constant 0 : index !CHECK: %[[C1:.*]] = arith.constant 1 : index !CHECK: %[[UB:.*]] = arith.subi %[[C10]], %[[C1]] : index -!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[C1]] : index) startIdx(%[[C1]] : index) +!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) extent(%[[C10]] : index) stride(%[[C1]] : index) startIdx(%[[C1]] : index) !CHECK: %[[CREATE:.*]] = acc.create varPtr(%[[ARRAY_COORD]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "a%array(:)", structured = false} !CHECK: acc.enter_data dataOperands(%[[CREATE]] : !fir.ref>) @@ -749,7 +749,7 @@ subroutine acc_enter_data_derived_type() !CHECK: %[[ONE:.*]] = arith.constant 1 : index !CHECK: %[[LB:.*]] = arith.constant 1 : index !CHECK: %[[UB:.*]] = arith.subi %[[C10]], %[[ONE]] : index -!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[ONE]] : index) startIdx(%[[ONE]] : index) +!CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) extent(%[[C10]] : index) stride(%[[ONE]] : index) startIdx(%[[ONE]] : index) !CHECK: %[[CREATE:.*]] = acc.create varPtr(%[[ARRAY_COORD]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "a%array(2:)", structured = false} !CHECK: acc.enter_data dataOperands(%[[CREATE]] : !fir.ref>) diff --git a/flang/test/Lower/OpenACC/acc-parallel-loop.f90 b/flang/test/Lower/OpenACC/acc-parallel-loop.f90 index 22726b0f49094..4123211e2f49e 100644 --- a/flang/test/Lower/OpenACC/acc-parallel-loop.f90 +++ b/flang/test/Lower/OpenACC/acc-parallel-loop.f90 @@ -5,8 +5,8 @@ ! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_10xf32 : !fir.ref> init { ! CHECK: ^bb0(%{{.*}}: !fir.ref>): -! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10xf32> ! HLFIR: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1> +! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10xf32> ! HLFIR: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.ref> ! CHECK: } copy { diff --git a/flang/test/Lower/OpenACC/acc-parallel.f90 b/flang/test/Lower/OpenACC/acc-parallel.f90 index cdde9128d70c9..9e48cb1a43712 100644 --- a/flang/test/Lower/OpenACC/acc-parallel.f90 +++ b/flang/test/Lower/OpenACC/acc-parallel.f90 @@ -5,8 +5,8 @@ ! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_10x10xf32 : !fir.ref> init { ! CHECK: ^bb0(%{{.*}}: !fir.ref>): -! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10x10xf32> ! HLFIR: %[[SHAPE:.*]] = fir.shape %{{.*}}, %{{.*}} : (index, index) -> !fir.shape<2> +! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10x10xf32> ! HLFIR: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) ! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.ref> ! CHECK: } copy { diff --git a/flang/test/Lower/OpenACC/acc-private.f90 b/flang/test/Lower/OpenACC/acc-private.f90 index 6c71a9bc72ff3..cfec2e43930c4 100644 --- a/flang/test/Lower/OpenACC/acc-private.f90 +++ b/flang/test/Lower/OpenACC/acc-private.f90 @@ -3,6 +3,34 @@ ! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s --check-prefixes=CHECK,FIR ! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,HLFIR +! CHECK-LABEL: acc.private.recipe @privatization_ref_UxUx2xi32 : !fir.ref> init { +! CHECK: ^bb0(%[[ARG0:.*]]: !fir.ref>, %[[ARG1:.*]]: index, %[[ARG2:.*]]: index, %[[ARG3:.*]]: index): +! HLFIR: %[[SHAPE:.*]] = fir.shape %[[ARG1]], %[[ARG2]], %[[ARG3]] : (index, index, index) -> !fir.shape<3> +! HLFIR: %[[ALLOCA:.*]] = fir.alloca !fir.array, %[[ARG1]], %[[ARG2]], %[[ARG3]] +! HLFIR: %[[DECL:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref>, !fir.shape<3>) -> (!fir.box>, !fir.ref>) +! HLFIR: acc.yield %[[DECL]]#0 : !fir.box> +! CHECK: } + +! CHECK-LABEL: acc.private.recipe @privatization_box_ptr_Uxi32 : !fir.box>> init { +! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box>>): +! HLFIR: %[[C0:.*]] = arith.constant 0 : index +! HLFIR: %[[BOX_DIMS:.*]]:3 = fir.box_dims %arg0, %c0 : (!fir.box>>, index) -> (index, index, index) +! HLFIR: %[[SHAPE:.*]] = fir.shape %[[BOX_DIMS]]#1 : (index) -> !fir.shape<1> +! HLFIR: %[[TEMP:.*]] = fir.allocmem !fir.array, %0#1 {bindc_name = ".tmp", uniq_name = ""} +! HLFIR: %[[DECLARE:.*]]:2 = hlfir.declare %[[TEMP]](%[[SHAPE]]) {uniq_name = ".tmp"} : (!fir.heap>, !fir.shape<1>) -> (!fir.box>, !fir.heap>) +! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.box> +! CHECK: } + +! CHECK-LABEL: acc.private.recipe @privatization_box_heap_Uxi32 : !fir.box>> init { +! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box>>): +! HLFIR: %[[C0:.*]] = arith.constant 0 : index +! HLFIR: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[ARG0]], %[[C0]] : (!fir.box>>, index) -> (index, index, index) +! HLFIR: %[[SHAPE:.*]] = fir.shape %[[BOX_DIMS]]#1 : (index) -> !fir.shape<1> +! HLFIR: %[[TEMP:.*]] = fir.allocmem !fir.array, %[[BOX_DIMS]]#1 {bindc_name = ".tmp", uniq_name = ""} +! HLFIR: %[[DECLARE:.*]]:2 = hlfir.declare %[[TEMP]](%[[SHAPE]]) {uniq_name = ".tmp"} : (!fir.heap>, !fir.shape<1>) -> (!fir.box>, !fir.heap>) +! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.box> +! CHECK: } + ! CHECK-LABEL: acc.private.recipe @privatization_box_Uxi32 : !fir.box> init { ! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box>): ! HLFIR: %[[C0:.*]] = arith.constant 0 : index @@ -15,8 +43,8 @@ ! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_50xf32 : !fir.ref> init { ! CHECK: ^bb0(%{{.*}}: !fir.ref>): -! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<50xf32> ! HLFIR: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1> +! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<50xf32> ! HLFIR: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.ref> ! CHECK: } copy { @@ -35,8 +63,8 @@ ! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_100xf32 : !fir.ref> init { ! CHECK: ^bb0(%{{.*}}: !fir.ref>): -! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<100xf32> ! HLFIR: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1> +! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<100xf32> ! HLFIR: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.ref> ! CHECK: } copy { @@ -67,16 +95,16 @@ ! CHECK-LABEL: acc.private.recipe @privatization_ref_50xf32 : !fir.ref> init { ! CHECK: ^bb0(%{{.*}}: !fir.ref>): -! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<50xf32> ! HLFIR: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1> +! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<50xf32> ! HLFIR: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.ref> ! CHECK: } ! CHECK-LABEL: acc.private.recipe @privatization_ref_100xf32 : !fir.ref> init { ! CHECK: ^bb0(%{{.*}}: !fir.ref>): -! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<100xf32> ! HLFIR: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1> +! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<100xf32> ! HLFIR: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.ref> ! CHECK: } @@ -191,7 +219,60 @@ subroutine acc_private_assumed_shape(a, n) ! CHECK-LABEL: func.func @_QPacc_private_assumed_shape( ! CHECK-SAME: %[[ARG0:.*]]: !fir.box> {fir.bindc_name = "a"} -! HLFIR: %[[DECL_A:.*]]:2 = hlfir.declare %arg0 {uniq_name = "_QFacc_private_assumed_shapeEa"} : (!fir.box>) -> (!fir.box>, !fir.box>) +! HLFIR: %[[DECL_A:.*]]:2 = hlfir.declare %[[ARG0]] {uniq_name = "_QFacc_private_assumed_shapeEa"} : (!fir.box>) -> (!fir.box>, !fir.box>) ! HLFIR: %[[ADDR:.*]] = fir.box_addr %[[DECL_A]]#1 : (!fir.box>) -> !fir.ref> ! HLFIR: %[[PRIVATE:.*]] = acc.private varPtr(%[[ADDR]] : !fir.ref>) bounds(%{{.*}}) -> !fir.ref> {name = "a"} ! HLFIR: acc.parallel private(@privatization_box_Uxi32 -> %[[PRIVATE]] : !fir.ref>) { + +subroutine acc_private_allocatable_array(a, n) + integer, allocatable :: a(:) + integer :: i, n + + !$acc parallel loop private(a) + do i = 1, n + a(i) = i + end do +end subroutine + +! CHECK-LABEL: func.func @_QPacc_private_allocatable_array( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>> {fir.bindc_name = "a"} +! HLFIR: %[[DECLA_A:.*]]:2 = hlfir.declare %[[ARG0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFacc_private_allocatable_arrayEa"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) +! HLFIR: %[[BOX:.*]] = fir.load %[[DECLA_A]]#1 : !fir.ref>>> +! HLFIR: %[[BOX_ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box>>) -> !fir.heap> +! HLFIR: %[[PRIVATE:.*]] = acc.private varPtr(%[[BOX_ADDR]] : !fir.heap>) bounds(%{{.*}}) -> !fir.heap> {name = "a"} +! HLFIR: acc.parallel private(@privatization_box_heap_Uxi32 -> %[[PRIVATE]] : !fir.heap>) { + +subroutine acc_private_pointer_array(a, n) + integer, pointer :: a(:) + integer :: i, n + + !$acc parallel loop private(a) + do i = 1, n + a(i) = i + end do +end subroutine + +! CHECK-LABEL: func.func @_QPacc_private_pointer_array( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>> {fir.bindc_name = "a"}, %arg1: !fir.ref {fir.bindc_name = "n"}) { +! HLFIR: %[[DECL_A:.*]]:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFacc_private_pointer_arrayEa"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) +! HLFIR: %[[BOX:.*]] = fir.load %[[DECLA_A]]#1 : !fir.ref>>> +! HLFIR: %[[BOX_ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box>>) -> !fir.ptr> +! HLFIR: %[[PRIVATE:.*]] = acc.private varPtr(%[[BOX_ADDR]] : !fir.ptr>) bounds(%{{.*}}) -> !fir.ptr> {name = "a"} +! HLFIR: acc.parallel private(@privatization_box_ptr_Uxi32 -> %[[PRIVATE]] : !fir.ptr>) + +subroutine acc_private_dynamic_extent(a, n) + integer :: n, i + integer :: a(n, n, 2) + + !$acc parallel loop private(a) + do i = 1, n + a(i, i, 1) = i + end do +end subroutine + +! CHECK-LABEL: func.func @_QPacc_private_dynamic_extent( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref> {fir.bindc_name = "a"}, %[[ARG1:.*]]: !fir.ref {fir.bindc_name = "n"}) { +! HLFIR: %[[DECL_N:.*]]:2 = hlfir.declare %arg1 {uniq_name = "_QFacc_private_dynamic_extentEn"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! HLFIR: %[[DECL_A:.*]]:2 = hlfir.declare %[[ARG0]](%16) {uniq_name = "_QFacc_private_dynamic_extentEa"} : (!fir.ref>, !fir.shape<3>) -> (!fir.box>, !fir.ref>) +! HLFIR: %[[PRIV:.*]] = acc.private varPtr(%[[DECL_A]]#1 : !fir.ref>) bounds(%{{.*}}, %{{.*}}, %{{.*}}) -> !fir.ref> {name = "a"} +! HLFIR: acc.parallel private(@privatization_ref_UxUx2xi32 -> %[[PRIV]] : !fir.ref>) diff --git a/flang/test/Lower/OpenACC/acc-reduction.f90 b/flang/test/Lower/OpenACC/acc-reduction.f90 index c102991b48632..07979445394d9 100644 --- a/flang/test/Lower/OpenACC/acc-reduction.f90 +++ b/flang/test/Lower/OpenACC/acc-reduction.f90 @@ -3,7 +3,42 @@ ! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s --check-prefixes=CHECK,FIR ! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,HLFIR -! CHECK-LABEL: acc.reduction.recipe @reduction_add_section_lb1.ub3_ref_Uxi32 : !fir.box> reduction_operator init { +! CHECK-LABEL: acc.reduction.recipe @reduction_max_box_ptr_Uxf32 : !fir.box>> reduction_operator init { +! CHECK: ^bb0(%{{.*}}: !fir.box>>): +! CHECK: } combiner { +! CHECK: ^bb0(%{{.*}}: !fir.box>>, %{{.*}}: !fir.box>>, %{{.*}}: index, %{{.*}}: index, %{{.*}}: index): +! CHECK: } + +! CHECK-LABEL: acc.reduction.recipe @reduction_max_box_heap_Uxf32 : !fir.box>> reduction_operator init { +! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box>>): +! HLFIR: %[[CST:.*]] = arith.constant -1.401300e-45 : f32 +! HLFIR: %[[C0:.*]] = arith.constant 0 : index +! HLFIR: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[ARG0]], %[[C0]] : (!fir.box>>, index) -> (index, index, index) +! HLFIR: %[[SHAPE:.*]] = fir.shape %[[BOX_DIMS]]#1 : (index) -> !fir.shape<1> +! HLFIR: %[[TEMP:.*]] = fir.allocmem !fir.array, %[[BOX_DIMS]]#1 {bindc_name = ".tmp", uniq_name = ""} +! HLFIR: %[[DECLARE:.*]]:2 = hlfir.declare %2(%1) {uniq_name = ".tmp"} : (!fir.heap>, !fir.shape<1>) -> (!fir.box>, !fir.heap>) +! HLFIR: hlfir.assign %[[CST]] to %[[DECLARE]]#0 : f32, !fir.box> +! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.box> +! CHECK: } combiner { +! HLFIR: ^bb0(%[[ARG0:.*]]: !fir.box>>, %[[ARG1:.*]]: !fir.box>>, %[[ARG2:.*]]: index, %[[ARG3:.*]]: index, %[[ARG4:.*]]: index): +! HLFIR: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1> +! HLFIR: %[[DES_V1:.*]] = hlfir.designate %[[ARG0]] (%[[ARG2]]:%[[ARG3]]:%[[ARG4]]) shape %[[SHAPE]] : (!fir.box>>, index, index, index, !fir.shape<1>) -> !fir.box>> +! HLFIR: %[[DES_V2:.*]] = hlfir.designate %[[ARG1]] (%[[ARG2]]:%[[ARG3]]:%[[ARG4]]) shape %[[SHAPE]] : (!fir.box>>, index, index, index, !fir.shape<1>) -> !fir.box>> +! HLFIR: %[[ELEMENTAL:.*]] = hlfir.elemental %[[SHAPE]] unordered : (!fir.shape<1>) -> !hlfir.expr { +! HLFIR: ^bb0(%[[IV:.*]]: index): +! HLFIR: %[[V1:.*]] = hlfir.designate %[[DES_V1]] (%[[IV]]) : (!fir.box>>, index) -> !fir.ref +! HLFIR: %[[V2:.*]] = hlfir.designate %[[DES_V2]] (%[[IV]]) : (!fir.box>>, index) -> !fir.ref +! HLFIR: %[[LOAD_V1:.*]] = fir.load %[[V1]] : !fir.ref +! HLFIR: %[[LOAD_V2:.*]] = fir.load %[[V2]] : !fir.ref +! HLFIR: %[[CMP:.*]] = arith.cmpf ogt, %[[LOAD_V1]], %[[LOAD_V2]] : f32 +! HLFIR: %[[SELECT:.*]] = arith.select %[[CMP]], %[[LOAD_V1]], %[[LOAD_V2]] : f32 +! HLFIR: hlfir.yield_element %[[SELECT]] : f32 +! HLFIR: } +! HLFIR: hlfir.assign %[[ELEMENTAL]] to %[[ARG0]] : !hlfir.expr, !fir.box>> +! HLFIR: acc.yield %[[ARG0]] : !fir.box>> +! CHECK: } + +! CHECK-LABEL: acc.reduction.recipe @reduction_add_section_lb1.ub3_box_Uxi32 : !fir.box> reduction_operator init { ! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box>): ! HLFIR: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[ARG0]], %c0{{.*}} : (!fir.box>, index) -> (index, index, index) ! HLFIR: %[[SHAPE:.*]] = fir.shape %[[BOX_DIMS]]#1 : (index) -> !fir.shape<1> @@ -29,7 +64,7 @@ ! HLFIR: acc.yield %[[ARG0]] : !fir.box> ! HLFIR: } -! CHECK-LABEL: acc.reduction.recipe @reduction_max_ref_Uxf32 : !fir.box> reduction_operator init { +! CHECK-LABEL: acc.reduction.recipe @reduction_max_box_Uxf32 : !fir.box> reduction_operator init { ! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box>): ! CHECK: %[[INIT_VALUE:.*]] = arith.constant -1.401300e-45 : f32 ! HLFIR: %[[C0:.*]] = arith.constant 0 : index @@ -57,7 +92,7 @@ ! CHECK: acc.yield %[[ARG0]] : !fir.box> ! CHECK: } -! CHECK-LABEL: acc.reduction.recipe @reduction_add_ref_Uxi32 : !fir.box> reduction_operator init { +! CHECK-LABEL: acc.reduction.recipe @reduction_add_box_Uxi32 : !fir.box> reduction_operator init { ! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box>): ! HLFIR: %[[INIT_VALUE:.*]] = arith.constant 0 : i32 ! HLFIR: %[[C0:.*]] = arith.constant 0 : index @@ -1097,7 +1132,7 @@ subroutine acc_reduction_add_dynamic_extent_add(a) ! CHECK-SAME: %[[ARG0:.*]]: !fir.box> {fir.bindc_name = "a"}) ! HLFIR: %[[DECLARG0:.*]]:2 = hlfir.declare %[[ARG0]] ! HLFIR: %[[RED:.*]] = acc.reduction varPtr(%{{.*}} : !fir.ref>) bounds(%{{.*}}) -> !fir.ref> {name = "a"} -! HLFIR: acc.parallel reduction(@reduction_add_ref_Uxi32 -> %[[RED:.*]] : !fir.ref>) +! HLFIR: acc.parallel reduction(@reduction_add_box_Uxi32 -> %[[RED:.*]] : !fir.ref>) subroutine acc_reduction_add_dynamic_extent_max(a) real :: a(:) @@ -1109,7 +1144,7 @@ subroutine acc_reduction_add_dynamic_extent_max(a) ! CHECK-SAME: %[[ARG0:.*]]: !fir.box> {fir.bindc_name = "a"}) ! HLFIR: %[[DECLARG0:.*]]:2 = hlfir.declare %[[ARG0]] ! HLFIR: %[[RED:.*]] = acc.reduction varPtr(%{{.*}} : !fir.ref>) bounds(%{{.*}}) -> !fir.ref> {name = "a"} -! HLFIR: acc.parallel reduction(@reduction_max_ref_Uxf32 -> %[[RED]] : !fir.ref>) { +! HLFIR: acc.parallel reduction(@reduction_max_box_Uxf32 -> %[[RED]] : !fir.ref>) { subroutine acc_reduction_add_dynamic_extent_add_with_section(a) integer :: a(:) @@ -1123,4 +1158,34 @@ subroutine acc_reduction_add_dynamic_extent_add_with_section(a) ! HLFIR: %[[BOUND:.*]] = acc.bounds lowerbound(%c1{{.*}} : index) upperbound(%c3{{.*}} : index) stride(%{{.*}}#2 : index) startIdx(%{{.*}} : index) {strideInBytes = true} ! HLFIR: %[[BOX_ADDR:.*]] = fir.box_addr %[[DECL]]#1 : (!fir.box>) -> !fir.ref> ! HLFIR: %[[RED:.*]] = acc.reduction varPtr(%[[BOX_ADDR]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "a(2:4)"} -! HLFIR: acc.parallel reduction(@reduction_add_section_lb1.ub3_ref_Uxi32 -> %[[RED]] : !fir.ref>) +! HLFIR: acc.parallel reduction(@reduction_add_section_lb1.ub3_box_Uxi32 -> %[[RED]] : !fir.ref>) + +subroutine acc_reduction_add_allocatable(a) + real, allocatable :: a(:) + !$acc parallel reduction(max:a) + !$acc end parallel +end subroutine + +! CHECK-LABEL: func.func @_QPacc_reduction_add_allocatable( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>> {fir.bindc_name = "a"}) +! HLFIR: %[[DECL:.*]]:2 = hlfir.declare %[[ARG0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFacc_reduction_add_allocatableEa"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) +! HLFIR: %[[BOX:.*]] = fir.load %[[DECL]]#1 : !fir.ref>>> +! HLFIR: %[[BOUND:.*]] = acc.bounds lowerbound(%c0{{.*}} : index) upperbound(%{{.*}} : index) stride(%{{.*}}#2 : index) startIdx(%{{.*}}#0 : index) {strideInBytes = true} +! HLFIR: %[[BOX_ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box>>) -> !fir.heap> +! HLFIR: %[[RED:.*]] = acc.reduction varPtr(%[[BOX_ADDR]] : !fir.heap>) bounds(%6) -> !fir.heap> {name = "a"} +! HLFIR: acc.parallel reduction(@reduction_max_box_heap_Uxf32 -> %[[RED]] : !fir.heap>) + +subroutine acc_reduction_add_pointer_array(a) + real, pointer :: a(:) + !$acc parallel reduction(max:a) + !$acc end parallel +end subroutine + +! CHECK-LABEL: func.func @_QPacc_reduction_add_pointer_array( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>> {fir.bindc_name = "a"}) +! HLFIR: %[[DECL:.*]]:2 = hlfir.declare %[[ARG0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFacc_reduction_add_pointer_arrayEa"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) +! HLFIR: %[[BOX:.*]] = fir.load %[[DECL]]#1 : !fir.ref>>> +! HLFIR: %[[BOUND:.*]] = acc.bounds lowerbound(%c0{{.*}} : index) upperbound(%{{.*}} : index) stride(%{{.*}}#2 : index) startIdx(%{{.*}}#0 : index) {strideInBytes = true} +! HLFIR: %[[BOX_ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box>>) -> !fir.ptr> +! HLFIR: %[[RED:.*]] = acc.reduction varPtr(%[[BOX_ADDR]] : !fir.ptr>) bounds(%[[BOUND]]) -> !fir.ptr> {name = "a"} +! HLFIR: acc.parallel reduction(@reduction_max_box_ptr_Uxf32 -> %[[RED]] : !fir.ptr>) diff --git a/flang/test/Lower/OpenACC/acc-routine.f90 b/flang/test/Lower/OpenACC/acc-routine.f90 index f9fc9b1a0b4b7..7514e0a8819fa 100644 --- a/flang/test/Lower/OpenACC/acc-routine.f90 +++ b/flang/test/Lower/OpenACC/acc-routine.f90 @@ -3,6 +3,8 @@ ! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s ! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s + +! CHECK: acc.routine @acc_routine_10 func(@_QPacc_routine11) seq ! CHECK: acc.routine @acc_routine_9 func(@_QPacc_routine10) seq ! CHECK: acc.routine @acc_routine_8 func(@_QPacc_routine9) bind("_QPacc_routine9a") ! CHECK: acc.routine @acc_routine_7 func(@_QPacc_routine8) bind("routine8_") @@ -76,3 +78,21 @@ function acc_routine10() end function ! CHECK-LABEL: func.func @_QPacc_routine10() -> f32 attributes {acc.routine_info = #acc.routine_info<[@acc_routine_9]>} + +subroutine acc_routine11(a) + real :: a + !$acc routine(acc_routine11) seq +end subroutine + +! CHECK-LABEL: func.func @_QPacc_routine11(%arg0: !fir.ref {fir.bindc_name = "a"}) attributes {acc.routine_info = #acc.routine_info<[@acc_routine_10]>} + +subroutine acc_routine12() + + interface + subroutine acc_routine11(a) + real :: a + !$acc routine(acc_routine11) seq + end subroutine + end interface + +end subroutine diff --git a/flang/test/Lower/OpenACC/acc-serial-loop.f90 b/flang/test/Lower/OpenACC/acc-serial-loop.f90 index c9d556b91cb6c..523873325eed1 100644 --- a/flang/test/Lower/OpenACC/acc-serial-loop.f90 +++ b/flang/test/Lower/OpenACC/acc-serial-loop.f90 @@ -5,8 +5,8 @@ ! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_10xf32 : !fir.ref> init { ! CHECK: ^bb0(%{{.*}}: !fir.ref>): -! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10xf32> ! HLFIR: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1> +! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10xf32> ! HLFIR: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.ref> ! CHECK: } copy { diff --git a/flang/test/Lower/OpenACC/acc-serial.f90 b/flang/test/Lower/OpenACC/acc-serial.f90 index e538cee1407a2..56952a37c9101 100644 --- a/flang/test/Lower/OpenACC/acc-serial.f90 +++ b/flang/test/Lower/OpenACC/acc-serial.f90 @@ -5,8 +5,8 @@ ! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_10x10xf32 : !fir.ref> init { ! CHECK: ^bb0(%{{.*}}: !fir.ref>): -! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10x10xf32> ! HLFIR: %[[SHAPE:.*]] = fir.shape %{{.*}}, %{{.*}} : (index, index) -> !fir.shape<2> +! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10x10xf32> ! HLFIR: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) ! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.ref> ! CHECK: } copy { diff --git a/flang/test/Lower/OpenMP/omp-declare-target-program-var.f90 b/flang/test/Lower/OpenMP/omp-declare-target-program-var.f90 new file mode 100644 index 0000000000000..20538ff34871f --- /dev/null +++ b/flang/test/Lower/OpenMP/omp-declare-target-program-var.f90 @@ -0,0 +1,13 @@ +!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s --check-prefixes=HOST,ALL +!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-is-target-device %s -o - | FileCheck %s --check-prefix=ALL + +PROGRAM main + ! HOST-DAG: %[[I_REF:.*]] = fir.alloca f32 {bindc_name = "i", uniq_name = "_QFEi"} + ! HOST-DAG: %[[I_DECL:.*]]:2 = hlfir.declare %[[I_REF]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) + REAL :: I + ! ALL-DAG: fir.global internal @_QFEi {omp.declare_target = #omp.declaretarget} : f32 { + ! ALL-DAG: %[[UNDEF:.*]] = fir.undefined f32 + ! ALL-DAG: fir.has_value %[[UNDEF]] : f32 + ! ALL-DAG: } + !$omp declare target(I) +END diff --git a/flang/test/Lower/OpenMP/ordered-threads.f90 b/flang/test/Lower/OpenMP/ordered-threads.f90 new file mode 100644 index 0000000000000..a3f99129eba7e --- /dev/null +++ b/flang/test/Lower/OpenMP/ordered-threads.f90 @@ -0,0 +1,25 @@ +! This test checks lowering of OpenMP ordered directive with threads Clause. +! Without clause in ordered direcitve, it behaves as if threads clause is +! specified. + +!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s + +subroutine ordered + integer :: i + integer :: a(20) + +!CHECK: omp.ordered_region { +!$OMP ORDERED + a(i) = a(i-1) + 1 +!CHECK: omp.terminator +!CHECK-NEXT: } +!$OMP END ORDERED + +!CHECK: omp.ordered_region { +!$OMP ORDERED THREADS + a(i) = a(i-1) + 1 +!CHECK: omp.terminator +!CHECK-NEXT: } +!$OMP END ORDERED + +end diff --git a/flang/test/Lower/OpenMP/taskgroup.f90 b/flang/test/Lower/OpenMP/taskgroup.f90 new file mode 100644 index 0000000000000..85dc253b59d65 --- /dev/null +++ b/flang/test/Lower/OpenMP/taskgroup.f90 @@ -0,0 +1,20 @@ +!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s + +!CHECK-LABEL: @_QPomp_taskgroup +subroutine omp_taskgroup +use omp_lib +integer :: allocated_x +!CHECK: %[[ALLOC_X_REF:.*]] = fir.alloca i32 {bindc_name = "allocated_x", uniq_name = "_QFomp_taskgroupEallocated_x"} +!CHECK-NEXT: %[[ALLOC_X_DECL:.*]]:2 = hlfir.declare %[[ALLOC_X_REF]] {uniq_name = "_QFomp_taskgroupEallocated_x"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[C1:.*]] = arith.constant 1 : i32 + +!CHECK: omp.taskgroup allocate(%[[C1]] : i32 -> %[[ALLOC_X_DECL]]#1 : !fir.ref) +!$omp taskgroup allocate(omp_high_bw_mem_alloc: allocated_x) +!$omp task +!CHECK: fir.call @_QPwork() {{.*}}: () -> () + call work() +!CHECK: omp.terminator +!$omp end task +!CHECK: omp.terminator +!$omp end taskgroup +end subroutine diff --git a/flang/test/Lower/charconvert.f90 b/flang/test/Lower/charconvert.f90 index 427b5b1b26271..693d5bf603788 100644 --- a/flang/test/Lower/charconvert.f90 +++ b/flang/test/Lower/charconvert.f90 @@ -19,10 +19,6 @@ subroutine test_c4_to_c1(c4, c1) ! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]]#0 typeparams %[[VAL_2]]#1 {uniq_name = "_QFtest_c1_to_c4Ec4"} : (!fir.ref>, index) -> (!fir.boxchar<4>, !fir.ref>) ! CHECK: %[[VAL_4:.*]] = fir.alloca !fir.char<4,?>(%[[VAL_0]]#1 : index) ! CHECK: fir.char_convert %[[VAL_1]]#1 for %[[VAL_0]]#1 to %[[VAL_4:.*]] : !fir.ref>, index, !fir.ref> -! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] typeparams %[[VAL_0]]#1 {uniq_name = "ctor.temp"} : (!fir.ref>, index) -> (!fir.boxchar<4>, !fir.ref>) -! CHECK: hlfir.assign %[[VAL_5]]#0 to %[[VAL_3]]#0 : !fir.boxchar<4>, !fir.boxchar<4> -! CHECK: return -! CHECK: } ! CHECK: func.func @_QPtest_c4_to_c1(%[[ARG0:.*]]: !fir.boxchar<4> {fir.bindc_name = "c4"}, %[[ARG1:.*]]: !fir.boxchar<1> {fir.bindc_name = "c1"}) { ! CHECK: %[[VAL_0:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref>, index) @@ -33,7 +29,4 @@ subroutine test_c4_to_c1(c4, c1) ! CHECK: %[[VAL_4:.*]] = arith.muli %[[VAL_2]]#1, %[[C4]] : index ! CHECK: %[[VAL_5:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_4]] : index) ! CHECK: fir.char_convert %[[VAL_3]]#1 for %[[VAL_2]]#1 to %[[VAL_5:.*]] : !fir.ref>, index, !fir.ref> -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] typeparams %[[VAL_2]]#1 {uniq_name = "ctor.temp"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) -! CHECK: hlfir.assign %[[VAL_6]]#0 to %[[VAL_1]]#0 : !fir.boxchar<1>, !fir.boxchar<1> -! CHECK: return -! CHECK: } \ No newline at end of file +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] typeparams %[[VAL_2]]#1 {uniq_name = "ctor.temp"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) \ No newline at end of file diff --git a/flang/test/Lower/derived-type-finalization.f90 b/flang/test/Lower/derived-type-finalization.f90 index d0fbfe8906c4d..86e2e274e9d7e 100644 --- a/flang/test/Lower/derived-type-finalization.f90 +++ b/flang/test/Lower/derived-type-finalization.f90 @@ -55,11 +55,12 @@ subroutine test_lhs_allocatable() end subroutine ! CHECK-LABEL: func.func @_QMderived_type_finalizationPtest_lhs() { +! CHECK: %[[BOXREF:.*]] = fir.alloca !fir.box> ! CHECK: %[[LHS:.*]] = fir.alloca !fir.type<_QMderived_type_finalizationTt1{a:i32}> {bindc_name = "lhs", uniq_name = "_QMderived_type_finalizationFtest_lhsElhs"} -! CHECK: %[[RHS:.*]] = fir.alloca !fir.type<_QMderived_type_finalizationTt1{a:i32}> {bindc_name = "rhs", uniq_name = "_QMderived_type_finalizationFtest_lhsErhs"} ! CHECK: %[[EMBOX:.*]] = fir.embox %[[LHS]] : (!fir.ref>) -> !fir.box> -! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[EMBOX]] : (!fir.box>) -> !fir.box -! CHECK: %{{.*}} = fir.call @_FortranADestroy(%[[BOX_NONE]]) {{.*}} : (!fir.box) -> none +! CHECK: fir.store %[[EMBOX]] to %[[BOXREF]] : !fir.ref>> +! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[BOXREF]] : (!fir.ref>>) -> !fir.ref> +! CHECK: %{{.*}} = fir.call @_FortranAAssign(%[[BOX_NONE]], {{.*}} ! CHECK-LABEL: func.func @_QMderived_type_finalizationPtest_lhs_allocatable() { ! CHECK: %[[LHS:.*]] = fir.alloca !fir.box>> {bindc_name = "lhs", uniq_name = "_QMderived_type_finalizationFtest_lhs_allocatableElhs"} @@ -210,7 +211,8 @@ function no_func_ret_finalize() result(ty) end function ! CHECK-LABEL: func.func @_QMderived_type_finalizationPno_func_ret_finalize() -> !fir.type<_QMderived_type_finalizationTt1{a:i32}> { -! CHECK: %{{.*}} = fir.call @_FortranADestroy +! CHECK: %{{.*}} = fir.call @_FortranAAssign +! CHECK-NOT: fir.call @_FortranADestroy ! CHECK: return %{{.*}} : !fir.type<_QMderived_type_finalizationTt1{a:i32}> function copy(a) result(ty) diff --git a/flang/test/Lower/dispatch-table.f90 b/flang/test/Lower/dispatch-table.f90 index 7b5a5ec4a39e6..0df4981b3eaf8 100644 --- a/flang/test/Lower/dispatch-table.f90 +++ b/flang/test/Lower/dispatch-table.f90 @@ -1,6 +1,6 @@ ! RUN: bbc -polymorphic-type -emit-fir %s -o - | FileCheck %s -! Tests the generation of fir.dispatch_table operations. +! Tests the generation of fir.type_info operations. module polymorphic_types type p1 @@ -53,20 +53,20 @@ subroutine aproc3(p) end module -! CHECK-LABEL: fir.dispatch_table @_QMpolymorphic_typesTp1 { +! CHECK-LABEL: fir.type_info @_QMpolymorphic_typesTp1 ! CHECK: fir.dt_entry "aproc", @_QMpolymorphic_typesPaproc ! CHECK: fir.dt_entry "proc1", @_QMpolymorphic_typesPproc1_p1 ! CHECK: fir.dt_entry "zproc", @_QMpolymorphic_typesPzproc ! CHECK: } -! CHECK-LABEL: fir.dispatch_table @_QMpolymorphic_typesTp2 extends("_QMpolymorphic_typesTp1") { +! CHECK-LABEL: fir.type_info @_QMpolymorphic_typesTp2 {{.*}}extends !fir.type<_QMpolymorphic_typesTp1{{.*}}> ! CHECK: fir.dt_entry "aproc", @_QMpolymorphic_typesPaproc ! CHECK: fir.dt_entry "proc1", @_QMpolymorphic_typesPproc1_p2 ! CHECK: fir.dt_entry "zproc", @_QMpolymorphic_typesPzproc ! CHECK: fir.dt_entry "aproc2", @_QMpolymorphic_typesPaproc2 ! CHECK: } -! CHECK-LABEL: fir.dispatch_table @_QMpolymorphic_typesTp3 extends("_QMpolymorphic_typesTp2") { +! CHECK-LABEL: fir.type_info @_QMpolymorphic_typesTp3 {{.*}}extends !fir.type<_QMpolymorphic_typesTp2{{.*}}> ! CHECK: fir.dt_entry "aproc", @_QMpolymorphic_typesPaproc ! CHECK: fir.dt_entry "proc1", @_QMpolymorphic_typesPproc1_p2 ! CHECK: fir.dt_entry "zproc", @_QMpolymorphic_typesPzproc diff --git a/libc/cmake/modules/LLVMLibCCheckCpuFeatures.cmake b/libc/cmake/modules/LLVMLibCCheckCpuFeatures.cmake index 0b522318aaa12..73b249374a066 100644 --- a/libc/cmake/modules/LLVMLibCCheckCpuFeatures.cmake +++ b/libc/cmake/modules/LLVMLibCCheckCpuFeatures.cmake @@ -22,10 +22,6 @@ list(SORT ALL_CPU_FEATURES) # # ) function(cpu_supports output_var features) - if(LIBC_TARGET_ARCHITECTURE_IS_GPU) - unset(${output_var} PARENT_SCOPE) - return() - endif() _intersection(var "${LIBC_CPU_FEATURES}" "${features}") if("${var}" STREQUAL "${features}") set(${output_var} TRUE PARENT_SCOPE) diff --git a/libc/src/__support/float_to_string.h b/libc/src/__support/float_to_string.h index d3fcec7a652fa..eb06cd9c08af2 100644 --- a/libc/src/__support/float_to_string.h +++ b/libc/src/__support/float_to_string.h @@ -708,7 +708,7 @@ FloatToString::get_negative_block(int block_index) { const int32_t SHIFT_CONST = TABLE_SHIFT_CONST; // if the requested block is zero - if (block_index <= MIN_BLOCK_2[idx]) { + if (block_index < MIN_BLOCK_2[idx]) { return 0; } const uint32_t p = POW10_OFFSET_2[idx] + block_index - MIN_BLOCK_2[idx]; diff --git a/libc/src/math/gpu/vendor/amdgpu/platform.h b/libc/src/math/gpu/vendor/amdgpu/platform.h index 480a46bf14dfd..d06a53d7371d2 100644 --- a/libc/src/math/gpu/vendor/amdgpu/platform.h +++ b/libc/src/math/gpu/vendor/amdgpu/platform.h @@ -9,6 +9,8 @@ #ifndef LLVM_LIBC_SRC_MATH_GPU_AMDGPU_PLATFORM_H #define LLVM_LIBC_SRC_MATH_GPU_AMDGPU_PLATFORM_H +#include "src/__support/macros/attributes.h" + #include namespace LIBC_NAMESPACE { @@ -19,96 +21,106 @@ namespace LIBC_NAMESPACE { extern "C" { // Disable unsafe math optimizations in the implementation. -extern const uint8_t __oclc_unsafe_math_opt = 0; +extern const LIBC_INLINE_VAR uint8_t __oclc_unsafe_math_opt = 0; // Disable denormalization at zero optimizations in the implementation. -extern const uint8_t __oclc_daz_opt = 0; +extern const LIBC_INLINE_VAR uint8_t __oclc_daz_opt = 0; // Disable rounding optimizations for 32-bit square roots. -extern const uint8_t __oclc_correctly_rounded_sqrt32 = 1; +extern const LIBC_INLINE_VAR uint8_t __oclc_correctly_rounded_sqrt32 = 1; // Disable finite math optimizations. -extern const uint8_t __oclc_finite_only_opt = 0; +extern const LIBC_INLINE_VAR uint8_t __oclc_finite_only_opt = 0; #if defined(__gfx700__) -extern const uint32_t __oclc_ISA_version = 7000; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 7000; #elif defined(__gfx701__) -extern const uint32_t __oclc_ISA_version = 7001; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 7001; #elif defined(__gfx702__) -extern const uint32_t __oclc_ISA_version = 7002; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 7002; #elif defined(__gfx703__) -extern const uint32_t __oclc_ISA_version = 7003; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 7003; #elif defined(__gfx704__) -extern const uint32_t __oclc_ISA_version = 7004; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 7004; #elif defined(__gfx705__) -extern const uint32_t __oclc_ISA_version = 7005; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 7005; #elif defined(__gfx801__) -extern const uint32_t __oclc_ISA_version = 8001; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 8001; #elif defined(__gfx802__) -extern const uint32_t __oclc_ISA_version = 8002; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 8002; #elif defined(__gfx803__) -extern const uint32_t __oclc_ISA_version = 8003; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 8003; #elif defined(__gfx805__) -extern const uint32_t __oclc_ISA_version = 8005; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 8005; #elif defined(__gfx810__) -extern const uint32_t __oclc_ISA_version = 8100; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 8100; #elif defined(__gfx900__) -extern const uint32_t __oclc_ISA_version = 9000; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 9000; #elif defined(__gfx902__) -extern const uint32_t __oclc_ISA_version = 9002; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 9002; #elif defined(__gfx904__) -extern const uint32_t __oclc_ISA_version = 9004; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 9004; #elif defined(__gfx906__) -extern const uint32_t __oclc_ISA_version = 9006; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 9006; #elif defined(__gfx908__) -extern const uint32_t __oclc_ISA_version = 9008; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 9008; #elif defined(__gfx909__) -extern const uint32_t __oclc_ISA_version = 9009; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 9009; #elif defined(__gfx90a__) -extern const uint32_t __oclc_ISA_version = 9010; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 9010; #elif defined(__gfx90c__) -extern const uint32_t __oclc_ISA_version = 9012; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 9012; #elif defined(__gfx940__) -extern const uint32_t __oclc_ISA_version = 9400; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 9400; #elif defined(__gfx1010__) -extern const uint32_t __oclc_ISA_version = 10100; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 10100; #elif defined(__gfx1011__) -extern const uint32_t __oclc_ISA_version = 10101; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 10101; #elif defined(__gfx1012__) -extern const uint32_t __oclc_ISA_version = 10102; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 10102; #elif defined(__gfx1013__) -extern const uint32_t __oclc_ISA_version = 10103; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 10103; #elif defined(__gfx1030__) -extern const uint32_t __oclc_ISA_version = 10300; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 10300; #elif defined(__gfx1031__) -extern const uint32_t __oclc_ISA_version = 10301; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 10301; #elif defined(__gfx1032__) -extern const uint32_t __oclc_ISA_version = 10302; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 10302; #elif defined(__gfx1033__) -extern const uint32_t __oclc_ISA_version = 10303; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 10303; #elif defined(__gfx1034__) -extern const uint32_t __oclc_ISA_version = 10304; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 10304; #elif defined(__gfx1035__) -extern const uint32_t __oclc_ISA_version = 10305; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 10305; #elif defined(__gfx1036__) -extern const uint32_t __oclc_ISA_version = 10306; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 10306; #elif defined(__gfx1100__) -extern const uint32_t __oclc_ISA_version = 11000; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 11000; #elif defined(__gfx1101__) -extern const uint32_t __oclc_ISA_version = 11001; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 11001; #elif defined(__gfx1102__) -extern const uint32_t __oclc_ISA_version = 11002; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 11002; #elif defined(__gfx1103__) -extern const uint32_t __oclc_ISA_version = 11003; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 11003; #elif defined(__gfx1150__) -extern const uint32_t __oclc_ISA_version = 11500; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 11500; #elif defined(__gfx1151__) -extern const uint32_t __oclc_ISA_version = 11501; +extern const LIBC_INLINE_VAR uint32_t __oclc_ISA_version = 11501; #else #error "Unknown AMDGPU architecture" #endif } +// These aliases cause clang to emit the control constants with ODR linkage. +// This allows us to link against the symbols without preventing them from being +// optimized out or causing symbol collisions. +[[gnu::alias("__oclc_unsafe_math_opt")]] const uint8_t __oclc_unsafe_math_opt__; +[[gnu::alias("__oclc_daz_opt")]] const uint8_t __oclc_daz_opt__; +[[gnu::alias("__oclc_correctly_rounded_sqrt32")]] const uint8_t + __oclc_correctly_rounded_sqrt32__; +[[gnu::alias("__oclc_finite_only_opt")]] const uint8_t __oclc_finite_only_opt__; +[[gnu::alias("__oclc_ISA_version")]] const uint32_t __oclc_ISA_version__; + } // namespace LIBC_NAMESPACE #endif // LLVM_LIBC_SRC_MATH_GPU_AMDGPU_PLATFORM_H diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt index f2e5654d03cce..67675b682081c 100644 --- a/libc/src/string/CMakeLists.txt +++ b/libc/src/string/CMakeLists.txt @@ -498,6 +498,8 @@ if(${LIBC_TARGET_ARCHITECTURE_IS_X86}) add_bcmp(bcmp_x86_64_opt_avx512 COMPILE_OPTIONS -march=skylake-avx512 REQUIRE AVX512BW) add_bcmp(bcmp_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE}) add_bcmp(bcmp) +elseif(LIBC_TARGET_ARCHITECTURE_IS_GPU) + add_bcmp(bcmp) else() add_bcmp(bcmp_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE}) add_bcmp(bcmp) @@ -525,6 +527,8 @@ if(${LIBC_TARGET_ARCHITECTURE_IS_X86}) add_bzero(bzero_x86_64_opt_avx512 COMPILE_OPTIONS -march=skylake-avx512 REQUIRE AVX512F) add_bzero(bzero_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE}) add_bzero(bzero) +elseif(LIBC_TARGET_ARCHITECTURE_IS_GPU) + add_bzero(bzero) else() add_bzero(bzero_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE}) add_bzero(bzero) @@ -555,6 +559,8 @@ if(${LIBC_TARGET_ARCHITECTURE_IS_X86}) elseif(${LIBC_TARGET_ARCHITECTURE_IS_AARCH64}) add_memcmp(memcmp_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE}) add_memcmp(memcmp) +elseif(LIBC_TARGET_ARCHITECTURE_IS_GPU) + add_memcmp(memcmp) else() add_memcmp(memcmp_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE}) add_memcmp(memcmp) @@ -589,6 +595,8 @@ elseif(${LIBC_TARGET_ARCHITECTURE_IS_AARCH64}) add_memcpy(memcpy_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE} MLLVM_COMPILE_OPTIONS "-tail-merge-threshold=0") add_memcpy(memcpy MLLVM_COMPILE_OPTIONS "-tail-merge-threshold=0") +elseif(LIBC_TARGET_ARCHITECTURE_IS_GPU) + add_memcpy(memcpy) else() add_memcpy(memcpy_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE}) add_memcpy(memcpy) @@ -621,6 +629,8 @@ elseif(${LIBC_TARGET_ARCHITECTURE_IS_AARCH64}) add_memmove(memmove_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE} MLLVM_COMPILE_OPTIONS "-tail-merge-threshold=0") add_memmove(memmove MLLVM_COMPILE_OPTIONS "-tail-merge-threshold=0") +elseif(LIBC_TARGET_ARCHITECTURE_IS_GPU) + add_memmove(memmove) else() add_memmove(memmove_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE}) add_memmove(memmove) @@ -653,6 +663,8 @@ elseif(${LIBC_TARGET_ARCHITECTURE_IS_AARCH64}) add_memset(memset_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE} MLLVM_COMPILE_OPTIONS "-tail-merge-threshold=0") add_memset(memset MLLVM_COMPILE_OPTIONS "-tail-merge-threshold=0") +elseif(LIBC_TARGET_ARCHITECTURE_IS_GPU) + add_memset(memset) else() add_memset(memset_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE}) add_memset(memset) diff --git a/libc/src/string/memory_utils/generic/builtin.h b/libc/src/string/memory_utils/generic/builtin.h new file mode 100644 index 0000000000000..5239329f653b3 --- /dev/null +++ b/libc/src/string/memory_utils/generic/builtin.h @@ -0,0 +1,41 @@ +//===-- Trivial builtin implementations ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_STRING_MEMORY_UTILS_GENERIC_BUILTIN_H +#define LLVM_LIBC_SRC_STRING_MEMORY_UTILS_GENERIC_BUILTIN_H + +#include "src/__support/macros/attributes.h" // LIBC_INLINE +#include "src/__support/macros/config.h" // LIBC_HAS_BUILTIN +#include "src/string/memory_utils/utils.h" // Ptr, CPtr + +#include // size_t + +namespace LIBC_NAMESPACE { + +static_assert(LIBC_HAS_BUILTIN(__builtin_memcpy), "Builtin not defined"); +static_assert(LIBC_HAS_BUILTIN(__builtin_memset), "Builtin not defined"); +static_assert(LIBC_HAS_BUILTIN(__builtin_memmove), "Builtin not defined"); + +[[maybe_unused]] LIBC_INLINE void +inline_memcpy_builtin(Ptr dst, CPtr src, size_t count, size_t offset = 0) { + __builtin_memcpy(dst + offset, src + offset, count); +} + +[[maybe_unused]] LIBC_INLINE void inline_memmove_builtin(Ptr dst, CPtr src, + size_t count) { + __builtin_memmove(dst, src, count); +} + +[[maybe_unused]] LIBC_INLINE static void +inline_memset_builtin(Ptr dst, uint8_t value, size_t count, size_t offset = 0) { + __builtin_memset(dst + offset, value, count); +} + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_STRING_MEMORY_UTILS_GENERIC_BUILTIN_H diff --git a/libc/src/string/memory_utils/inline_memcpy.h b/libc/src/string/memory_utils/inline_memcpy.h index 0b8a7848da87b..a92bf4ddf881d 100644 --- a/libc/src/string/memory_utils/inline_memcpy.h +++ b/libc/src/string/memory_utils/inline_memcpy.h @@ -28,9 +28,12 @@ #elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) #include "src/string/memory_utils/riscv/inline_memcpy.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY inline_memcpy_riscv -#elif defined(LIBC_TARGET_ARCH_IS_ARM) || defined(LIBC_TARGET_ARCH_IS_GPU) +#elif defined(LIBC_TARGET_ARCH_IS_ARM) #include "src/string/memory_utils/generic/byte_per_byte.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY inline_memcpy_byte_per_byte +#elif defined(LIBC_TARGET_ARCH_IS_GPU) +#include "src/string/memory_utils/generic/builtin.h" +#define LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY inline_memcpy_builtin #else #error "Unsupported architecture" #endif diff --git a/libc/src/string/memory_utils/inline_memmove.h b/libc/src/string/memory_utils/inline_memmove.h index 0d31e10eaff28..f72ea24ab538d 100644 --- a/libc/src/string/memory_utils/inline_memmove.h +++ b/libc/src/string/memory_utils/inline_memmove.h @@ -20,9 +20,12 @@ #elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) #include "src/string/memory_utils/riscv/inline_memmove.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMMOVE inline_memmove_riscv -#elif defined(LIBC_TARGET_ARCH_IS_ARM) || defined(LIBC_TARGET_ARCH_IS_GPU) +#elif defined(LIBC_TARGET_ARCH_IS_ARM) #include "src/string/memory_utils/generic/byte_per_byte.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMMOVE inline_memmove_byte_per_byte +#elif defined(LIBC_TARGET_ARCH_IS_GPU) +#include "src/string/memory_utils/generic/builtin.h" +#define LIBC_SRC_STRING_MEMORY_UTILS_MEMMOVE inline_memmove_builtin #else #error "Unsupported architecture" #endif diff --git a/libc/src/string/memory_utils/inline_memset.h b/libc/src/string/memory_utils/inline_memset.h index f20ae45fa753b..1c07c1ca4bffc 100644 --- a/libc/src/string/memory_utils/inline_memset.h +++ b/libc/src/string/memory_utils/inline_memset.h @@ -24,9 +24,12 @@ #elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) #include "src/string/memory_utils/riscv/inline_memset.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMSET inline_memset_riscv -#elif defined(LIBC_TARGET_ARCH_IS_ARM) || defined(LIBC_TARGET_ARCH_IS_GPU) +#elif defined(LIBC_TARGET_ARCH_IS_ARM) #include "src/string/memory_utils/generic/byte_per_byte.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMSET inline_memset_byte_per_byte +#elif defined(LIBC_TARGET_ARCH_IS_GPU) +#include "src/string/memory_utils/generic/builtin.h" +#define LIBC_SRC_STRING_MEMORY_UTILS_MEMSET inline_memset_builtin #else #error "Unsupported architecture" #endif diff --git a/libc/startup/linux/x86_64/CMakeLists.txt b/libc/startup/linux/x86_64/CMakeLists.txt index 40f01836c1313..076c0c3e444f5 100644 --- a/libc/startup/linux/x86_64/CMakeLists.txt +++ b/libc/startup/linux/x86_64/CMakeLists.txt @@ -10,6 +10,7 @@ add_startup_object( libc.src.__support.threads.thread libc.src.__support.OSUtil.osutil libc.src.stdlib.exit + libc.src.stdlib.abort libc.src.stdlib.atexit libc.src.string.memory_utils.inline_memcpy libc.src.unistd.environ diff --git a/libc/startup/linux/x86_64/start.cpp b/libc/startup/linux/x86_64/start.cpp index 4b46a4f4a7b08..af95d2702ded9 100644 --- a/libc/startup/linux/x86_64/start.cpp +++ b/libc/startup/linux/x86_64/start.cpp @@ -7,8 +7,10 @@ //===----------------------------------------------------------------------===// #include "config/linux/app.h" +#include "src/__support/OSUtil/io.h" #include "src/__support/OSUtil/syscall.h" #include "src/__support/threads/thread.h" +#include "src/stdlib/abort.h" #include "src/stdlib/atexit.h" #include "src/stdlib/exit.h" #include "src/string/memory_utils/inline_memcpy.h" @@ -23,6 +25,11 @@ extern "C" int main(int, char **, char **); +extern "C" void __stack_chk_fail() { + LIBC_NAMESPACE::write_to_stderr("stack smashing detected"); + LIBC_NAMESPACE::abort(); +} + namespace LIBC_NAMESPACE { #ifdef SYS_mmap2 @@ -54,7 +61,9 @@ void init_tls(TLSDescriptor &tls_descriptor) { // Per the x86_64 TLS ABI, the entry pointed to by the thread pointer is the // address of the TLS block. So, we add more size to accomodate this address // entry. - uintptr_t tlsSizeWithAddr = tlsSize + sizeof(uintptr_t); + // We also need to include space for the stack canary. The canary is at + // offset 0x28 (40) and is of size uintptr_t. + uintptr_t tlsSizeWithAddr = tlsSize + sizeof(uintptr_t) + 40; // We cannot call the mmap function here as the functions set errno on // failure. Since errno is implemented via a thread local variable, we cannot @@ -76,6 +85,16 @@ void init_tls(TLSDescriptor &tls_descriptor) { LIBC_NAMESPACE::inline_memcpy(reinterpret_cast(tlsAddr), reinterpret_cast(app.tls.address), app.tls.init_size); + uintptr_t *stackGuardAddr = reinterpret_cast(endPtr + 40); + // Setting the stack guard to a random value. + // We cannot call the get_random function here as the function sets errno on + // failure. Since errno is implemented via a thread local variable, we cannot + // use errno before TLS is setup. + ssize_t stackGuardRetVal = LIBC_NAMESPACE::syscall_impl( + SYS_getrandom, reinterpret_cast(stackGuardAddr), sizeof(uint64_t), + 0); + if (stackGuardRetVal < 0) + LIBC_NAMESPACE::syscall_impl(SYS_exit, 1); tls_descriptor = {tlsSizeWithAddr, uintptr_t(tlsAddr), endPtr}; return; diff --git a/libc/test/UnitTest/FPMatcher.h b/libc/test/UnitTest/FPMatcher.h index 0c1f340449236..fb60916a0402f 100644 --- a/libc/test/UnitTest/FPMatcher.h +++ b/libc/test/UnitTest/FPMatcher.h @@ -156,17 +156,21 @@ template FPMatcher getMatcher(T expectedValue) { do { \ using namespace LIBC_NAMESPACE::fputil::testing; \ ForceRoundingMode __r1(RoundingMode::Nearest); \ - if (__r1.success) \ + if (__r1.success) { \ EXPECT_FP_EQ((expected), (actual)); \ + } \ ForceRoundingMode __r2(RoundingMode::Upward); \ - if (__r2.success) \ + if (__r2.success) { \ EXPECT_FP_EQ((expected), (actual)); \ + } \ ForceRoundingMode __r3(RoundingMode::Downward); \ - if (__r3.success) \ + if (__r3.success) { \ EXPECT_FP_EQ((expected), (actual)); \ + } \ ForceRoundingMode __r4(RoundingMode::TowardZero); \ - if (__r4.success) \ + if (__r4.success) { \ EXPECT_FP_EQ((expected), (actual)); \ + } \ } while (0) #endif // LLVM_LIBC_UTILS_UNITTEST_FPMATCHER_H diff --git a/libc/test/UnitTest/LibcTest.h b/libc/test/UnitTest/LibcTest.h index dc17c3c49d427..68fd5f28f3e0b 100644 --- a/libc/test/UnitTest/LibcTest.h +++ b/libc/test/UnitTest/LibcTest.h @@ -378,19 +378,6 @@ CString libc_make_test_file_path_func(const char *file_name); SuiteClass##_##TestName SuiteClass##_##TestName##_Instance; \ void SuiteClass##_##TestName::Run() -// The GNU compiler emits a warning if nested "if" statements are followed by -// an "else" statement and braces are not used to explicitly disambiguate the -// "else" binding. This leads to problems with code like: -// -// if (gate) -// ASSERT_*(condition) << "Some message"; -// -// The "switch (0) case 0:" idiom is used to suppress this. -#define LIBC_AMBIGUOUS_ELSE_BLOCKER_ \ - switch (0) \ - case 0: \ - default: - // If RET_OR_EMPTY is the 'return' keyword we perform an early return which // corresponds to an assert. If it is empty the execution continues, this // corresponds to an expect. @@ -402,7 +389,6 @@ CString libc_make_test_file_path_func(const char *file_name); // returning a boolean. This expression is responsible for logging the // diagnostic in case of failure. #define LIBC_TEST_SCAFFOLDING_(TEST, RET_OR_EMPTY) \ - LIBC_AMBIGUOUS_ELSE_BLOCKER_ \ if (TEST) \ ; \ else \ diff --git a/libc/test/integration/src/unistd/CMakeLists.txt b/libc/test/integration/src/unistd/CMakeLists.txt index 72fdb8fc7e6b0..10aac212af355 100644 --- a/libc/test/integration/src/unistd/CMakeLists.txt +++ b/libc/test/integration/src/unistd/CMakeLists.txt @@ -33,6 +33,29 @@ add_integration_test( libc.src.unistd.fork ) +if((${LIBC_TARGET_OS} STREQUAL "linux") AND (${LIBC_TARGET_ARCHITECTURE_IS_X86})) + add_integration_test( + stack_smashing_test + SUITE + unistd-integration-tests + SRCS + stack_smashing_test.cpp + DEPENDS + libc.include.errno + libc.include.signal + libc.include.sys_wait + libc.include.unistd + libc.src.pthread.pthread_atfork + libc.src.signal.raise + libc.src.sys.wait.wait + libc.src.sys.wait.wait4 + libc.src.sys.wait.waitpid + libc.src.unistd.fork + COMPILE_OPTIONS + -fstack-protector-all + ) +endif() + add_executable( libc_execv_test_normal_exit EXCLUDE_FROM_ALL diff --git a/libc/test/integration/src/unistd/stack_smashing_test.cpp b/libc/test/integration/src/unistd/stack_smashing_test.cpp new file mode 100644 index 0000000000000..89fc53dac506a --- /dev/null +++ b/libc/test/integration/src/unistd/stack_smashing_test.cpp @@ -0,0 +1,68 @@ +//===--- Stack smashing test to check stack canary set up ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/__support/CPP/string.h" +#include "src/__support/OSUtil/io.h" +#include "src/pthread/pthread_atfork.h" +#include "src/signal/raise.h" +#include "src/sys/wait/wait.h" +#include "src/sys/wait/wait4.h" +#include "src/sys/wait/waitpid.h" +#include "src/unistd/fork.h" + +#include "test/IntegrationTest/test.h" + +#include +#include +#include +#include + +void no_stack_smashing_normal_exit() { + pid_t pid = LIBC_NAMESPACE::fork(); + if (pid == 0) { + // Child process + char foo[30]; + for (int i = 0; i < 30; i++) + foo[i] = (foo[i] != 42) ? 42 : 24; + return; + } + ASSERT_TRUE(pid > 0); + int status; + pid_t cpid = LIBC_NAMESPACE::wait(&status); + ASSERT_TRUE(cpid > 0); + ASSERT_EQ(cpid, pid); + ASSERT_TRUE(WIFEXITED(status)); +} + +void stack_smashing_abort() { + pid_t pid = LIBC_NAMESPACE::fork(); + if (pid == 0) { + // Child process + char foo[30]; + char *frame_ptr = static_cast(__builtin_frame_address(0)); + char *cur_ptr = &foo[0]; + // Corrupt the stack + while (cur_ptr != frame_ptr) { + *cur_ptr = (*cur_ptr != 42) ? 42 : 24; + cur_ptr++; + } + return; + } + ASSERT_TRUE(pid > 0); + int status; + pid_t cpid = LIBC_NAMESPACE::wait(&status); + ASSERT_TRUE(cpid > 0); + ASSERT_EQ(cpid, pid); + ASSERT_TRUE(WTERMSIG(status) == SIGABRT); +} + +TEST_MAIN(int argc, char **argv, char **envp) { + no_stack_smashing_normal_exit(); + stack_smashing_abort(); + return 0; +} diff --git a/libc/test/src/__support/FPUtil/rounding_mode_test.cpp b/libc/test/src/__support/FPUtil/rounding_mode_test.cpp index e73d10d965884..8077a5aab7afd 100644 --- a/libc/test/src/__support/FPUtil/rounding_mode_test.cpp +++ b/libc/test/src/__support/FPUtil/rounding_mode_test.cpp @@ -19,23 +19,27 @@ TEST(LlvmLibcFEnvImplTest, QuickRoundingUpTest) { using LIBC_NAMESPACE::fputil::fenv_is_round_up; { ForceRoundingMode __r(RoundingMode::Upward); - if (__r.success) + if (__r.success) { ASSERT_TRUE(fenv_is_round_up()); + } } { ForceRoundingMode __r(RoundingMode::Downward); - if (__r.success) + if (__r.success) { ASSERT_FALSE(fenv_is_round_up()); + } } { ForceRoundingMode __r(RoundingMode::Nearest); - if (__r.success) + if (__r.success) { ASSERT_FALSE(fenv_is_round_up()); + } } { ForceRoundingMode __r(RoundingMode::TowardZero); - if (__r.success) + if (__r.success) { ASSERT_FALSE(fenv_is_round_up()); + } } } @@ -43,23 +47,27 @@ TEST(LlvmLibcFEnvImplTest, QuickRoundingDownTest) { using LIBC_NAMESPACE::fputil::fenv_is_round_down; { ForceRoundingMode __r(RoundingMode::Upward); - if (__r.success) + if (__r.success) { ASSERT_FALSE(fenv_is_round_down()); + } } { ForceRoundingMode __r(RoundingMode::Downward); - if (__r.success) + if (__r.success) { ASSERT_TRUE(fenv_is_round_down()); + } } { ForceRoundingMode __r(RoundingMode::Nearest); - if (__r.success) + if (__r.success) { ASSERT_FALSE(fenv_is_round_down()); + } } { ForceRoundingMode __r(RoundingMode::TowardZero); - if (__r.success) + if (__r.success) { ASSERT_FALSE(fenv_is_round_down()); + } } } @@ -67,23 +75,27 @@ TEST(LlvmLibcFEnvImplTest, QuickRoundingNearestTest) { using LIBC_NAMESPACE::fputil::fenv_is_round_to_nearest; { ForceRoundingMode __r(RoundingMode::Upward); - if (__r.success) + if (__r.success) { ASSERT_FALSE(fenv_is_round_to_nearest()); + } } { ForceRoundingMode __r(RoundingMode::Downward); - if (__r.success) + if (__r.success) { ASSERT_FALSE(fenv_is_round_to_nearest()); + } } { ForceRoundingMode __r(RoundingMode::Nearest); - if (__r.success) + if (__r.success) { ASSERT_TRUE(fenv_is_round_to_nearest()); + } } { ForceRoundingMode __r(RoundingMode::TowardZero); - if (__r.success) + if (__r.success) { ASSERT_FALSE(fenv_is_round_to_nearest()); + } } } @@ -91,23 +103,27 @@ TEST(LlvmLibcFEnvImplTest, QuickRoundingTowardZeroTest) { using LIBC_NAMESPACE::fputil::fenv_is_round_to_zero; { ForceRoundingMode __r(RoundingMode::Upward); - if (__r.success) + if (__r.success) { ASSERT_FALSE(fenv_is_round_to_zero()); + } } { ForceRoundingMode __r(RoundingMode::Downward); - if (__r.success) + if (__r.success) { ASSERT_FALSE(fenv_is_round_to_zero()); + } } { ForceRoundingMode __r(RoundingMode::Nearest); - if (__r.success) + if (__r.success) { ASSERT_FALSE(fenv_is_round_to_zero()); + } } { ForceRoundingMode __r(RoundingMode::TowardZero); - if (__r.success) + if (__r.success) { ASSERT_TRUE(fenv_is_round_to_zero()); + } } } @@ -115,22 +131,26 @@ TEST(LlvmLibcFEnvImplTest, QuickGetRoundTest) { using LIBC_NAMESPACE::fputil::quick_get_round; { ForceRoundingMode __r(RoundingMode::Upward); - if (__r.success) + if (__r.success) { ASSERT_EQ(quick_get_round(), FE_UPWARD); + } } { ForceRoundingMode __r(RoundingMode::Downward); - if (__r.success) + if (__r.success) { ASSERT_EQ(quick_get_round(), FE_DOWNWARD); + } } { ForceRoundingMode __r(RoundingMode::Nearest); - if (__r.success) + if (__r.success) { ASSERT_EQ(quick_get_round(), FE_TONEAREST); + } } { ForceRoundingMode __r(RoundingMode::TowardZero); - if (__r.success) + if (__r.success) { ASSERT_EQ(quick_get_round(), FE_TOWARDZERO); + } } } diff --git a/libc/test/src/spawn/posix_spawn_file_actions_test.cpp b/libc/test/src/spawn/posix_spawn_file_actions_test.cpp index a343710829f10..008167e07221f 100644 --- a/libc/test/src/spawn/posix_spawn_file_actions_test.cpp +++ b/libc/test/src/spawn/posix_spawn_file_actions_test.cpp @@ -40,12 +40,15 @@ TEST(LlvmLibcPosixSpawnFileActionsTest, AddActions) { int action_count = 0; while (act != nullptr) { ++action_count; - if (action_count == 1) + if (action_count == 1) { ASSERT_EQ(act->type, LIBC_NAMESPACE::BaseSpawnFileAction::CLOSE); - if (action_count == 2) + } + if (action_count == 2) { ASSERT_EQ(act->type, LIBC_NAMESPACE::BaseSpawnFileAction::DUP2); - if (action_count == 3) + } + if (action_count == 3) { ASSERT_EQ(act->type, LIBC_NAMESPACE::BaseSpawnFileAction::OPEN); + } act = act->next; } ASSERT_EQ(action_count, 3); diff --git a/libc/test/src/stdio/sprintf_test.cpp b/libc/test/src/stdio/sprintf_test.cpp index 8b9c919bed203..b7e8b75485881 100644 --- a/libc/test/src/stdio/sprintf_test.cpp +++ b/libc/test/src/stdio/sprintf_test.cpp @@ -2433,6 +2433,9 @@ TEST_F(LlvmLibcSPrintfTest, FloatAutoConv) { written = LIBC_NAMESPACE::sprintf(buff, "%g", 9999999000000.00); ASSERT_STREQ_LEN(written, buff, "1e+13"); + written = LIBC_NAMESPACE::sprintf(buff, "%g", 0xa.aaaaaaaaaaaaaabp-7); + ASSERT_STREQ_LEN(written, buff, "0.0833333"); + // Simple Subnormal Tests. written = LIBC_NAMESPACE::sprintf(buff, "%g", 0x1.0p-1027); @@ -2457,9 +2460,16 @@ TEST_F(LlvmLibcSPrintfTest, FloatAutoConv) { // Length Modifier Tests. +#if defined(SPECIAL_X86_LONG_DOUBLE) + written = LIBC_NAMESPACE::sprintf(buff, "%Lg", 0xf.fffffffffffffffp+16380L); ASSERT_STREQ_LEN(written, buff, "1.18973e+4932"); + written = LIBC_NAMESPACE::sprintf(buff, "%Lg", 0xa.aaaaaaaaaaaaaabp-7L); + ASSERT_STREQ_LEN(written, buff, "0.0833333"); + +#endif // SPECIAL_X86_LONG_DOUBLE + // TODO: Uncomment the below tests after long double support is added /* written = LIBC_NAMESPACE::sprintf(buff, "%Lf", 1e100L); @@ -2757,6 +2767,15 @@ TEST_F(LlvmLibcSPrintfTest, FloatAutoConv) { written = LIBC_NAMESPACE::sprintf(buff, "%.10g", 0x1.0p-1074); ASSERT_STREQ_LEN(written, buff, "4.940656458e-324"); +#if defined(SPECIAL_X86_LONG_DOUBLE) + + written = LIBC_NAMESPACE::sprintf(buff, "%.60Lg", 0xa.aaaaaaaaaaaaaabp-7L); + ASSERT_STREQ_LEN( + written, buff, + "0.0833333333333333333355920878593448009041821933351457118988037"); + +#endif // SPECIAL_X86_LONG_DOUBLE + // Long double precision tests. // These are currently commented out because they require long double support // that isn't ready yet. diff --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt index b90da43f9a7b9..6088289532d77 100644 --- a/libc/test/src/string/CMakeLists.txt +++ b/libc/test/src/string/CMakeLists.txt @@ -425,8 +425,11 @@ function(add_libc_multi_impl_test name) get_target_property(required_cpu_features ${fq_config_name} REQUIRE_CPU_FEATURES) cpu_supports(can_run "${required_cpu_features}") if(can_run) + string(FIND ${fq_config_name} "." last_dot_loc REVERSE) + math(EXPR name_loc "${last_dot_loc} + 1") + string(SUBSTRING ${fq_config_name} ${name_loc} -1 target_name) add_libc_test( - ${fq_config_name}_test + ${target_name}_test SUITE libc-string-tests COMPILE_OPTIONS diff --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h index baac2d0e3a410..b9573e89f25a4 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.h +++ b/libc/utils/MPFRWrapper/MPFRUtils.h @@ -356,21 +356,25 @@ template bool round_to_long(T x, RoundingMode mode, long &result); { \ namespace mpfr = LIBC_NAMESPACE::testing::mpfr; \ mpfr::ForceRoundingMode __r1(mpfr::RoundingMode::Nearest); \ - if (__r1.success) \ + if (__r1.success) { \ EXPECT_MPFR_MATCH(op, input, match_value, ulp_tolerance, \ mpfr::RoundingMode::Nearest); \ + } \ mpfr::ForceRoundingMode __r2(mpfr::RoundingMode::Upward); \ - if (__r2.success) \ + if (__r2.success) { \ EXPECT_MPFR_MATCH(op, input, match_value, ulp_tolerance, \ mpfr::RoundingMode::Upward); \ + } \ mpfr::ForceRoundingMode __r3(mpfr::RoundingMode::Downward); \ - if (__r3.success) \ + if (__r3.success) { \ EXPECT_MPFR_MATCH(op, input, match_value, ulp_tolerance, \ mpfr::RoundingMode::Downward); \ + } \ mpfr::ForceRoundingMode __r4(mpfr::RoundingMode::TowardZero); \ - if (__r4.success) \ + if (__r4.success) { \ EXPECT_MPFR_MATCH(op, input, match_value, ulp_tolerance, \ mpfr::RoundingMode::TowardZero); \ + } \ } #define TEST_MPFR_MATCH_ROUNDING_SILENTLY(op, input, match_value, \ @@ -400,21 +404,25 @@ template bool round_to_long(T x, RoundingMode mode, long &result); { \ namespace mpfr = LIBC_NAMESPACE::testing::mpfr; \ mpfr::ForceRoundingMode __r1(mpfr::RoundingMode::Nearest); \ - if (__r1.success) \ + if (__r1.success) { \ ASSERT_MPFR_MATCH(op, input, match_value, ulp_tolerance, \ mpfr::RoundingMode::Nearest); \ + } \ mpfr::ForceRoundingMode __r2(mpfr::RoundingMode::Upward); \ - if (__r2.success) \ + if (__r2.success) { \ ASSERT_MPFR_MATCH(op, input, match_value, ulp_tolerance, \ mpfr::RoundingMode::Upward); \ + } \ mpfr::ForceRoundingMode __r3(mpfr::RoundingMode::Downward); \ - if (__r3.success) \ + if (__r3.success) { \ ASSERT_MPFR_MATCH(op, input, match_value, ulp_tolerance, \ mpfr::RoundingMode::Downward); \ + } \ mpfr::ForceRoundingMode __r4(mpfr::RoundingMode::TowardZero); \ - if (__r4.success) \ + if (__r4.success) { \ ASSERT_MPFR_MATCH(op, input, match_value, ulp_tolerance, \ mpfr::RoundingMode::TowardZero); \ + } \ } #endif // LLVM_LIBC_UTILS_TESTUTILS_MPFRUTILS_H diff --git a/libcxx/benchmarks/CMakeLists.txt b/libcxx/benchmarks/CMakeLists.txt index 56d22af049c44..1a4d634500180 100644 --- a/libcxx/benchmarks/CMakeLists.txt +++ b/libcxx/benchmarks/CMakeLists.txt @@ -173,6 +173,7 @@ endfunction() #============================================================================== set(BENCHMARK_TESTS algorithms.partition_point.bench.cpp + algorithms/count.bench.cpp algorithms/equal.bench.cpp algorithms/find.bench.cpp algorithms/lower_bound.bench.cpp diff --git a/libcxx/benchmarks/algorithms/count.bench.cpp b/libcxx/benchmarks/algorithms/count.bench.cpp new file mode 100644 index 0000000000000..7370293fd6efd --- /dev/null +++ b/libcxx/benchmarks/algorithms/count.bench.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include + +static void bm_vector_bool_count(benchmark::State& state) { + std::vector vec1(state.range(), false); + + for (auto _ : state) { + benchmark::DoNotOptimize(vec1); + benchmark::DoNotOptimize(std::count(vec1.begin(), vec1.end(), true)); + } +} +BENCHMARK(bm_vector_bool_count)->DenseRange(1, 8)->Range(16, 1 << 20); + +static void bm_vector_bool_ranges_count(benchmark::State& state) { + std::vector vec1(state.range(), false); + + for (auto _ : state) { + benchmark::DoNotOptimize(vec1); + benchmark::DoNotOptimize(std::ranges::count(vec1.begin(), vec1.end(), true)); + } +} +BENCHMARK(bm_vector_bool_ranges_count)->DenseRange(1, 8)->Range(16, 1 << 20); + +BENCHMARK_MAIN(); diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst index 0a5e99984fa75..b8d21334a77a5 100644 --- a/libcxx/docs/ReleaseNotes/18.rst +++ b/libcxx/docs/ReleaseNotes/18.rst @@ -52,11 +52,15 @@ Implemented Papers - P2697R1 - Interfacing ``bitset`` with ``string_view`` - P2443R1 - ``views::chunk_by`` - P2538R1 - ADL-proof ``std::projected`` +- P2614R2 - Deprecate ``numeric_limits::has_denorm`` Improvements and New Features ----------------------------- +- ``std::ranges::count`` is now optimized for ``vector::iterator``, which + can lead up to 350x performance improvements. + - The library now provides a hardened mode under which common cases of library undefined behavior will be turned into a reliable program termination. Vendors can configure whether the hardened mode is enabled by default with the ``LIBCXX_HARDENING_MODE`` variable at CMake configuration time. Users can control whether the hardened mode is @@ -87,6 +91,9 @@ Deprecations and Removals warning). ``_LIBCPP_ENABLE_ASSERTIONS`` will be removed entirely in the next release and setting it will become an error. See :ref:`the hardening documentation ` for more details. +- The non-conforming constructor ``std::future_error(std::error_code)`` has been removed. Please use the + ``std::future_error(std::future_errc)`` constructor provided in C++17 instead. + Upcoming Deprecations and Removals ---------------------------------- diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv index 67ef35ec39b2a..8be1ff588cf3b 100644 --- a/libcxx/docs/Status/Cxx23Issues.csv +++ b/libcxx/docs/Status/Cxx23Issues.csv @@ -198,7 +198,7 @@ "`3629 `__","``make_error_code`` and ``make_error_condition`` are customization points","November 2022","|Complete|","16.0","" "`3636 `__","``formatter::format`` should be ``const``-qualified","November 2022","|Complete|","16.0","|format|" "`3646 `__","``std::ranges::view_interface::size`` returns a signed type","November 2022","|Complete|","16.0","|ranges|" -"`3677 `__","Is a cv-qualified ``pair`` specially handled in uses-allocator construction?", "November 2022","","","" +"`3677 `__","Is a cv-qualified ``pair`` specially handled in uses-allocator construction?", "November 2022","|Complete|","18.0","" "`3717 `__","``common_view::end`` should improve ``random_access_range`` case", "November 2022","","","|ranges|" "`3732 `__","``prepend_range`` and ``append_range`` can't be amortized constant time", "November 2022","|Nothing to do|","","|ranges|" "`3736 `__","``move_iterator`` missing ``disable_sized_sentinel_for`` specialization", "November 2022","","","|ranges|" @@ -262,7 +262,7 @@ "`3742 `__","``deque::prepend_range`` needs to permute","February 2023","","","|ranges|" "`3790 `__","`P1467 `__ accidentally changed ``nexttoward``'s signature","February 2023","","","" "`3819 `__","``reference_meows_from_temporary`` should not use ``is_meowible``","February 2023","","","" -"`3821 `__","``uses_allocator_construction_args`` should have overload for ``pair-like``","February 2023","","","" +"`3821 `__","``uses_allocator_construction_args`` should have overload for ``pair-like``","February 2023","|Complete|","18.0.0","" "`3834 `__","Missing ``constexpr`` for ``std::intmax_t`` math functions in ````","February 2023","","","" "`3839 `__","``range_formatter``'s ``set_separator``, ``set_brackets``, and ``underlying`` functions should be ``noexcept``","February 2023","|Complete|","17.0","|format|" "`3841 `__","```` should not be ""all freestanding""","February 2023","","","" diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index 9cb49fd5176ea..35319fb7576d3 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -117,7 +117,7 @@ "`P2655R3 `__","LWG", "``common_reference_t`` of ``reference_wrapper`` Should Be a Reference Type","February 2023","","","" "`P2652R2 `__","LWG", "Disallow User Specialization of ``allocator_traits``","February 2023","","","" "`P2787R1 `__","LWG", "``pmr::generator`` - Promise Types are not Values","February 2023","","","" -"`P2614R2 `__","LWG", "Deprecate ``numeric_limits::has_denorm``","February 2023","","","" +"`P2614R2 `__","LWG", "Deprecate ``numeric_limits::has_denorm``","February 2023","|Complete|","18.0","" "`P2588R3 `__","LWG", "``barrier``’s phase completion guarantees","February 2023","","","" "`P2763R1 `__","LWG", "``layout_stride`` static extents default constructor fix","February 2023","","","" "`P2736R2 `__","CWG","Referencing The Unicode Standard","February 2023","","","|format|" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 2ec755236dbae..340353f8ebb41 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -838,6 +838,7 @@ set(files __utility/cmp.h __utility/convert_to_integral.h __utility/declval.h + __utility/empty.h __utility/exception_guard.h __utility/exchange.h __utility/forward.h @@ -851,7 +852,6 @@ set(files __utility/priority_tag.h __utility/rel_ops.h __utility/swap.h - __utility/terminate_on_exception.h __utility/to_underlying.h __utility/unreachable.h __variant/monostate.h diff --git a/libcxx/include/__algorithm/count.h b/libcxx/include/__algorithm/count.h index 6c8c7fda35df6..23a7d3c4dcfed 100644 --- a/libcxx/include/__algorithm/count.h +++ b/libcxx/include/__algorithm/count.h @@ -10,26 +10,83 @@ #ifndef _LIBCPP___ALGORITHM_COUNT_H #define _LIBCPP___ALGORITHM_COUNT_H +#include <__algorithm/iterator_operations.h> +#include <__algorithm/min.h> +#include <__bit/invert_if.h> +#include <__bit/popcount.h> #include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__fwd/bit_reference.h> #include <__iterator/iterator_traits.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD -template -_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 - typename iterator_traits<_InputIterator>::difference_type - count(_InputIterator __first, _InputIterator __last, const _Tp& __value) { - typename iterator_traits<_InputIterator>::difference_type __r(0); +// generic implementation +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename _IterOps<_AlgPolicy>::template __difference_type<_Iter> +__count(_Iter __first, _Sent __last, const _Tp& __value, _Proj& __proj) { + typename _IterOps<_AlgPolicy>::template __difference_type<_Iter> __r(0); for (; __first != __last; ++__first) - if (*__first == __value) + if (std::__invoke(__proj, *__first) == __value) ++__r; return __r; } +// __bit_iterator implementation +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __bit_iterator<_Cp, _IsConst>::difference_type +__count_bool(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n) { + using _It = __bit_iterator<_Cp, _IsConst>; + using __storage_type = typename _It::__storage_type; + using difference_type = typename _It::difference_type; + + const int __bits_per_word = _It::__bits_per_word; + difference_type __r = 0; + // do first partial word + if (__first.__ctz_ != 0) { + __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); + __storage_type __dn = std::min(__clz_f, __n); + __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); + __r = std::__libcpp_popcount(std::__invert_if(*__first.__seg_) & __m); + __n -= __dn; + ++__first.__seg_; + } + // do middle whole words + for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) + __r += std::__libcpp_popcount(std::__invert_if(*__first.__seg_)); + // do last partial word + if (__n > 0) { + __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); + __r += std::__libcpp_popcount(std::__invert_if(*__first.__seg_) & __m); + } + return __r; +} + +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __iter_diff_t<__bit_iterator<_Cp, _IsConst> > +__count(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, const _Tp& __value, _Proj&) { + if (__value) + return std::__count_bool(__first, static_cast(__last - __first)); + return std::__count_bool(__first, static_cast(__last - __first)); +} + +template +_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __iter_diff_t<_InputIterator> +count(_InputIterator __first, _InputIterator __last, const _Tp& __value) { + __identity __proj; + return std::__count<_ClassicAlgPolicy>(__first, __last, __value, __proj); +} + _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP___ALGORITHM_COUNT_H diff --git a/libcxx/include/__algorithm/pstl_any_all_none_of.h b/libcxx/include/__algorithm/pstl_any_all_none_of.h index b4b063ca4dda7..d93fdba2224c9 100644 --- a/libcxx/include/__algorithm/pstl_any_all_none_of.h +++ b/libcxx/include/__algorithm/pstl_any_all_none_of.h @@ -17,7 +17,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -35,19 +35,35 @@ template , enable_if_t, int> = 0> -_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool -any_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional __any_of( + _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) noexcept { return std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_any_of), - [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) { - return std::find_if(__policy, __g_first, __g_last, __g_pred) != __g_last; + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_any_of, _RawPolicy), + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) -> optional { + auto __res = std::__find_if(__policy, __g_first, __g_last, __g_pred); + if (!__res) + return nullopt; + return *__res != __g_last; }, std::move(__first), std::move(__last), std::move(__pred)); } +template , + enable_if_t, int> = 0> +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool +any_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + auto __res = std::__any_of(__policy, std::move(__first), std::move(__last), std::move(__pred)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + template void __pstl_all_of(); // declaration needed for the frontend dispatch below @@ -56,21 +72,37 @@ template , enable_if_t, int> = 0> -_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool -all_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional +__all_of(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Pred&& __pred) noexcept { return std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_all_of), - [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) { - return !std::any_of(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __value) { + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_all_of, _RawPolicy), + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) -> optional { + auto __res = std::__any_of(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __value) { return !__g_pred(__value); }); + if (!__res) + return nullopt; + return !*__res; }, std::move(__first), std::move(__last), std::move(__pred)); } +template , + enable_if_t, int> = 0> +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool +all_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + auto __res = std::__all_of(__policy, std::move(__first), std::move(__last), std::move(__pred)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + template void __pstl_none_of(); // declaration needed for the frontend dispatch below @@ -79,19 +111,35 @@ template , enable_if_t, int> = 0> -_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool -none_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional +__none_of(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Pred&& __pred) noexcept { return std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_none_of), - [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) { - return !std::any_of(__policy, __g_first, __g_last, __g_pred); + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_none_of, _RawPolicy), + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) -> optional { + auto __res = std::__any_of(__policy, __g_first, __g_last, __g_pred); + if (!__res) + return nullopt; + return !*__res; }, std::move(__first), std::move(__last), std::move(__pred)); } +template , + enable_if_t, int> = 0> +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool +none_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + auto __res = std::__none_of(__policy, std::move(__first), std::move(__last), std::move(__pred)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_backend.h b/libcxx/include/__algorithm/pstl_backend.h index 93372f019031b..94644e5c47b39 100644 --- a/libcxx/include/__algorithm/pstl_backend.h +++ b/libcxx/include/__algorithm/pstl_backend.h @@ -27,23 +27,38 @@ TODO: Documentation of how backends work A PSTL parallel backend is a tag type to which the following functions are associated, at minimum: template - void __pstl_for_each(_Backend, _ExecutionPolicy&&, _Iterator __first, _Iterator __last, _Func __f); + optional<__empty> __pstl_for_each(_Backend, _ExecutionPolicy&&, _Iterator __first, _Iterator __last, _Func __f); template - _Iterator __pstl_find_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); + optional<_Iterator> __pstl_find_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); template - void __pstl_stable_sort(_Backend, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp); + optional<__empty> + __pstl_stable_sort(_Backend, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp); + + template + _ForwardOutIterator __pstl_merge(_Backend, + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2, + _ForwardOutIterator __result, + _Comp __comp); template - _OutIterator __pstl_transform(_InIterator __first, _InIterator __last, _OutIterator __result, _UnaryOperation __op); + optional<_OutIterator> + __pstl_transform(_Backend, _InIterator __first, _InIterator __last, _OutIterator __result, _UnaryOperation __op); template - _OutIterator __pstl_transform(_InIterator1 __first1, - _InIterator1 __last1, - _InIterator2 __first2, - _OutIterator __result, - _BinaryOperation __op); + optional<_OutIterator> __pstl_transform(_InIterator1 __first1, + _InIterator2 __first2, + _InIterator1 __last1, + _OutIterator __result, + _BinaryOperation __op); template - _Tp __pstl_transform_reduce(_Backend, - _Iterator1 __first1, - _Iterator1 __last1, - _Iterator2 __first2, - _Iterator2 __last2, - _Tp __init, - _BinaryOperation1 __reduce, - _BinaryOperation2 __transform); + optional<_Tp> __pstl_transform_reduce(_Backend, + _Iterator1 __first1, + _Iterator1 __last1, + _Iterator2 __first2, + _Iterator2 __last2, + _Tp __init, + _BinaryOperation1 __reduce, + _BinaryOperation2 __transform); template - _Tp __pstl_transform_reduce(_Backend, - _Iterator __first, - _Iterator __last, - _Tp __init, - _BinaryOperation __reduce, - _UnaryOperation __transform); + optional<_Tp> __pstl_transform_reduce(_Backend, + _Iterator __first, + _Iterator __last, + _Tp __init, + _BinaryOperation __reduce, + _UnaryOperation __transform); // TODO: Complete this list @@ -75,86 +90,95 @@ algorithms, otherwise they are implemented in terms of other algorithms. If none implemented, all the algorithms will eventually forward to the basis algorithms listed above: template - void __pstl_for_each_n(_Backend, _Iterator __first, _Size __n, _Func __f); + optional<__empty> __pstl_for_each_n(_Backend, _Iterator __first, _Size __n, _Func __f); template - bool __pstl_any_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred); + optional __pstl_any_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred); template - bool __pstl_all_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred); + optional __pstl_all_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred); template - bool __pstl_none_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred); + optional __pstl_none_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred); template - _Iterator __pstl_find(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value); + optional<_Iterator> __pstl_find(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value); template - _Iterator __pstl_find_if_not(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); + optional<_Iterator> __pstl_find_if_not(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); template - void __pstl_fill(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value); + optional<__empty> __pstl_fill(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value); template - void __pstl_fill_n(_Backend, _Iterator __first, _SizeT __n, const _Tp& __value); + optional<__empty> __pstl_fill_n(_Backend, _Iterator __first, _SizeT __n, const _Tp& __value); template - void __pstl_generate(_Backend, _Iterator __first, _Iterator __last, _Generator __gen); + optional<__empty> __pstl_generate(_Backend, _Iterator __first, _Iterator __last, _Generator __gen); template - void __pstl_is_partitioned(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); + optional<__empty> __pstl_is_partitioned(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); template - void __pstl_generator_n(_Backend, _Iterator __first, _Size __n, _Generator __gen); + optional<__empty> __pstl_generator_n(_Backend, _Iterator __first, _Size __n, _Generator __gen); template - _OutIterator __pstl_merge(_Backend, - _Iterator1 __first1, - _Iterator1 __last1, - _Iterator2 __first2, - _Iterator2 __last2, - _OutIterator __result, - _Comp __comp); + optional<_OutIterator> __pstl_merge(_Backend, + _Iterator1 __first1, + _Iterator1 __last1, + _Iterator2 __first2, + _Iterator2 __last2, + _OutIterator __result, + _Comp __comp); template - _Tp __pstl_reduce(_Backend, _Iterator __first, _Iterator __last, _Tp __init, _BinaryOperation __op); + optional<_Tp> __pstl_reduce(_Backend, _Iterator __first, _Iterator __last, _Tp __init, _BinaryOperation __op); temlate - __iter_value_type<_Iterator> __pstl_reduce(_Backend, _Iterator __first, _Iterator __last); + optional<__iter_value_type<_Iterator>> __pstl_reduce(_Backend, _Iterator __first, _Iterator __last); template - __iter_diff_t<_Iterator> __pstl_count(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value); + optional<__iter_diff_t<_Iterator>> __pstl_count(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value); template - __iter_diff_t<_Iterator> __pstl_count_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); + optional<__iter_diff_t<_Iterator>> __pstl_count_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); template - void __pstl_replace(_Backend, _Iterator __first, _Iterator __last, const _Tp& __old_value, const _Tp& __new_value); + optional<__empty> + __pstl_replace(_Backend, _Iterator __first, _Iterator __last, const _Tp& __old_value, const _Tp& __new_value); template - void __pstl_replace_if(_Backend, _Iterator __first, _Iterator __last, _Pred __pred, const _Tp& __new_value); + optional<__empty> + __pstl_replace_if(_Backend, _Iterator __first, _Iterator __last, _Pred __pred, const _Tp& __new_value); template - void __pstl_replace_copy(_Backend, - _Iterator __first, - _Iterator __last, - _OutIterator __result, - const _Tp& __old_value, - const _Tp& __new_value); + optional<__empty> __pstl_replace_copy(_Backend, + _Iterator __first, + _Iterator __last, + _OutIterator __result, + const _Tp& __old_value, + const _Tp& __new_value); template - void __pstl_replace_copy_if(_Backend, - _Iterator __first, - _Iterator __last, - _OutIterator __result, - _Pred __pred, - const _Tp& __new_value); + optional<__empty> __pstl_replace_copy_if(_Backend, + _Iterator __first, + _Iterator __last, + _OutIterator __result, + _Pred __pred, + const _Tp& __new_value); template - void __pstl_sort(_Backend, _Iterator __first, _Iterator __last, _Comp __comp); + optional<__empty> __pstl_sort(_Backend, _Iterator __first, _Iterator __last, _Comp __comp); // TODO: Complete this list +Exception handling +================== + +PSTL backends are expected to report errors (i.e. failure to allocate) by returning a disengaged `optional` from their +implementation. Exceptions shouldn't be used to report an internal failure-to-allocate, since all exceptions are turned +into a program termination at the front-end level. When a backend returns a disengaged `optional` to the frontend, the +frontend will turn that into a call to `std::__throw_bad_alloc();` to report the internal failure to the user. */ template diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backend.h b/libcxx/include/__algorithm/pstl_backends/cpu_backend.h index e54f331b9430b..6980ded189ea2 100644 --- a/libcxx/include/__algorithm/pstl_backends/cpu_backend.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backend.h @@ -15,10 +15,11 @@ // _Functor takes a subrange for [__first, __last) that should be executed in serial template - void __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func); + optional<__empty> __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func); template - _Tp __parallel_transform_reduce(_Iterator __first, _Iterator __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduction); + optional<_Tp> + __parallel_transform_reduce(_Iterator __first, _Iterator __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduction); // Cancel the execution of other jobs - they aren't needed anymore void __cancel_execution(); @@ -28,7 +29,7 @@ class _RandomAccessIterator3, class _Compare, class _LeafMerge> - void __parallel_merge( + optional __parallel_merge( _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2, @@ -44,6 +45,14 @@ _LeafSort __leaf_sort); TODO: Document the parallel backend + +Exception handling +================== + +CPU backends are expected to report errors (i.e. failure to allocate) by returning a disengaged `optional` from their +implementation. Exceptions shouldn't be used to report an internal failure-to-allocate, since all exceptions are turned +into a program termination at the front-end level. When a backend returns a disengaged `optional` to the frontend, the +frontend will turn that into a call to `std::__throw_bad_alloc();` to report the internal failure to the user. */ #include <__algorithm/pstl_backends/cpu_backends/any_of.h> diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h index c8a071af82ac6..13dff80086e72 100644 --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h @@ -18,24 +18,30 @@ #include <__functional/operations.h> #include <__iterator/concepts.h> #include <__type_traits/is_execution_policy.h> +#include <__utility/move.h> #include <__utility/pair.h> -#include <__utility/terminate_on_exception.h> #include +#include #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD template -_LIBCPP_HIDE_FROM_ABI bool __parallel_or(_Index __first, _Index __last, _Brick __f) { +_LIBCPP_HIDE_FROM_ABI optional __parallel_or(_Index __first, _Index __last, _Brick __f) { std::atomic __found(false); - __par_backend::__parallel_for(__first, __last, [__f, &__found](_Index __i, _Index __j) { + auto __ret = __par_backend::__parallel_for(__first, __last, [__f, &__found](_Index __i, _Index __j) { if (!__found.load(std::memory_order_relaxed) && __f(__i, __j)) { __found.store(true, std::memory_order_relaxed); __par_backend::__cancel_execution(); } }); - return __found; + if (!__ret) + return nullopt; + return static_cast(__found); } // TODO: check whether __simd_first() can be used here @@ -64,17 +70,17 @@ _LIBCPP_HIDE_FROM_ABI bool __simd_or(_Index __first, _DifferenceType __n, _Pred } template -_LIBCPP_HIDE_FROM_ABI bool +_LIBCPP_HIDE_FROM_ABI optional __pstl_any_of(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { - return std::__terminate_on_exception([&] { - return std::__parallel_or( - __first, __last, [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { - return std::__pstl_any_of<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, __brick_first, __brick_last, __pred); - }); - }); + return std::__parallel_or( + __first, __last, [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + auto __res = std::__pstl_any_of<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, __brick_first, __brick_last, __pred); + _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!"); + return *std::move(__res); + }); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { return std::__simd_or(__first, __last - __first, __pred); @@ -85,6 +91,8 @@ __pstl_any_of(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __la _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 #endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_ANY_OF_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h index 8b531887c7318..64babe9fd2bda 100644 --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h @@ -14,7 +14,8 @@ #include <__config> #include <__iterator/concepts.h> #include <__type_traits/is_execution_policy.h> -#include <__utility/terminate_on_exception.h> +#include <__utility/empty.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -34,22 +35,23 @@ _LIBCPP_HIDE_FROM_ABI _Index __simd_fill_n(_Index __first, _DifferenceType __n, } template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI optional<__empty> __pstl_fill(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { - std::__terminate_on_exception([&] { - __par_backend::__parallel_for( - __first, __last, [&__value](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { - std::__pstl_fill<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, __brick_first, __brick_last, __value); - }); - }); + return __par_backend::__parallel_for( + __first, __last, [&__value](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + [[maybe_unused]] auto __res = std::__pstl_fill<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, __brick_first, __brick_last, __value); + _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!"); + }); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { std::__simd_fill_n(__first, __last - __first, __value); + return __empty{}; } else { std::fill(__first, __last, __value); + return __empty{}; } } diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h index 91610c040857b..170470e4fb7ed 100644 --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h @@ -17,9 +17,10 @@ #include <__iterator/concepts.h> #include <__iterator/iterator_traits.h> #include <__type_traits/is_execution_policy.h> +#include <__utility/move.h> #include <__utility/pair.h> -#include <__utility/terminate_on_exception.h> #include +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -27,31 +28,37 @@ #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD template -_LIBCPP_HIDE_FROM_ABI _Index +_LIBCPP_HIDE_FROM_ABI optional<_Index> __parallel_find(_Index __first, _Index __last, _Brick __f, _Compare __comp, bool __b_first) { typedef typename std::iterator_traits<_Index>::difference_type _DifferenceType; const _DifferenceType __n = __last - __first; _DifferenceType __initial_dist = __b_first ? __n : -1; std::atomic<_DifferenceType> __extremum(__initial_dist); // TODO: find out what is better here: parallel_for or parallel_reduce - __par_backend::__parallel_for(__first, __last, [__comp, __f, __first, &__extremum](_Index __i, _Index __j) { - // See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of - // why using a shared variable scales fairly well in this situation. - if (__comp(__i - __first, __extremum)) { - _Index __res = __f(__i, __j); - // If not '__last' returned then we found what we want so put this to extremum - if (__res != __j) { - const _DifferenceType __k = __res - __first; - for (_DifferenceType __old = __extremum; __comp(__k, __old); __old = __extremum) { - __extremum.compare_exchange_weak(__old, __k); + auto __res = + __par_backend::__parallel_for(__first, __last, [__comp, __f, __first, &__extremum](_Index __i, _Index __j) { + // See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of + // why using a shared variable scales fairly well in this situation. + if (__comp(__i - __first, __extremum)) { + _Index __result = __f(__i, __j); + // If not '__last' returned then we found what we want so put this to extremum + if (__result != __j) { + const _DifferenceType __k = __result - __first; + for (_DifferenceType __old = __extremum; __comp(__k, __old); __old = __extremum) { + __extremum.compare_exchange_weak(__old, __k); + } + } } - } - } - }); - return __extremum != __initial_dist ? __first + __extremum : __last; + }); + if (!__res) + return nullopt; + return __extremum.load() != __initial_dist ? __first + __extremum.load() : __last; } template @@ -91,21 +98,21 @@ __simd_first(_Index __first, _DifferenceType __begin, _DifferenceType __end, _Co } template -_LIBCPP_HIDE_FROM_ABI _ForwardIterator +_LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator> __pstl_find_if(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { - return std::__terminate_on_exception([&] { - return std::__parallel_find( - __first, - __last, - [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { - return std::__pstl_find_if<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, __brick_first, __brick_last, __pred); - }, - less<>{}, - true); - }); + return std::__parallel_find( + __first, + __last, + [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + auto __res = std::__pstl_find_if<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, __brick_first, __brick_last, __pred); + _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!"); + return *std::move(__res); + }, + less<>{}, + true); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { using __diff_t = __iter_diff_t<_ForwardIterator>; @@ -119,6 +126,8 @@ __pstl_find_if(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __l _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 #endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_FIND_IF_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h index f6f22fdd8713c..6cfef932aa48d 100644 --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h @@ -14,7 +14,8 @@ #include <__config> #include <__iterator/concepts.h> #include <__type_traits/is_execution_policy.h> -#include <__utility/terminate_on_exception.h> +#include <__utility/empty.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -34,22 +35,23 @@ _LIBCPP_HIDE_FROM_ABI _Iterator __simd_walk_1(_Iterator __first, _DifferenceType } template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI optional<__empty> __pstl_for_each(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Functor __func) { if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { - std::__terminate_on_exception([&] { - std::__par_backend::__parallel_for( - __first, __last, [__func](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { - std::__pstl_for_each<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, __brick_first, __brick_last, __func); - }); - }); + return std::__par_backend::__parallel_for( + __first, __last, [__func](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + [[maybe_unused]] auto __res = std::__pstl_for_each<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, __brick_first, __brick_last, __func); + _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!"); + }); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { std::__simd_walk_1(__first, __last - __first, __func); + return __empty{}; } else { std::for_each(__first, __last, __func); + return __empty{}; } } diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h index 50b6e0b1d0a03..e885e7f225172 100644 --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h @@ -23,11 +23,13 @@ #include <__memory/construct_at.h> #include <__memory/unique_ptr.h> #include <__numeric/reduce.h> +#include <__utility/empty.h> +#include <__utility/exception_guard.h> #include <__utility/move.h> #include <__utility/pair.h> -#include <__utility/terminate_on_exception.h> #include #include +#include _LIBCPP_PUSH_MACROS #include <__undef_macros> @@ -61,8 +63,9 @@ struct __chunk_partitions { [[__gnu__::__const__]] _LIBCPP_EXPORTED_FROM_ABI __chunk_partitions __partition_chunks(ptrdiff_t __size) noexcept; template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI optional<__empty> __dispatch_parallel_for(__chunk_partitions __partitions, _RandomAccessIterator __first, _Functor __func) { + // Perform the chunked execution. __libdispatch::__dispatch_apply(__partitions.__chunk_count_, [&](size_t __chunk) { auto __this_chunk_size = __chunk == 0 ? __partitions.__first_chunk_size_ : __partitions.__chunk_size_; auto __index = @@ -71,10 +74,12 @@ __dispatch_parallel_for(__chunk_partitions __partitions, _RandomAccessIterator _ : (__chunk * __partitions.__chunk_size_) + (__partitions.__first_chunk_size_ - __partitions.__chunk_size_); __func(__first + __index, __first + __index + __this_chunk_size); }); + + return __empty{}; } template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func) { return __libdispatch::__dispatch_parallel_for( __libdispatch::__partition_chunks(__last - __first), std::move(__first), std::move(__func)); @@ -95,23 +100,23 @@ template -_LIBCPP_HIDE_FROM_ABI void __parallel_merge( +_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_merge( _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2, _RandomAccessIterator3 __result, _Compare __comp, - _LeafMerge __leaf_merge) { + _LeafMerge __leaf_merge) noexcept { __chunk_partitions __partitions = __libdispatch::__partition_chunks(std::max(__last1 - __first1, __last2 - __first2)); if (__partitions.__chunk_count_ == 0) - return; + return __empty{}; if (__partitions.__chunk_count_ == 1) { __leaf_merge(__first1, __last1, __first2, __last2, __result, __comp); - return; + return __empty{}; } using __merge_range_t = __merge_range<_RandomAccessIterator1, _RandomAccessIterator2, _RandomAccessIterator3>; @@ -122,61 +127,76 @@ _LIBCPP_HIDE_FROM_ABI void __parallel_merge( std::destroy_n(__ptr, __n_ranges); std::allocator<__merge_range_t>().deallocate(__ptr, __n_ranges); }; + unique_ptr<__merge_range_t[], decltype(__destroy)> __ranges( - std::allocator<__merge_range_t>().allocate(__n_ranges), __destroy); + [&]() -> __merge_range_t* { +# ifndef _LIBCPP_HAS_NO_EXCEPTIONS + try { +# endif + return std::allocator<__merge_range_t>().allocate(__n_ranges); +# ifndef _LIBCPP_HAS_NO_EXCEPTIONS + } catch (const std::bad_alloc&) { + return nullptr; + } +# endif + }(), + __destroy); + + if (!__ranges) + return nullopt; // TODO: Improve the case where the smaller range is merged into just a few (or even one) chunks of the larger case - std::__terminate_on_exception([&] { - __merge_range_t* __r = __ranges.get(); - std::__construct_at(__r++, __first1, __first2, __result); - - bool __iterate_first_range = __last1 - __first1 > __last2 - __first2; - - auto __compute_chunk = [&](size_t __chunk_size) -> __merge_range_t { - auto [__mid1, __mid2] = [&] { - if (__iterate_first_range) { - auto __m1 = __first1 + __chunk_size; - auto __m2 = std::lower_bound(__first2, __last2, __m1[-1], __comp); - return std::make_pair(__m1, __m2); - } else { - auto __m2 = __first2 + __chunk_size; - auto __m1 = std::lower_bound(__first1, __last1, __m2[-1], __comp); - return std::make_pair(__m1, __m2); - } - }(); + __merge_range_t* __r = __ranges.get(); + std::__construct_at(__r++, __first1, __first2, __result); - __result += (__mid1 - __first1) + (__mid2 - __first2); - __first1 = __mid1; - __first2 = __mid2; - return {std::move(__mid1), std::move(__mid2), __result}; - }; + bool __iterate_first_range = __last1 - __first1 > __last2 - __first2; - // handle first chunk - std::__construct_at(__r++, __compute_chunk(__partitions.__first_chunk_size_)); - - // handle 2 -> N - 1 chunks - for (ptrdiff_t __i = 0; __i != __partitions.__chunk_count_ - 2; ++__i) - std::__construct_at(__r++, __compute_chunk(__partitions.__chunk_size_)); - - // handle last chunk - std::__construct_at(__r, __last1, __last2, __result); - - __libdispatch::__dispatch_apply(__partitions.__chunk_count_, [&](size_t __index) { - auto __first_iters = __ranges[__index]; - auto __last_iters = __ranges[__index + 1]; - __leaf_merge( - __first_iters.__mid1_, - __last_iters.__mid1_, - __first_iters.__mid2_, - __last_iters.__mid2_, - __first_iters.__result_, - __comp); - }); + auto __compute_chunk = [&](size_t __chunk_size) -> __merge_range_t { + auto [__mid1, __mid2] = [&] { + if (__iterate_first_range) { + auto __m1 = __first1 + __chunk_size; + auto __m2 = std::lower_bound(__first2, __last2, __m1[-1], __comp); + return std::make_pair(__m1, __m2); + } else { + auto __m2 = __first2 + __chunk_size; + auto __m1 = std::lower_bound(__first1, __last1, __m2[-1], __comp); + return std::make_pair(__m1, __m2); + } + }(); + + __result += (__mid1 - __first1) + (__mid2 - __first2); + __first1 = __mid1; + __first2 = __mid2; + return {std::move(__mid1), std::move(__mid2), __result}; + }; + + // handle first chunk + std::__construct_at(__r++, __compute_chunk(__partitions.__first_chunk_size_)); + + // handle 2 -> N - 1 chunks + for (ptrdiff_t __i = 0; __i != __partitions.__chunk_count_ - 2; ++__i) + std::__construct_at(__r++, __compute_chunk(__partitions.__chunk_size_)); + + // handle last chunk + std::__construct_at(__r, __last1, __last2, __result); + + __libdispatch::__dispatch_apply(__partitions.__chunk_count_, [&](size_t __index) { + auto __first_iters = __ranges[__index]; + auto __last_iters = __ranges[__index + 1]; + __leaf_merge( + __first_iters.__mid1_, + __last_iters.__mid1_, + __first_iters.__mid2_, + __last_iters.__mid2_, + __first_iters.__result_, + __comp); }); + + return __empty{}; } template -_LIBCPP_HIDE_FROM_ABI _Value __parallel_transform_reduce( +_LIBCPP_HIDE_FROM_ABI optional<_Value> __parallel_transform_reduce( _RandomAccessIterator __first, _RandomAccessIterator __last, _Transform __transform, @@ -216,26 +236,26 @@ _LIBCPP_HIDE_FROM_ABI _Value __parallel_transform_reduce( } }); - return std::__terminate_on_exception([&] { - return std::reduce( - std::make_move_iterator(__values.get()), - std::make_move_iterator(__values.get() + __partitions.__chunk_count_), - std::move(__init), - __combiner); - }); + return std::reduce( + std::make_move_iterator(__values.get()), + std::make_move_iterator(__values.get() + __partitions.__chunk_count_), + std::move(__init), + __combiner); } template -_LIBCPP_HIDE_FROM_ABI void __parallel_stable_sort( +_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_stable_sort( _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp, _LeafSort __leaf_sort) { const auto __size = __last - __first; auto __partitions = __libdispatch::__partition_chunks(__size); if (__partitions.__chunk_count_ == 0) - return; + return __empty{}; - if (__partitions.__chunk_count_ == 1) - return __leaf_sort(__first, __last, __comp); + if (__partitions.__chunk_count_ == 1) { + __leaf_sort(__first, __last, __comp); + return __empty{}; + } using _Value = __iter_value_type<_RandomAccessIterator>; @@ -247,70 +267,70 @@ _LIBCPP_HIDE_FROM_ABI void __parallel_stable_sort( // TODO: use __uninitialized_buffer unique_ptr<_Value[], decltype(__destroy)> __values(std::allocator<_Value>().allocate(__size), __destroy); - return std::__terminate_on_exception([&] { - // Initialize all elements to a moved-from state - // TODO: Don't do this - this can be done in the first merge - see https://llvm.org/PR63928 - std::__construct_at(__values.get(), std::move(*__first)); - for (__iter_diff_t<_RandomAccessIterator> __i = 1; __i != __size; ++__i) { - std::__construct_at(__values.get() + __i, std::move(__values.get()[__i - 1])); - } - *__first = std::move(__values.get()[__size - 1]); - - __libdispatch::__dispatch_parallel_for( - __partitions, - __first, - [&__leaf_sort, &__comp](_RandomAccessIterator __chunk_first, _RandomAccessIterator __chunk_last) { - __leaf_sort(std::move(__chunk_first), std::move(__chunk_last), __comp); - }); - - bool __objects_are_in_buffer = false; - do { - const auto __old_chunk_size = __partitions.__chunk_size_; - if (__partitions.__chunk_count_ % 2 == 1) { - auto __inplace_merge_chunks = [&__comp, &__partitions](auto __first_chunk_begin) { - std::inplace_merge( - __first_chunk_begin, - __first_chunk_begin + __partitions.__first_chunk_size_, - __first_chunk_begin + __partitions.__first_chunk_size_ + __partitions.__chunk_size_, - __comp); - }; - if (__objects_are_in_buffer) - __inplace_merge_chunks(__values.get()); - else - __inplace_merge_chunks(__first); - __partitions.__first_chunk_size_ += 2 * __partitions.__chunk_size_; - } else { - __partitions.__first_chunk_size_ += __partitions.__chunk_size_; - } - - __partitions.__chunk_size_ *= 2; - __partitions.__chunk_count_ /= 2; - - auto __merge_chunks = [__partitions, __old_chunk_size, &__comp](auto __from_first, auto __to_first) { - __libdispatch::__dispatch_parallel_for( - __partitions, - __from_first, - [__old_chunk_size, &__from_first, &__to_first, &__comp](auto __chunk_first, auto __chunk_last) { - std::merge(std::make_move_iterator(__chunk_first), - std::make_move_iterator(__chunk_last - __old_chunk_size), - std::make_move_iterator(__chunk_last - __old_chunk_size), - std::make_move_iterator(__chunk_last), - __to_first + (__chunk_first - __from_first), - __comp); - }); + // Initialize all elements to a moved-from state + // TODO: Don't do this - this can be done in the first merge - see https://llvm.org/PR63928 + std::__construct_at(__values.get(), std::move(*__first)); + for (__iter_diff_t<_RandomAccessIterator> __i = 1; __i != __size; ++__i) { + std::__construct_at(__values.get() + __i, std::move(__values.get()[__i - 1])); + } + *__first = std::move(__values.get()[__size - 1]); + + __libdispatch::__dispatch_parallel_for( + __partitions, + __first, + [&__leaf_sort, &__comp](_RandomAccessIterator __chunk_first, _RandomAccessIterator __chunk_last) { + __leaf_sort(std::move(__chunk_first), std::move(__chunk_last), __comp); + }); + + bool __objects_are_in_buffer = false; + do { + const auto __old_chunk_size = __partitions.__chunk_size_; + if (__partitions.__chunk_count_ % 2 == 1) { + auto __inplace_merge_chunks = [&__comp, &__partitions](auto __first_chunk_begin) { + std::inplace_merge( + __first_chunk_begin, + __first_chunk_begin + __partitions.__first_chunk_size_, + __first_chunk_begin + __partitions.__first_chunk_size_ + __partitions.__chunk_size_, + __comp); }; - if (__objects_are_in_buffer) - __merge_chunks(__values.get(), __first); + __inplace_merge_chunks(__values.get()); else - __merge_chunks(__first, __values.get()); - __objects_are_in_buffer = !__objects_are_in_buffer; - } while (__partitions.__chunk_count_ > 1); - - if (__objects_are_in_buffer) { - std::move(__values.get(), __values.get() + __size, __first); + __inplace_merge_chunks(__first); + __partitions.__first_chunk_size_ += 2 * __partitions.__chunk_size_; + } else { + __partitions.__first_chunk_size_ += __partitions.__chunk_size_; } - }); + + __partitions.__chunk_size_ *= 2; + __partitions.__chunk_count_ /= 2; + + auto __merge_chunks = [__partitions, __old_chunk_size, &__comp](auto __from_first, auto __to_first) { + __libdispatch::__dispatch_parallel_for( + __partitions, + __from_first, + [__old_chunk_size, &__from_first, &__to_first, &__comp](auto __chunk_first, auto __chunk_last) { + std::merge(std::make_move_iterator(__chunk_first), + std::make_move_iterator(__chunk_last - __old_chunk_size), + std::make_move_iterator(__chunk_last - __old_chunk_size), + std::make_move_iterator(__chunk_last), + __to_first + (__chunk_first - __from_first), + __comp); + }); + }; + + if (__objects_are_in_buffer) + __merge_chunks(__values.get(), __first); + else + __merge_chunks(__first, __values.get()); + __objects_are_in_buffer = !__objects_are_in_buffer; + } while (__partitions.__chunk_count_ > 1); + + if (__objects_are_in_buffer) { + std::move(__values.get(), __values.get() + __size, __first); + } + + return __empty{}; } _LIBCPP_HIDE_FROM_ABI inline void __cancel_execution() {} diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h index c4b28e95024ff..b0db70f58b2ef 100644 --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h @@ -15,7 +15,7 @@ #include <__iterator/concepts.h> #include <__type_traits/is_execution_policy.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -23,6 +23,9 @@ #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD template -_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_merge( +_LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __pstl_merge( __cpu_backend_tag, _ForwardIterator1 __first1, _ForwardIterator1 __last1, @@ -42,31 +45,32 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_merge( __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value && __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value && __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) { - return std::__terminate_on_exception([&] { - __par_backend::__parallel_merge( - __first1, - __last1, - __first2, - __last2, - __result, - __comp, - [](_ForwardIterator1 __g_first1, - _ForwardIterator1 __g_last1, - _ForwardIterator2 __g_first2, - _ForwardIterator2 __g_last2, - _ForwardOutIterator __g_result, - _Comp __g_comp) { - return std::__pstl_merge<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, - std::move(__g_first1), - std::move(__g_last1), - std::move(__g_first2), - std::move(__g_last2), - std::move(__g_result), - std::move(__g_comp)); - }); - return __result + (__last1 - __first1) + (__last2 - __first2); - }); + auto __res = __par_backend::__parallel_merge( + __first1, + __last1, + __first2, + __last2, + __result, + __comp, + [](_ForwardIterator1 __g_first1, + _ForwardIterator1 __g_last1, + _ForwardIterator2 __g_first2, + _ForwardIterator2 __g_last2, + _ForwardOutIterator __g_result, + _Comp __g_comp) { + [[maybe_unused]] auto __g_res = std::__pstl_merge<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, + std::move(__g_first1), + std::move(__g_last1), + std::move(__g_first2), + std::move(__g_last2), + std::move(__g_result), + std::move(__g_comp)); + _LIBCPP_ASSERT_INTERNAL(__g_res, "unsed/sed should never try to allocate!"); + }); + if (!__res) + return nullopt; + return __result + (__last1 - __first1) + (__last2 - __first2); } else { return std::merge(__first1, __last1, __first2, __last2, __result, __comp); } @@ -74,6 +78,8 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_merge( _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 #endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_MERGE_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h index f151c3b098f67..afcc7ffb26613 100644 --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h @@ -11,8 +11,10 @@ #define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_SERIAL_H #include <__config> +#include <__utility/empty.h> #include <__utility/move.h> #include +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -20,26 +22,32 @@ #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD namespace __par_backend { inline namespace __serial_cpu_backend { template -_LIBCPP_HIDE_FROM_ABI void __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) { +_LIBCPP_HIDE_FROM_ABI optional<__empty> +__parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) { __f(__first, __last); + return __empty{}; } template -_LIBCPP_HIDE_FROM_ABI _Tp +_LIBCPP_HIDE_FROM_ABI optional<_Tp> __parallel_transform_reduce(_Index __first, _Index __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduce __reduce) { return __reduce(std::move(__first), std::move(__last), std::move(__init)); } template -_LIBCPP_HIDE_FROM_ABI void __parallel_stable_sort( +_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_stable_sort( _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, _LeafSort __leaf_sort) { __leaf_sort(__first, __last, __comp); + return __empty{}; } _LIBCPP_HIDE_FROM_ABI inline void __cancel_execution() {} @@ -49,7 +57,7 @@ template -_LIBCPP_HIDE_FROM_ABI void __parallel_merge( +_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_merge( _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2, @@ -58,6 +66,7 @@ _LIBCPP_HIDE_FROM_ABI void __parallel_merge( _Compare __comp, _LeafMerge __leaf_merge) { __leaf_merge(__first1, __last1, __first2, __last2, __outit, __comp); + return __empty{}; } // TODO: Complete this list @@ -67,6 +76,8 @@ _LIBCPP_HIDE_FROM_ABI void __parallel_merge( _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && && _LIBCPP_STD_VER >= 17 #endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_SERIAL_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/stable_sort.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/stable_sort.h index 0a701443b3c40..34c423586c4b7 100644 --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/stable_sort.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/stable_sort.h @@ -13,7 +13,8 @@ #include <__algorithm/stable_sort.h> #include <__config> #include <__type_traits/is_execution_policy.h> -#include <__utility/terminate_on_exception.h> +#include <__utility/empty.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -24,17 +25,16 @@ _LIBCPP_BEGIN_NAMESPACE_STD template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI optional<__empty> __pstl_stable_sort(__cpu_backend_tag, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) { if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy>) { - std::__terminate_on_exception([&] { - __par_backend::__parallel_stable_sort( - __first, __last, __comp, [](_RandomAccessIterator __g_first, _RandomAccessIterator __g_last, _Comp __g_comp) { - std::stable_sort(__g_first, __g_last, __g_comp); - }); - }); + return __par_backend::__parallel_stable_sort( + __first, __last, __comp, [](_RandomAccessIterator __g_first, _RandomAccessIterator __g_last, _Comp __g_comp) { + std::stable_sort(__g_first, __g_last, __g_comp); + }); } else { std::stable_sort(__first, __last, __comp); + return __empty{}; } } diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h index 30eb0ae3626d4..eb11a961b760c 100644 --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h @@ -11,8 +11,10 @@ #include <__assert> #include <__config> +#include <__utility/empty.h> #include <__utility/move.h> #include +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -32,20 +34,23 @@ namespace __par_backend { inline namespace __thread_cpu_backend { template -_LIBCPP_HIDE_FROM_ABI void __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) { +_LIBCPP_HIDE_FROM_ABI optional<__empty> +__parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) { __f(__first, __last); + return __empty{}; } template -_LIBCPP_HIDE_FROM_ABI _Tp +_LIBCPP_HIDE_FROM_ABI optional<_Tp> __parallel_transform_reduce(_Index __first, _Index __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduce __reduce) { return __reduce(std::move(__first), std::move(__last), std::move(__init)); } template -_LIBCPP_HIDE_FROM_ABI void __parallel_stable_sort( +_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_stable_sort( _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, _LeafSort __leaf_sort) { __leaf_sort(__first, __last, __comp); + return __empty{}; } _LIBCPP_HIDE_FROM_ABI inline void __cancel_execution() {} @@ -55,7 +60,7 @@ template -_LIBCPP_HIDE_FROM_ABI void __parallel_merge( +_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_merge( _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2, @@ -64,6 +69,7 @@ _LIBCPP_HIDE_FROM_ABI void __parallel_merge( _Compare __comp, _LeafMerge __leaf_merge) { __leaf_merge(__first1, __last1, __first2, __last2, __outit, __comp); + return __empty{}; } } // namespace __thread_cpu_backend diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h index 0259d8a84bb3f..2c7647d61a2b0 100644 --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h @@ -17,7 +17,7 @@ #include <__type_traits/enable_if.h> #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -25,6 +25,9 @@ #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD template @@ -37,7 +40,7 @@ __simd_walk_2(_Iterator1 __first1, _DifferenceType __n, _Iterator2 __first2, _Fu } template -_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform( +_LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __pstl_transform( __cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, @@ -46,13 +49,13 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform( if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value && __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) { - std::__terminate_on_exception([&] { - std::__par_backend::__parallel_for( - __first, __last, [__op, __first, __result](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { - return std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, __brick_first, __brick_last, __result + (__brick_first - __first), __op); - }); - }); + std::__par_backend::__parallel_for( + __first, __last, [__op, __first, __result](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + auto __res = std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, __brick_first, __brick_last, __result + (__brick_first - __first), __op); + _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!"); + return *std::move(__res); + }); return __result + (__last - __first); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value && @@ -83,7 +86,7 @@ template >, int> = 0> -_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform( +_LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __pstl_transform( __cpu_backend_tag, _ForwardIterator1 __first1, _ForwardIterator1 __last1, @@ -94,20 +97,20 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform( __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value && __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value && __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) { - std::__terminate_on_exception([&] { - std::__par_backend::__parallel_for( - __first1, - __last1, - [__op, __first1, __first2, __result](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) { - return std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, - __brick_first, - __brick_last, - __first2 + (__brick_first - __first1), - __result + (__brick_first - __first1), - __op); - }); - }); + auto __res = std::__par_backend::__parallel_for( + __first1, + __last1, + [__op, __first1, __first2, __result](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) { + return std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, + __brick_first, + __brick_last, + __first2 + (__brick_first - __first1), + __result + (__brick_first - __first1), + __op); + }); + if (!__res) + return nullopt; return __result + (__last1 - __first1); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value && @@ -128,6 +131,8 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform( _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 #endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_TRANSFORM_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform_reduce.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform_reduce.h index 2afe5c7d10483..a5ca9c89d1ab2 100644 --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform_reduce.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform_reduce.h @@ -18,8 +18,8 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/operation_traits.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> #include +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -98,7 +98,7 @@ template -_LIBCPP_HIDE_FROM_ABI _Tp __pstl_transform_reduce( +_LIBCPP_HIDE_FROM_ABI optional<_Tp> __pstl_transform_reduce( __cpu_backend_tag, _ForwardIterator1 __first1, _ForwardIterator1 __last1, @@ -109,27 +109,25 @@ _LIBCPP_HIDE_FROM_ABI _Tp __pstl_transform_reduce( if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value && __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) { - return std::__terminate_on_exception([&] { - return __par_backend::__parallel_transform_reduce( - __first1, - std::move(__last1), - [__first1, __first2, __transform](_ForwardIterator1 __iter) { - return __transform(*__iter, *(__first2 + (__iter - __first1))); - }, - std::move(__init), - std::move(__reduce), - [__first1, __first2, __reduce, __transform]( - _ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _Tp __brick_init) { - return std::__pstl_transform_reduce<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, - __brick_first, - std::move(__brick_last), - __first2 + (__brick_first - __first1), - std::move(__brick_init), - std::move(__reduce), - std::move(__transform)); - }); - }); + return __par_backend::__parallel_transform_reduce( + __first1, + std::move(__last1), + [__first1, __first2, __transform](_ForwardIterator1 __iter) { + return __transform(*__iter, *(__first2 + (__iter - __first1))); + }, + std::move(__init), + std::move(__reduce), + [__first1, __first2, __reduce, __transform]( + _ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _Tp __brick_init) { + return *std::__pstl_transform_reduce<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, + __brick_first, + std::move(__brick_last), + __first2 + (__brick_first - __first1), + std::move(__brick_init), + std::move(__reduce), + std::move(__transform)); + }); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value && __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) { @@ -149,7 +147,7 @@ _LIBCPP_HIDE_FROM_ABI _Tp __pstl_transform_reduce( } template -_LIBCPP_HIDE_FROM_ABI _Tp __pstl_transform_reduce( +_LIBCPP_HIDE_FROM_ABI optional<_Tp> __pstl_transform_reduce( __cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, @@ -158,23 +156,23 @@ _LIBCPP_HIDE_FROM_ABI _Tp __pstl_transform_reduce( _UnaryOperation __transform) { if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { - return std::__terminate_on_exception([&] { - return __par_backend::__parallel_transform_reduce( - std::move(__first), - std::move(__last), - [__transform](_ForwardIterator __iter) { return __transform(*__iter); }, - std::move(__init), - __reduce, - [__transform, __reduce](auto __brick_first, auto __brick_last, _Tp __brick_init) { - return std::__pstl_transform_reduce<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, - std::move(__brick_first), - std::move(__brick_last), - std::move(__brick_init), - std::move(__reduce), - std::move(__transform)); - }); - }); + return __par_backend::__parallel_transform_reduce( + std::move(__first), + std::move(__last), + [__transform](_ForwardIterator __iter) { return __transform(*__iter); }, + std::move(__init), + __reduce, + [__transform, __reduce](auto __brick_first, auto __brick_last, _Tp __brick_init) { + auto __res = std::__pstl_transform_reduce<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, + std::move(__brick_first), + std::move(__brick_last), + std::move(__brick_init), + std::move(__reduce), + std::move(__transform)); + _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!"); + return *std::move(__res); + }); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { return std::__simd_transform_reduce( diff --git a/libcxx/include/__algorithm/pstl_copy.h b/libcxx/include/__algorithm/pstl_copy.h index 35d995a4719f6..19f275a0d5d97 100644 --- a/libcxx/include/__algorithm/pstl_copy.h +++ b/libcxx/include/__algorithm/pstl_copy.h @@ -22,6 +22,7 @@ #include <__type_traits/is_trivially_copyable.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -41,18 +42,34 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator -copy(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> +__copy(_ExecutionPolicy&& __policy, + _ForwardIterator&& __first, + _ForwardIterator&& __last, + _ForwardOutIterator&& __result) noexcept { return std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_copy), + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_copy, _RawPolicy), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _ForwardOutIterator __g_result) { - return std::transform(__policy, __g_first, __g_last, __g_result, __identity()); + return std::__transform(__policy, __g_first, __g_last, __g_result, __identity()); }, std::move(__first), std::move(__last), std::move(__result)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator +copy(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result) { + auto __res = std::__copy(__policy, std::move(__first), std::move(__last), std::move(__result)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + template void __pstl_copy_n(); @@ -62,21 +79,36 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator -copy_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, _ForwardOutIterator __result) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __copy_n( + _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _Size&& __n, _ForwardOutIterator&& __result) noexcept { return std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_copy_n), - [&__policy](_ForwardIterator __g_first, _Size __g_n, _ForwardOutIterator __g_result) { + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_copy_n, _RawPolicy), + [&__policy]( + _ForwardIterator __g_first, _Size __g_n, _ForwardOutIterator __g_result) -> optional<_ForwardIterator> { if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) - return std::copy(__policy, __g_first, __g_first + __g_n, __g_result); + return std::__copy(__policy, std::move(__g_first), std::move(__g_first + __g_n), std::move(__g_result)); else return std::copy_n(__g_first, __g_n, __g_result); }, std::move(__first), - __n, + std::move(__n), std::move(__result)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator +copy_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, _ForwardOutIterator __result) { + auto __res = std::__copy_n(__policy, std::move(__first), std::move(__n), std::move(__result)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_count.h b/libcxx/include/__algorithm/pstl_count.h index 15acb85de0bff..28806fca06370 100644 --- a/libcxx/include/__algorithm/pstl_count.h +++ b/libcxx/include/__algorithm/pstl_count.h @@ -23,7 +23,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -41,13 +41,13 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI __iter_diff_t<_ForwardIterator> -count_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iter_diff_t<_ForwardIterator>> __count_if( + _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) noexcept { using __diff_t = __iter_diff_t<_ForwardIterator>; return std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_count_if), - [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) { - return std::transform_reduce( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_count_if, _RawPolicy), + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) -> optional<__diff_t> { + return std::__transform_reduce( __policy, std::move(__g_first), std::move(__g_last), @@ -60,6 +60,19 @@ count_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator std::move(__pred)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI __iter_diff_t<_ForwardIterator> +count_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + auto __res = std::__count_if(__policy, std::move(__first), std::move(__last), std::move(__pred)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + template void __pstl_count(); // declaration needed for the frontend dispatch below @@ -68,11 +81,12 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI __iter_diff_t<_ForwardIterator> -count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iter_diff_t<_ForwardIterator>> +__count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { return std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_count), - [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) { + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_count, _RawPolicy), + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) + -> optional<__iter_diff_t<_ForwardIterator>> { return std::count_if(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __v) { return __v == __g_value; }); @@ -82,6 +96,19 @@ count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __ __value); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI __iter_diff_t<_ForwardIterator> +count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + auto __res = std::__count(__policy, std::move(__first), std::move(__last), __value); + if (!__res) + std::__throw_bad_alloc(); + return *__res; +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_fill.h b/libcxx/include/__algorithm/pstl_fill.h index 3d914131e0591..3057dcc04f1ad 100644 --- a/libcxx/include/__algorithm/pstl_fill.h +++ b/libcxx/include/__algorithm/pstl_fill.h @@ -20,7 +20,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -38,13 +38,13 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { +_LIBCPP_HIDE_FROM_ABI optional<__empty> +__fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) noexcept { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); - std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_fill), + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_fill, _RawPolicy), [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) { - std::for_each(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __element) { + return std::__for_each(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __element) { __element = __g_value; }); }, @@ -53,6 +53,18 @@ fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __l __value); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + if (!std::__fill(__policy, std::move(__first), std::move(__last), __value)) + std::__throw_bad_alloc(); +} + template void __pstl_fill_n(); // declaration needed for the frontend dispatch below @@ -62,22 +74,36 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -fill_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _SizeT __n, const _Tp& __value) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> +__fill_n(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _SizeT&& __n, const _Tp& __value) noexcept { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); - std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_fill_n), + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_fill_n, _RawPolicy), [&](_ForwardIterator __g_first, _SizeT __g_n, const _Tp& __g_value) { if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) std::fill(__policy, __g_first, __g_first + __g_n, __g_value); else std::fill_n(__g_first, __g_n, __g_value); + return optional<__empty>{__empty{}}; }, std::move(__first), - __n, + std::move(__n), __value); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +fill_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _SizeT __n, const _Tp& __value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + if (!std::__fill_n(__policy, std::move(__first), std::move(__n), __value)) + std::__throw_bad_alloc(); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_find.h b/libcxx/include/__algorithm/pstl_find.h index 425d53ff16bab..adc05ea1a9e55 100644 --- a/libcxx/include/__algorithm/pstl_find.h +++ b/libcxx/include/__algorithm/pstl_find.h @@ -19,7 +19,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -34,13 +34,26 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _ForwardIterator -find_if(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardIterator>> +__find_if(_ExecutionPolicy&&, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) noexcept { using _Backend = typename __select_backend<_RawPolicy>::type; return std::__pstl_find_if<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__pred)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardIterator +find_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + auto __res = std::__find_if(__policy, std::move(__first), std::move(__last), std::move(__pred)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + template void __pstl_find_if_not(); @@ -49,21 +62,36 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _ForwardIterator -find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardIterator>> +__find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) { return std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_find_if_not), - [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) { - return std::find_if(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __value) { - return !__g_pred(__value); - }); + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_find_if_not, _RawPolicy), + [&](_ForwardIterator&& __g_first, _ForwardIterator&& __g_last, _Predicate&& __g_pred) + -> optional<__remove_cvref_t<_ForwardIterator>> { + return std::__find_if( + __policy, __g_first, __g_last, [&](__iter_reference<__remove_cvref_t<_ForwardIterator>> __value) { + return !__g_pred(__value); + }); }, std::move(__first), std::move(__last), std::move(__pred)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardIterator +find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + auto __res = std::__find_if_not(__policy, std::move(__first), std::move(__last), std::move(__pred)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + template void __pstl_find(); @@ -72,21 +100,35 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _ForwardIterator -find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardIterator>> +__find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) noexcept { return std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_find), - [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) { - return std::find_if(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __element) { - return __element == __g_value; - }); + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_find, _RawPolicy), + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) -> optional<_ForwardIterator> { + return std::find_if( + __policy, __g_first, __g_last, [&](__iter_reference<__remove_cvref_t<_ForwardIterator>> __element) { + return __element == __g_value; + }); }, std::move(__first), std::move(__last), __value); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardIterator +find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + auto __res = std::__find(__policy, std::move(__first), std::move(__last), __value); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_for_each.h b/libcxx/include/__algorithm/pstl_for_each.h index ec22e937aa803..819a43d685abe 100644 --- a/libcxx/include/__algorithm/pstl_for_each.h +++ b/libcxx/include/__algorithm/pstl_for_each.h @@ -20,8 +20,9 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__type_traits/void_t.h> +#include <__utility/empty.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -31,16 +32,27 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template , + enable_if_t, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> +__for_each(_ExecutionPolicy&&, _ForwardIterator&& __first, _ForwardIterator&& __last, _Function&& __func) noexcept { + using _Backend = typename __select_backend<_RawPolicy>::type; + return std::__pstl_for_each<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__func)); +} + template , enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI void -for_each(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Function __func) { +for_each(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Function __func) { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); - using _Backend = typename __select_backend<_RawPolicy>::type; - std::__pstl_for_each<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__func)); + if (!std::__for_each(__policy, std::move(__first), std::move(__last), std::move(__func))) + std::__throw_bad_alloc(); } template @@ -52,23 +64,38 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -for_each_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __size, _Function __func) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> +__for_each_n(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _Size&& __size, _Function&& __func) noexcept { return std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_for_each_n), - [&](_ForwardIterator __g_first, _Size __g_size, _Function __g_func) { + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_for_each_n, _RawPolicy), + [&](_ForwardIterator __g_first, _Size __g_size, _Function __g_func) -> optional<__empty> { if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { std::for_each(__policy, std::move(__g_first), __g_first + __g_size, std::move(__g_func)); + return __empty{}; } else { std::for_each_n(std::move(__g_first), __g_size, std::move(__g_func)); + return __empty{}; } }, - __first, - __size, + std::move(__first), + std::move(__size), std::move(__func)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +for_each_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __size, _Function __func) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + auto __res = std::__for_each_n(__policy, std::move(__first), std::move(__size), std::move(__func)); + if (!__res) + std::__throw_bad_alloc(); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_frontend_dispatch.h b/libcxx/include/__algorithm/pstl_frontend_dispatch.h index dc49f3e5163a3..6fa1107491154 100644 --- a/libcxx/include/__algorithm/pstl_frontend_dispatch.h +++ b/libcxx/include/__algorithm/pstl_frontend_dispatch.h @@ -21,11 +21,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD -# define _LIBCPP_PSTL_CUSTOMIZATION_POINT(name) \ - [](auto&&... __args) -> decltype(std::name<_RawPolicy>(typename __select_backend<_RawPolicy>::type{}, \ - std::forward(__args)...)) { \ - return std::name<_RawPolicy>( \ - typename __select_backend<_RawPolicy>::type{}, std::forward(__args)...); \ +# define _LIBCPP_PSTL_CUSTOMIZATION_POINT(name, policy) \ + [](auto&&... __args) -> decltype(std::name( \ + typename __select_backend::type{}, std::forward(__args)...)) { \ + return std::name(typename __select_backend::type{}, std::forward(__args)...); \ } template diff --git a/libcxx/include/__algorithm/pstl_generate.h b/libcxx/include/__algorithm/pstl_generate.h index 4c23c788bf08d..56538392d5b5d 100644 --- a/libcxx/include/__algorithm/pstl_generate.h +++ b/libcxx/include/__algorithm/pstl_generate.h @@ -19,6 +19,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -36,13 +37,13 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -generate(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Generator __gen) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> +__generate(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Generator&& __gen) { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); - std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_generate), + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_generate, _RawPolicy), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _Generator __g_gen) { - std::for_each( + return std::__for_each( __policy, std::move(__g_first), std::move(__g_last), [&](__iter_reference<_ForwardIterator> __element) { __element = __g_gen(); }); @@ -52,6 +53,18 @@ generate(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator std::move(__gen)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +generate(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Generator __gen) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + if (!std::__generate(__policy, std::move(__first), std::move(__last), std::move(__gen))) + std::__throw_bad_alloc(); +} + template void __pstl_generate_n(); @@ -61,21 +74,34 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -generate_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, _Generator __gen) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); - std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_generate_n), +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> +__generate_n(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _Size&& __n, _Generator&& __gen) { + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_generate_n, _RawPolicy), [&__policy](_ForwardIterator __g_first, _Size __g_n, _Generator __g_gen) { - std::for_each_n(__policy, std::move(__g_first), __g_n, [&](__iter_reference<_ForwardIterator> __element) { - __element = __g_gen(); - }); + return std::__for_each_n( + __policy, std::move(__g_first), std::move(__g_n), [&](__iter_reference<_ForwardIterator> __element) { + __element = __g_gen(); + }); }, std::move(__first), __n, std::move(__gen)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +generate_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, _Generator __gen) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + if (!std::__generate_n(__policy, std::move(__first), std::move(__n), std::move(__gen))) + std::__throw_bad_alloc(); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_is_partitioned.h b/libcxx/include/__algorithm/pstl_is_partitioned.h index 6f6e9b2f4478f..39cf6369339db 100644 --- a/libcxx/include/__algorithm/pstl_is_partitioned.h +++ b/libcxx/include/__algorithm/pstl_is_partitioned.h @@ -18,6 +18,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -35,10 +36,10 @@ template , enable_if_t, int> = 0> -_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool -is_partitioned(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional __is_partitioned( + _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) { return std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_is_partitioned), + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_is_partitioned, _RawPolicy), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) { __g_first = std::find_if_not(__policy, __g_first, __g_last, __g_pred); if (__g_first == __g_last) @@ -51,6 +52,19 @@ is_partitioned(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIt std::move(__pred)); } +template , + enable_if_t, int> = 0> +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool +is_partitioned(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + auto __res = std::__is_partitioned(__policy, std::move(__first), std::move(__last), std::move(__pred)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_merge.h b/libcxx/include/__algorithm/pstl_merge.h index f10ac76742828..ed80145108632 100644 --- a/libcxx/include/__algorithm/pstl_merge.h +++ b/libcxx/include/__algorithm/pstl_merge.h @@ -16,6 +16,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -25,6 +26,32 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template , + class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, + enable_if_t, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> +__merge(_ExecutionPolicy&&, + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2, + _ForwardOutIterator __result, + _Comp __comp = {}) noexcept { + using _Backend = typename __select_backend<_RawPolicy>::type; + return std::__pstl_merge<_RawPolicy>( + _Backend{}, + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + std::move(__comp)); +} + template , enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator -merge(_ExecutionPolicy&&, +merge(_ExecutionPolicy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator2 __last2, _ForwardOutIterator __result, _Comp __comp = {}) { - using _Backend = typename __select_backend<_RawPolicy>::type; - return std::__pstl_merge<_RawPolicy>( - _Backend{}, + auto __res = std::__merge( + __policy, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__result), std::move(__comp)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/pstl_replace.h b/libcxx/include/__algorithm/pstl_replace.h index 04ffaaba596ae..05dee3f6a4f30 100644 --- a/libcxx/include/__algorithm/pstl_replace.h +++ b/libcxx/include/__algorithm/pstl_replace.h @@ -18,6 +18,7 @@ #include <__type_traits/enable_if.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -36,19 +37,21 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -replace_if(_ExecutionPolicy&& __policy, - _ForwardIterator __first, - _ForwardIterator __last, - _Pred __pred, - const _Tp& __new_value) { - std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace_if), - [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred, const _Tp& __g_new_value) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> +__replace_if(_ExecutionPolicy&& __policy, + _ForwardIterator&& __first, + _ForwardIterator&& __last, + _Pred&& __pred, + const _Tp& __new_value) noexcept { + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace_if, _RawPolicy), + [&__policy]( + _ForwardIterator&& __g_first, _ForwardIterator&& __g_last, _Pred&& __g_pred, const _Tp& __g_new_value) { std::for_each(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __element) { if (__g_pred(__element)) __element = __g_new_value; }); + return optional<__empty>{__empty{}}; }, std::move(__first), std::move(__last), @@ -56,6 +59,23 @@ replace_if(_ExecutionPolicy&& __policy, __new_value); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +replace_if(_ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + _Pred __pred, + const _Tp& __new_value) { + auto __res = std::__replace_if(__policy, std::move(__first), std::move(__last), std::move(__pred), __new_value); + if (!__res) + std::__throw_bad_alloc(); +} + template void __pstl_replace(); @@ -64,17 +84,17 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -replace(_ExecutionPolicy&& __policy, - _ForwardIterator __first, - _ForwardIterator __last, - const _Tp& __old_value, - const _Tp& __new_value) { - std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace), +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> +__replace(_ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + const _Tp& __old_value, + const _Tp& __new_value) noexcept { + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace, _RawPolicy), [&__policy]( _ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_old_value, const _Tp& __g_new_value) { - std::replace_if( + return std::__replace_if( __policy, std::move(__g_first), std::move(__g_last), @@ -87,6 +107,21 @@ replace(_ExecutionPolicy&& __policy, __new_value); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +replace(_ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + const _Tp& __old_value, + const _Tp& __new_value) { + if (!std::__replace(__policy, std::move(__first), std::move(__last), __old_value, __new_value)) + std::__throw_bad_alloc(); +} + template void __pstl_replace_copy_if(); @@ -97,23 +132,26 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void replace_copy_if( +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> __replace_copy_if( _ExecutionPolicy&& __policy, - _ForwardIterator __first, - _ForwardIterator __last, - _ForwardOutIterator __result, - _Pred __pred, + _ForwardIterator&& __first, + _ForwardIterator&& __last, + _ForwardOutIterator&& __result, + _Pred&& __pred, const _Tp& __new_value) { - std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace_copy_if), + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace_copy_if, _RawPolicy), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _ForwardOutIterator __g_result, _Pred __g_pred, - const _Tp& __g_new_value) { - std::transform(__policy, __g_first, __g_last, __g_result, [&](__iter_reference<_ForwardIterator> __element) { - return __g_pred(__element) ? __g_new_value : __element; - }); + const _Tp& __g_new_value) -> optional<__empty> { + if (!std::__transform( + __policy, __g_first, __g_last, __g_result, [&](__iter_reference<_ForwardIterator> __element) { + return __g_pred(__element) ? __g_new_value : __element; + })) + return nullopt; + return __empty{}; }, std::move(__first), std::move(__last), @@ -122,30 +160,49 @@ _LIBCPP_HIDE_FROM_ABI void replace_copy_if( __new_value); } -template -void __pstl_replace_copy(); - template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void replace_copy( +_LIBCPP_HIDE_FROM_ABI void replace_copy_if( _ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result, - const _Tp& __old_value, + _Pred __pred, const _Tp& __new_value) { - std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace_copy), + if (!std::__replace_copy_if( + __policy, std::move(__first), std::move(__last), std::move(__result), std::move(__pred), __new_value)) + std::__throw_bad_alloc(); +} + +template +void __pstl_replace_copy(); + +template , + enable_if_t, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> __replace_copy( + _ExecutionPolicy&& __policy, + _ForwardIterator&& __first, + _ForwardIterator&& __last, + _ForwardOutIterator&& __result, + const _Tp& __old_value, + const _Tp& __new_value) noexcept { + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace_copy, _RawPolicy), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _ForwardOutIterator __g_result, const _Tp& __g_old_value, const _Tp& __g_new_value) { - return std::replace_copy_if( + return std::__replace_copy_if( __policy, std::move(__g_first), std::move(__g_last), @@ -160,6 +217,24 @@ _LIBCPP_HIDE_FROM_ABI void replace_copy( __new_value); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void replace_copy( + _ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + _ForwardOutIterator __result, + const _Tp& __old_value, + const _Tp& __new_value) { + if (!std::__replace_copy( + __policy, std::move(__first), std::move(__last), std::move(__result), __old_value, __new_value)) + std::__throw_bad_alloc(); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_sort.h b/libcxx/include/__algorithm/pstl_sort.h index 75c77ed405275..3e71e0aa5ae0a 100644 --- a/libcxx/include/__algorithm/pstl_sort.h +++ b/libcxx/include/__algorithm/pstl_sort.h @@ -16,8 +16,10 @@ #include <__functional/operations.h> #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> +#include <__utility/empty.h> #include <__utility/forward.h> #include <__utility/move.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -35,18 +37,30 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -sort(_ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) { - std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_sort), +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> __sort( + _ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) noexcept { + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_sort, _RawPolicy), [&__policy](_RandomAccessIterator __g_first, _RandomAccessIterator __g_last, _Comp __g_comp) { std::stable_sort(__policy, std::move(__g_first), std::move(__g_last), std::move(__g_comp)); + return optional<__empty>{__empty{}}; }, std::move(__first), std::move(__last), std::move(__comp)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +sort(_ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) { + if (!std::__sort(__policy, std::move(__first), std::move(__last), std::move(__comp))) + std::__throw_bad_alloc(); +} + template , diff --git a/libcxx/include/__algorithm/pstl_stable_sort.h b/libcxx/include/__algorithm/pstl_stable_sort.h index 510ffd862980d..c9d375535fc45 100644 --- a/libcxx/include/__algorithm/pstl_stable_sort.h +++ b/libcxx/include/__algorithm/pstl_stable_sort.h @@ -15,7 +15,9 @@ #include <__type_traits/enable_if.h> #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> +#include <__utility/empty.h> #include <__utility/move.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -30,10 +32,21 @@ template , class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -stable_sort(_ExecutionPolicy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp = {}) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> __stable_sort( + _ExecutionPolicy&&, _RandomAccessIterator&& __first, _RandomAccessIterator&& __last, _Comp&& __comp = {}) noexcept { using _Backend = typename __select_backend<_RawPolicy>::type; - std::__pstl_stable_sort<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__comp)); + return std::__pstl_stable_sort<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__comp)); +} + +template , + class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void stable_sort( + _ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp = {}) { + if (!std::__stable_sort(__policy, std::move(__first), std::move(__last), std::move(__comp))) + std::__throw_bad_alloc(); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/pstl_transform.h b/libcxx/include/__algorithm/pstl_transform.h index a34439304a8fd..aad59d1f30e6b 100644 --- a/libcxx/include/__algorithm/pstl_transform.h +++ b/libcxx/include/__algorithm/pstl_transform.h @@ -16,7 +16,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -26,6 +26,23 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template , + enable_if_t, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardOutIterator>> +__transform(_ExecutionPolicy&&, + _ForwardIterator&& __first, + _ForwardIterator&& __last, + _ForwardOutIterator&& __result, + _UnaryOperation&& __op) noexcept { + using _Backend = typename __select_backend<_RawPolicy>::type; + return std::__pstl_transform<_RawPolicy>( + _Backend{}, std::move(__first), std::move(__last), std::move(__result), std::move(__op)); +} + template , enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform( - _ExecutionPolicy&&, + _ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result, @@ -41,9 +58,29 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform( _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardOutIterator); _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(_ForwardOutIterator, decltype(__op(*__first))); + auto __res = std::__transform(__policy, std::move(__first), std::move(__last), std::move(__result), std::move(__op)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardOutIterator>> +__transform(_ExecutionPolicy&&, + _ForwardIterator1&& __first1, + _ForwardIterator1&& __last1, + _ForwardIterator2&& __first2, + _ForwardOutIterator&& __result, + _BinaryOperation&& __op) noexcept { using _Backend = typename __select_backend<_RawPolicy>::type; return std::__pstl_transform<_RawPolicy>( - _Backend{}, std::move(__first), std::move(__last), std::move(__result), std::move(__op)); + _Backend{}, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__result), std::move(__op)); } template , enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform( - _ExecutionPolicy&&, + _ExecutionPolicy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, @@ -64,9 +101,11 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform( _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2); _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardOutIterator); _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(_ForwardOutIterator, decltype(__op(*__first1, *__first2))); - using _Backend = typename __select_backend<_RawPolicy>::type; - return std::__pstl_transform<_RawPolicy>( - _Backend{}, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__result), std::move(__op)); + auto __res = std::__transform( + __policy, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__result), std::move(__op)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/ranges_count.h b/libcxx/include/__algorithm/ranges_count.h index 82f54567561f2..4c8f1b2cbea7e 100644 --- a/libcxx/include/__algorithm/ranges_count.h +++ b/libcxx/include/__algorithm/ranges_count.h @@ -9,7 +9,8 @@ #ifndef _LIBCPP___ALGORITHM_RANGES_COUNT_H #define _LIBCPP___ALGORITHM_RANGES_COUNT_H -#include <__algorithm/ranges_count_if.h> +#include <__algorithm/count.h> +#include <__algorithm/iterator_operations.h> #include <__config> #include <__functional/identity.h> #include <__functional/ranges_operations.h> @@ -36,16 +37,14 @@ struct __fn { requires indirect_binary_predicate, const _Type*> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Iter> operator()(_Iter __first, _Sent __last, const _Type& __value, _Proj __proj = {}) const { - auto __pred = [&](auto&& __e) { return __e == __value; }; - return ranges::__count_if_impl(std::move(__first), std::move(__last), __pred, __proj); + return std::__count<_RangeAlgPolicy>(std::move(__first), std::move(__last), __value, __proj); } template requires indirect_binary_predicate, _Proj>, const _Type*> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr range_difference_t<_Range> operator()(_Range&& __r, const _Type& __value, _Proj __proj = {}) const { - auto __pred = [&](auto&& __e) { return __e == __value; }; - return ranges::__count_if_impl(ranges::begin(__r), ranges::end(__r), __pred, __proj); + return std::__count<_RangeAlgPolicy>(ranges::begin(__r), ranges::end(__r), __value, __proj); } }; } // namespace __count diff --git a/libcxx/include/__availability b/libcxx/include/__availability index 579698ec1e932..a6367945edc7c 100644 --- a/libcxx/include/__availability +++ b/libcxx/include/__availability @@ -179,6 +179,17 @@ // # define _LIBCPP_AVAILABILITY_HAS_NO_TZDB # define _LIBCPP_AVAILABILITY_TZDB +// Enable additional explicit instantiations of iostreams components. This +// reduces the number of weak definitions generated in programs that use +// iostreams by providing a single strong definition in the shared library. +// +// TODO: Enable additional explicit instantiations on GCC once it supports exclude_from_explicit_instantiation, +// or once libc++ doesn't use the attribute anymore. +// TODO: Enable them on Windows once https://llvm.org/PR41018 has been fixed. +#if defined(_LIBCPP_COMPILER_GCC) || defined(_WIN32) +# define _LIBCPP_AVAILABILITY_HAS_NO_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 +#endif + #elif defined(__APPLE__) // shared_mutex and shared_timed_mutex @@ -356,6 +367,12 @@ # define _LIBCPP_AVAILABILITY_HAS_NO_TZDB # define _LIBCPP_AVAILABILITY_TZDB __attribute__((unavailable)) +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 120000) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 150000) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 150000) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 80000) +# define _LIBCPP_AVAILABILITY_HAS_NO_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 +# endif #else // ...New vendors can add availability markup here... diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index 107368759c6e4..9032b8f018093 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -171,45 +171,6 @@ private: __bit_const_reference& operator=(const __bit_const_reference&) = delete; }; -// count - -template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 typename __bit_iterator<_Cp, _IsConst>::difference_type -__count_bool(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n) { - using _It = __bit_iterator<_Cp, _IsConst>; - using __storage_type = typename _It::__storage_type; - using difference_type = typename _It::difference_type; - - const int __bits_per_word = _It::__bits_per_word; - difference_type __r = 0; - // do first partial word - if (__first.__ctz_ != 0) { - __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); - __storage_type __dn = std::min(__clz_f, __n); - __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); - __r = std::__libcpp_popcount(std::__invert_if(*__first.__seg_) & __m); - __n -= __dn; - ++__first.__seg_; - } - // do middle whole words - for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) - __r += std::__libcpp_popcount(std::__invert_if(*__first.__seg_)); - // do last partial word - if (__n > 0) { - __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); - __r += std::__libcpp_popcount(std::__invert_if(*__first.__seg_) & __m); - } - return __r; -} - -template -inline _LIBCPP_HIDE_FROM_ABI typename __bit_iterator<_Cp, _IsConst>::difference_type -count(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, const _Tp& __value) { - if (static_cast(__value)) - return std::__count_bool(__first, static_cast(__last - __first)); - return std::__count_bool(__first, static_cast(__last - __first)); -} - // fill_n template @@ -1092,7 +1053,7 @@ private: _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, _IC> __find_bool(__bit_iterator<_Dp, _IC>, typename _Dp::size_type); template - friend typename __bit_iterator<_Dp, _IC>::difference_type _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 + friend typename __bit_iterator<_Dp, _IC>::difference_type _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __count_bool(__bit_iterator<_Dp, _IC>, typename _Dp::size_type); }; diff --git a/libcxx/include/__config b/libcxx/include/__config index 52bf12f80a28b..cddc39026f155 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -193,11 +193,6 @@ # endif # if defined(_LIBCPP_BUILDING_LIBRARY) || _LIBCPP_ABI_VERSION >= 2 -// Enable additional explicit instantiations of iostreams components. This -// reduces the number of weak definitions generated in programs that use -// iostreams by providing a single strong definition in the shared library. -# define _LIBCPP_ABI_ENABLE_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 - // Define a key function for `bad_function_call` in the library, to centralize // its vtable and typeinfo to libc++ rather than having all other libraries // using that class define their own copies. diff --git a/libcxx/include/__functional/bind_back.h b/libcxx/include/__functional/bind_back.h index 71dc63c86bdbe..0dd2befb52409 100644 --- a/libcxx/include/__functional/bind_back.h +++ b/libcxx/include/__functional/bind_back.h @@ -43,14 +43,9 @@ struct __bind_back_t : __perfect_forward<__bind_back_op using __perfect_forward<__bind_back_op>, _Fn, _BoundArgs>::__perfect_forward; }; -template , _Fn>, - is_move_constructible>, - is_constructible, _Args>..., - is_move_constructible>... - >::value ->> +template + requires is_constructible_v, _Fn> && is_move_constructible_v> && + (is_constructible_v, _Args> && ...) && (is_move_constructible_v> && ...) _LIBCPP_HIDE_FROM_ABI constexpr auto __bind_back(_Fn&& __f, _Args&&... __args) noexcept(noexcept(__bind_back_t, tuple...>>(_VSTD::forward<_Fn>(__f), _VSTD::forward_as_tuple(_VSTD::forward<_Args>(__args)...)))) diff --git a/libcxx/include/__functional/bind_front.h b/libcxx/include/__functional/bind_front.h index 72bb664809596..7ccd6e563b6e1 100644 --- a/libcxx/include/__functional/bind_front.h +++ b/libcxx/include/__functional/bind_front.h @@ -42,14 +42,9 @@ struct __bind_front_t : __perfect_forward<__bind_front_op, _Fn, _BoundArgs...> { using __perfect_forward<__bind_front_op, _Fn, _BoundArgs...>::__perfect_forward; }; -template , _Fn>, - is_move_constructible>, - is_constructible, _Args>..., - is_move_constructible>... - >::value ->> +template + requires is_constructible_v, _Fn> && is_move_constructible_v> && + (is_constructible_v, _Args> && ...) && (is_move_constructible_v> && ...) _LIBCPP_HIDE_FROM_ABI constexpr auto bind_front(_Fn&& __f, _Args&&... __args) { return __bind_front_t, decay_t<_Args>...>(_VSTD::forward<_Fn>(__f), _VSTD::forward<_Args>(__args)...); diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h index 33a1b95a31ddb..d9ddb8a17be27 100644 --- a/libcxx/include/__memory/shared_ptr.h +++ b/libcxx/include/__memory/shared_ptr.h @@ -1137,7 +1137,8 @@ struct __unbounded_array_control_block<_Tp[], _Alloc> : __shared_weak_count __alloc_.~_Alloc(); size_t __size = __unbounded_array_control_block::__bytes_for(__count_); _AlignedStorage* __storage = reinterpret_cast<_AlignedStorage*>(this); - allocator_traits<_StorageAlloc>::deallocate(__tmp, _PointerTraits::pointer_to(*__storage), __size); + allocator_traits<_StorageAlloc>::deallocate( + __tmp, _PointerTraits::pointer_to(*__storage), __size / sizeof(_AlignedStorage)); } _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_; @@ -1220,7 +1221,7 @@ struct __bounded_array_control_block<_Tp[_Count], _Alloc> _ControlBlockAlloc __tmp(__alloc_); __alloc_.~_Alloc(); - allocator_traits<_ControlBlockAlloc>::deallocate(__tmp, _PointerTraits::pointer_to(*this), sizeof(*this)); + allocator_traits<_ControlBlockAlloc>::deallocate(__tmp, _PointerTraits::pointer_to(*this), 1); } _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_; diff --git a/libcxx/include/__memory/uses_allocator_construction.h b/libcxx/include/__memory/uses_allocator_construction.h index a2e4f6e26f4b3..71ae5bcd32331 100644 --- a/libcxx/include/__memory/uses_allocator_construction.h +++ b/libcxx/include/__memory/uses_allocator_construction.h @@ -12,6 +12,7 @@ #include <__config> #include <__memory/construct_at.h> #include <__memory/uses_allocator.h> +#include <__tuple/pair_like.h> #include <__type_traits/enable_if.h> #include <__type_traits/is_same.h> #include <__type_traits/remove_cv.h> @@ -36,15 +37,19 @@ inline constexpr bool __is_std_pair = false; template inline constexpr bool __is_std_pair> = true; -template , int> = 0> +template +inline constexpr bool __is_cv_std_pair = __is_std_pair>; + +template , int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(const _Alloc& __alloc, _Args&&... __args) noexcept { - if constexpr (!uses_allocator_v<_Type, _Alloc> && is_constructible_v<_Type, _Args...>) { + if constexpr (!uses_allocator_v, _Alloc> && is_constructible_v<_Type, _Args...>) { return std::forward_as_tuple(std::forward<_Args>(__args)...); - } else if constexpr (uses_allocator_v<_Type, _Alloc> && + } else if constexpr (uses_allocator_v, _Alloc> && is_constructible_v<_Type, allocator_arg_t, const _Alloc&, _Args...>) { return tuple(allocator_arg, __alloc, std::forward<_Args>(__args)...); - } else if constexpr (uses_allocator_v<_Type, _Alloc> && is_constructible_v<_Type, _Args..., const _Alloc&>) { + } else if constexpr (uses_allocator_v, _Alloc> && + is_constructible_v<_Type, _Args..., const _Alloc&>) { return std::forward_as_tuple(std::forward<_Args>(__args)..., __alloc); } else { static_assert( @@ -52,7 +57,7 @@ __uses_allocator_construction_args(const _Alloc& __alloc, _Args&&... __args) noe } } -template , int> = 0> +template , int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args( const _Alloc& __alloc, piecewise_construct_t, _Tuple1&& __x, _Tuple2&& __y) noexcept { return std::make_tuple( @@ -71,12 +76,12 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args( std::forward<_Tuple2>(__y))); } -template , int> = 0> +template , int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(const _Alloc& __alloc) noexcept { return std::__uses_allocator_construction_args<_Pair>(__alloc, piecewise_construct, tuple<>{}, tuple<>{}); } -template , int> = 0> +template , int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(const _Alloc& __alloc, _Up&& __u, _Vp&& __v) noexcept { return std::__uses_allocator_construction_args<_Pair>( @@ -87,7 +92,7 @@ __uses_allocator_construction_args(const _Alloc& __alloc, _Up&& __u, _Vp&& __v) } # if _LIBCPP_STD_VER >= 23 -template , int> = 0> +template , int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(const _Alloc& __alloc, pair<_Up, _Vp>& __pair) noexcept { return std::__uses_allocator_construction_args<_Pair>( @@ -95,14 +100,14 @@ __uses_allocator_construction_args(const _Alloc& __alloc, pair<_Up, _Vp>& __pair } # endif -template , int> = 0> +template , int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(const _Alloc& __alloc, const pair<_Up, _Vp>& __pair) noexcept { return std::__uses_allocator_construction_args<_Pair>( __alloc, piecewise_construct, std::forward_as_tuple(__pair.first), std::forward_as_tuple(__pair.second)); } -template , int> = 0> +template , int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(const _Alloc& __alloc, pair<_Up, _Vp>&& __pair) noexcept { return std::__uses_allocator_construction_args<_Pair>( @@ -113,7 +118,7 @@ __uses_allocator_construction_args(const _Alloc& __alloc, pair<_Up, _Vp>&& __pai } # if _LIBCPP_STD_VER >= 23 -template , int> = 0> +template , int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(const _Alloc& __alloc, const pair<_Up, _Vp>&& __pair) noexcept { return std::__uses_allocator_construction_args<_Pair>( @@ -122,6 +127,20 @@ __uses_allocator_construction_args(const _Alloc& __alloc, const pair<_Up, _Vp>&& std::forward_as_tuple(std::get<0>(std::move(__pair))), std::forward_as_tuple(std::get<1>(std::move(__pair)))); } + +template < class _Pair, + class _Alloc, + __pair_like _PairLike, + __enable_if_t<__is_cv_std_pair<_Pair> && !__is_specialization_of_subrange>::value, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr auto +__uses_allocator_construction_args(const _Alloc& __alloc, _PairLike&& __p) noexcept { + return std::__uses_allocator_construction_args<_Pair>( + __alloc, + piecewise_construct, + std::forward_as_tuple(std::get<0>(std::forward<_PairLike>(__p))), + std::forward_as_tuple(std::get<1>(std::forward<_PairLike>(__p)))); +} # endif namespace __uses_allocator_detail { @@ -139,23 +158,33 @@ template inline constexpr bool __convertible_to_const_pair_ref = decltype(__uses_allocator_detail::__convertible_to_const_pair_ref_impl<_Tp>(0))::value; +# if _LIBCPP_STD_VER >= 23 +template +inline constexpr bool __uses_allocator_constraints = + __is_cv_std_pair<_Tp> && + (__is_specialization_of_subrange>::value || + (!__pair_like<_Up> && !__convertible_to_const_pair_ref<_Up>)); +# else +template +inline constexpr bool __uses_allocator_constraints = __is_cv_std_pair<_Tp> && !__convertible_to_const_pair_ref<_Up>; +# endif + } // namespace __uses_allocator_detail -template < - class _Pair, - class _Alloc, - class _Type, - __enable_if_t<__is_std_pair<_Pair> && !__uses_allocator_detail::__convertible_to_const_pair_ref<_Type>, int> = 0> +template < class _Pair, + class _Alloc, + class _Type, + __enable_if_t<__uses_allocator_detail::__uses_allocator_constraints<_Pair, _Type>, int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(const _Alloc& __alloc, _Type&& __value) noexcept; template _LIBCPP_HIDE_FROM_ABI constexpr _Type __make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args); -template && !__uses_allocator_detail::__convertible_to_const_pair_ref<_Type>, int>> +template < class _Pair, + class _Alloc, + class _Type, + __enable_if_t< __uses_allocator_detail::__uses_allocator_constraints<_Pair, _Type>, int>> _LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(const _Alloc& __alloc, _Type&& __value) noexcept { struct __pair_constructor { diff --git a/libcxx/include/__numeric/pstl_reduce.h b/libcxx/include/__numeric/pstl_reduce.h index 163e0078e10e5..b19972a46db7f 100644 --- a/libcxx/include/__numeric/pstl_reduce.h +++ b/libcxx/include/__numeric/pstl_reduce.h @@ -33,16 +33,16 @@ template , class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _Tp -reduce(_ExecutionPolicy&& __policy, - _ForwardIterator __first, - _ForwardIterator __last, - _Tp __init, - _BinaryOperation __op = {}) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_Tp> +__reduce(_ExecutionPolicy&& __policy, + _ForwardIterator&& __first, + _ForwardIterator&& __last, + _Tp&& __init, + _BinaryOperation&& __op = {}) noexcept { return std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_reduce), + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_reduce, _RawPolicy), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _Tp __g_init, _BinaryOperation __g_op) { - return std::transform_reduce( + return std::__transform_reduce( __policy, std::move(__g_first), std::move(__g_last), std::move(__g_init), std::move(__g_op), __identity{}); }, std::move(__first), @@ -53,19 +53,50 @@ reduce(_ExecutionPolicy&& __policy, template , class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI __iter_value_type<_ForwardIterator> -reduce(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last) { +_LIBCPP_HIDE_FROM_ABI _Tp +reduce(_ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + _Tp __init, + _BinaryOperation __op = {}) { + auto __res = std::__reduce(__policy, std::move(__first), std::move(__last), std::move(__init), std::move(__op)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + +template , + enable_if_t, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iter_value_type<_ForwardIterator>> +__reduce(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last) noexcept { return std::__pstl_frontend_dispatch( - _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_reduce), + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_reduce, _RawPolicy), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last) { - return std::reduce(__policy, __g_first, __g_last, __iter_value_type<_ForwardIterator>()); + return std::__reduce( + __policy, std::move(__g_first), std::move(__g_last), __iter_value_type<_ForwardIterator>()); }, std::move(__first), std::move(__last)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI __iter_value_type<_ForwardIterator> +reduce(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last) { + auto __res = std::__reduce(__policy, std::move(__first), std::move(__last)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__numeric/pstl_transform_reduce.h b/libcxx/include/__numeric/pstl_transform_reduce.h index b7c9d8d288f99..4127ee21e3045 100644 --- a/libcxx/include/__numeric/pstl_transform_reduce.h +++ b/libcxx/include/__numeric/pstl_transform_reduce.h @@ -16,7 +16,7 @@ #include <__numeric/transform_reduce.h> #include <__type_traits/is_execution_policy.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -34,23 +34,53 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _Tp transform_reduce( +_LIBCPP_HIDE_FROM_ABI optional<_Tp> __transform_reduce( _ExecutionPolicy&&, + _ForwardIterator1&& __first1, + _ForwardIterator1&& __last1, + _ForwardIterator2&& __first2, + _Tp&& __init, + _BinaryOperation1&& __reduce, + _BinaryOperation2&& __transform) noexcept { + using _Backend = typename __select_backend<_RawPolicy>::type; + return std::__pstl_transform_reduce<_RawPolicy>( + _Backend{}, + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__init), + std::move(__reduce), + std::move(__transform)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp transform_reduce( + _ExecutionPolicy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _Tp __init, _BinaryOperation1 __reduce, _BinaryOperation2 __transform) { - using _Backend = typename __select_backend<_RawPolicy>::type; - return std::__pstl_transform_reduce<_RawPolicy>( - _Backend{}, + auto __res = std::__transform_reduce( + __policy, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__init), std::move(__reduce), std::move(__transform)); + + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); } // This overload doesn't get a customization point because it's trivial to detect (through e.g. @@ -76,13 +106,13 @@ template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _Tp transform_reduce( +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_Tp>> __transform_reduce( _ExecutionPolicy&&, - _ForwardIterator __first, - _ForwardIterator __last, - _Tp __init, - _BinaryOperation __reduce, - _UnaryOperation __transform) { + _ForwardIterator&& __first, + _ForwardIterator&& __last, + _Tp&& __init, + _BinaryOperation&& __reduce, + _UnaryOperation&& __transform) noexcept { using _Backend = typename __select_backend<_RawPolicy>::type; return std::__pstl_transform_reduce<_RawPolicy>( _Backend{}, @@ -93,6 +123,27 @@ _LIBCPP_HIDE_FROM_ABI _Tp transform_reduce( std::move(__transform)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp transform_reduce( + _ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + _Tp __init, + _BinaryOperation __reduce, + _UnaryOperation __transform) { + auto __res = std::__transform_reduce( + __policy, std::move(__first), std::move(__last), std::move(__init), std::move(__reduce), std::move(__transform)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__ranges/iota_view.h b/libcxx/include/__ranges/iota_view.h index f372688abfdaf..ccf0c7a8e8d50 100644 --- a/libcxx/include/__ranges/iota_view.h +++ b/libcxx/include/__ranges/iota_view.h @@ -363,15 +363,14 @@ namespace ranges { (integral<_Start> && integral<_BoundSentinel>) || sized_sentinel_for<_BoundSentinel, _Start> { if constexpr (__integer_like<_Start> && __integer_like<_BoundSentinel>) { - if (__value_ < 0) { - if (__bound_sentinel_ < 0) { - return std::__to_unsigned_like(-__value_) - std::__to_unsigned_like(-__bound_sentinel_); - } - return std::__to_unsigned_like(__bound_sentinel_) + std::__to_unsigned_like(-__value_); - } - return std::__to_unsigned_like(__bound_sentinel_) - std::__to_unsigned_like(__value_); + return (__value_ < 0) + ? ((__bound_sentinel_ < 0) + ? std::__to_unsigned_like(-__value_) - std::__to_unsigned_like(-__bound_sentinel_) + : std::__to_unsigned_like(__bound_sentinel_) + std::__to_unsigned_like(-__value_)) + : std::__to_unsigned_like(__bound_sentinel_) - std::__to_unsigned_like(__value_); + } else { + return std::__to_unsigned_like(__bound_sentinel_ - __value_); } - return std::__to_unsigned_like(__bound_sentinel_ - __value_); } }; diff --git a/libcxx/include/__type_traits/datasizeof.h b/libcxx/include/__type_traits/datasizeof.h index 019099a9cf183..5688e3293a69e 100644 --- a/libcxx/include/__type_traits/datasizeof.h +++ b/libcxx/include/__type_traits/datasizeof.h @@ -47,7 +47,12 @@ struct __libcpp_datasizeof { }; #endif + // _FirstPaddingByte<> is sometimes non-standard layout. Using `offsetof` is UB in that case, but GCC and Clang allow + // the use as an extension. + _LIBCPP_DIAGNOSTIC_PUSH + _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-offsetof") static const size_t value = offsetof(_FirstPaddingByte<>, __first_padding_byte_); + _LIBCPP_DIAGNOSTIC_POP }; _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__utility/empty.h b/libcxx/include/__utility/empty.h new file mode 100644 index 0000000000000..8cca197145c72 --- /dev/null +++ b/libcxx/include/__utility/empty.h @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___UTILITY_EMPTY_H +#define _LIBCPP___UTILITY_EMPTY_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +struct __empty {}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___UTILITY_EMPTY_H diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h index 62dac6dd1da3f..535344eb1e2d6 100644 --- a/libcxx/include/__utility/pair.h +++ b/libcxx/include/__utility/pair.h @@ -284,7 +284,8 @@ struct _LIBCPP_TEMPLATE_VIS pair } template <__pair_like _PairLike> - requires(is_constructible_v(std::declval<_PairLike&&>()))> && + requires(!__is_specialization_of_subrange>::value && + is_constructible_v(std::declval<_PairLike&&>()))> && is_constructible_v(std::declval<_PairLike&&>()))>) _LIBCPP_HIDE_FROM_ABI constexpr explicit(__pair_like_explicit_wknd<_PairLike>()) pair(_PairLike&& __p) diff --git a/libcxx/include/__utility/terminate_on_exception.h b/libcxx/include/__utility/terminate_on_exception.h deleted file mode 100644 index e035ec3409ae5..0000000000000 --- a/libcxx/include/__utility/terminate_on_exception.h +++ /dev/null @@ -1,48 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef _LIBCPP___UTILITY_TERMINATE_ON_EXCEPTION_H -#define _LIBCPP___UTILITY_TERMINATE_ON_EXCEPTION_H - -#include <__config> -#include <__exception/terminate.h> -#include - -#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -#endif - -#if _LIBCPP_STD_VER >= 17 - -_LIBCPP_BEGIN_NAMESPACE_STD - -# ifndef _LIBCPP_HAS_NO_EXCEPTIONS - -template -_LIBCPP_HIDE_FROM_ABI auto __terminate_on_exception(_Func __func) { - try { - return __func(); - } catch (...) { - std::terminate(); - } -} - -# else // _LIBCPP_HAS_NO_EXCEPTIONS - -template -_LIBCPP_HIDE_FROM_ABI auto __terminate_on_exception(_Func __func) { - return __func(); -} - -# endif // _LIBCPP_HAS_NO_EXCEPTIONS - -_LIBCPP_END_NAMESPACE_STD - -#endif // _LIBCPP_STD_VER >= 17 - -#endif // _LIBCPP___UTILITY_TERMINATE_ON_EXCEPTION_H diff --git a/libcxx/include/bitset b/libcxx/include/bitset index e4c01e617110b..a3b1dc3a45357 100644 --- a/libcxx/include/bitset +++ b/libcxx/include/bitset @@ -122,6 +122,7 @@ template struct hash>; */ +#include <__algorithm/count.h> #include <__algorithm/fill.h> #include <__algorithm/find.h> #include <__assert> // all public C++ headers provide the assertion handler @@ -1042,7 +1043,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 size_t bitset<_Size>::count() const _NOEXCEPT { - return static_cast(_VSTD::__count_bool(base::__make_iter(0), _Size)); + return static_cast(std::count(base::__make_iter(0), base::__make_iter(_Size), true)); } template diff --git a/libcxx/include/fstream b/libcxx/include/fstream index cf5ca142e7d95..024eef8a9d669 100644 --- a/libcxx/include/fstream +++ b/libcxx/include/fstream @@ -1734,7 +1734,7 @@ basic_fstream<_CharT, _Traits>::close() this->setstate(ios_base::failbit); } -#if defined(_LIBCPP_ABI_ENABLE_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1) +#ifndef _LIBCPP_AVAILABILITY_HAS_NO_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_ifstream; extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_ofstream; extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_filebuf; diff --git a/libcxx/include/future b/libcxx/include/future index 273e4175e604b..f372b8e6ad5d8 100644 --- a/libcxx/include/future +++ b/libcxx/include/future @@ -44,14 +44,15 @@ error_condition make_error_condition(future_errc e) noexcept; const error_category& future_category() noexcept; -class future_error - : public logic_error -{ +class future_error : public logic_error { public: - future_error(error_code ec); // exposition only - explicit future_error(future_errc); // C++17 + explicit future_error(future_errc e); // since C++17 + const error_code& code() const noexcept; const char* what() const noexcept; + +private: + error_code ec_; // exposition only }; template @@ -516,12 +517,25 @@ make_error_condition(future_errc __e) _NOEXCEPT return error_condition(static_cast(__e), future_category()); } +_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS +_LIBCPP_AVAILABILITY_FUTURE_ERROR +#endif +void __throw_future_error(future_errc __ev); + class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_AVAILABILITY_FUTURE_ERROR future_error : public logic_error { error_code __ec_; + + future_error(error_code); + friend void __throw_future_error(future_errc); + template friend class promise; + public: - future_error(error_code __ec); +#if _LIBCPP_STD_VER >= 17 + _LIBCPP_HIDE_FROM_ABI explicit future_error(future_errc __ec) : future_error(std::make_error_code(__ec)) {} +#endif _LIBCPP_INLINE_VISIBILITY const error_code& code() const _NOEXCEPT {return __ec_;} @@ -530,10 +544,7 @@ public: ~future_error() _NOEXCEPT override; }; -_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY -#ifndef _LIBCPP_HAS_NO_EXCEPTIONS -_LIBCPP_AVAILABILITY_FUTURE_ERROR -#endif +// Declared above std::future_error void __throw_future_error(future_errc __ev) { #ifndef _LIBCPP_HAS_NO_EXCEPTIONS @@ -1359,9 +1370,7 @@ promise<_Rp>::~promise() if (__state_) { if (!__state_->__has_value() && __state_->use_count() > 1) - __state_->set_exception(make_exception_ptr( - future_error(make_error_code(future_errc::broken_promise)) - )); + __state_->set_exception(make_exception_ptr(future_error(make_error_code(future_errc::broken_promise)))); __state_->__release_shared(); } } @@ -1502,9 +1511,7 @@ promise<_Rp&>::~promise() if (__state_) { if (!__state_->__has_value() && __state_->use_count() > 1) - __state_->set_exception(make_exception_ptr( - future_error(make_error_code(future_errc::broken_promise)) - )); + __state_->set_exception(make_exception_ptr(future_error(make_error_code(future_errc::broken_promise)))); __state_->__release_shared(); } } diff --git a/libcxx/include/limits b/libcxx/include/limits index 9f5949e63cff0..51daee6c4968c 100644 --- a/libcxx/include/limits +++ b/libcxx/include/limits @@ -43,8 +43,8 @@ public: static constexpr bool has_infinity = false; static constexpr bool has_quiet_NaN = false; static constexpr bool has_signaling_NaN = false; - static constexpr float_denorm_style has_denorm = denorm_absent; - static constexpr bool has_denorm_loss = false; + static constexpr float_denorm_style has_denorm = denorm_absent; // deprecated in C++23 + static constexpr bool has_denorm_loss = false; // deprecated in C++23 static constexpr T infinity() noexcept; static constexpr T quiet_NaN() noexcept; static constexpr T signaling_NaN() noexcept; @@ -68,7 +68,7 @@ enum float_round_style round_toward_neg_infinity = 3 }; -enum float_denorm_style +enum float_denorm_style // deprecated in C++23 { denorm_indeterminate = -1, denorm_absent = 0, @@ -128,7 +128,7 @@ enum float_round_style round_toward_neg_infinity = 3 }; -enum float_denorm_style +enum _LIBCPP_DEPRECATED_IN_CXX23 float_denorm_style { denorm_indeterminate = -1, denorm_absent = 0, @@ -164,8 +164,8 @@ protected: static _LIBCPP_CONSTEXPR const bool has_infinity = false; static _LIBCPP_CONSTEXPR const bool has_quiet_NaN = false; static _LIBCPP_CONSTEXPR const bool has_signaling_NaN = false; - static _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = denorm_absent; - static _LIBCPP_CONSTEXPR const bool has_denorm_loss = false; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = denorm_absent; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const bool has_denorm_loss = false; _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type infinity() _NOEXCEPT {return type();} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type quiet_NaN() _NOEXCEPT {return type();} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type signaling_NaN() _NOEXCEPT {return type();} @@ -224,8 +224,8 @@ protected: static _LIBCPP_CONSTEXPR const bool has_infinity = false; static _LIBCPP_CONSTEXPR const bool has_quiet_NaN = false; static _LIBCPP_CONSTEXPR const bool has_signaling_NaN = false; - static _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = denorm_absent; - static _LIBCPP_CONSTEXPR const bool has_denorm_loss = false; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = denorm_absent; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const bool has_denorm_loss = false; _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type infinity() _NOEXCEPT {return type(0);} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type quiet_NaN() _NOEXCEPT {return type(0);} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type signaling_NaN() _NOEXCEPT {return type(0);} @@ -277,8 +277,8 @@ protected: static _LIBCPP_CONSTEXPR const bool has_infinity = false; static _LIBCPP_CONSTEXPR const bool has_quiet_NaN = false; static _LIBCPP_CONSTEXPR const bool has_signaling_NaN = false; - static _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = denorm_absent; - static _LIBCPP_CONSTEXPR const bool has_denorm_loss = false; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = denorm_absent; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const bool has_denorm_loss = false; _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type infinity() _NOEXCEPT {return type(0);} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type quiet_NaN() _NOEXCEPT {return type(0);} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type signaling_NaN() _NOEXCEPT {return type(0);} @@ -323,8 +323,8 @@ protected: static _LIBCPP_CONSTEXPR const bool has_infinity = true; static _LIBCPP_CONSTEXPR const bool has_quiet_NaN = true; static _LIBCPP_CONSTEXPR const bool has_signaling_NaN = true; - static _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = denorm_present; - static _LIBCPP_CONSTEXPR const bool has_denorm_loss = false; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = denorm_present; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const bool has_denorm_loss = false; _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type infinity() _NOEXCEPT {return __builtin_huge_valf();} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type quiet_NaN() _NOEXCEPT {return __builtin_nanf("");} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type signaling_NaN() _NOEXCEPT {return __builtin_nansf("");} @@ -373,8 +373,8 @@ protected: static _LIBCPP_CONSTEXPR const bool has_infinity = true; static _LIBCPP_CONSTEXPR const bool has_quiet_NaN = true; static _LIBCPP_CONSTEXPR const bool has_signaling_NaN = true; - static _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = denorm_present; - static _LIBCPP_CONSTEXPR const bool has_denorm_loss = false; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = denorm_present; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const bool has_denorm_loss = false; _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type infinity() _NOEXCEPT {return __builtin_huge_val();} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type quiet_NaN() _NOEXCEPT {return __builtin_nan("");} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type signaling_NaN() _NOEXCEPT {return __builtin_nans("");} @@ -423,8 +423,8 @@ protected: static _LIBCPP_CONSTEXPR const bool has_infinity = true; static _LIBCPP_CONSTEXPR const bool has_quiet_NaN = true; static _LIBCPP_CONSTEXPR const bool has_signaling_NaN = true; - static _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = denorm_present; - static _LIBCPP_CONSTEXPR const bool has_denorm_loss = false; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = denorm_present; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const bool has_denorm_loss = false; _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type infinity() _NOEXCEPT {return __builtin_huge_vall();} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type quiet_NaN() _NOEXCEPT {return __builtin_nanl("");} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type signaling_NaN() _NOEXCEPT {return __builtin_nansl("");} @@ -477,8 +477,10 @@ public: static _LIBCPP_CONSTEXPR const bool has_infinity = __base::has_infinity; static _LIBCPP_CONSTEXPR const bool has_quiet_NaN = __base::has_quiet_NaN; static _LIBCPP_CONSTEXPR const bool has_signaling_NaN = __base::has_signaling_NaN; - static _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = __base::has_denorm; - static _LIBCPP_CONSTEXPR const bool has_denorm_loss = __base::has_denorm_loss; +_LIBCPP_SUPPRESS_DEPRECATED_PUSH + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = __base::has_denorm; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const bool has_denorm_loss = __base::has_denorm_loss; +_LIBCPP_SUPPRESS_DEPRECATED_POP _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type infinity() _NOEXCEPT {return __base::infinity();} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type quiet_NaN() _NOEXCEPT {return __base::quiet_NaN();} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type signaling_NaN() _NOEXCEPT {return __base::signaling_NaN();} @@ -570,8 +572,10 @@ public: static _LIBCPP_CONSTEXPR const bool has_infinity = __base::has_infinity; static _LIBCPP_CONSTEXPR const bool has_quiet_NaN = __base::has_quiet_NaN; static _LIBCPP_CONSTEXPR const bool has_signaling_NaN = __base::has_signaling_NaN; - static _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = __base::has_denorm; - static _LIBCPP_CONSTEXPR const bool has_denorm_loss = __base::has_denorm_loss; +_LIBCPP_SUPPRESS_DEPRECATED_PUSH + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = __base::has_denorm; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const bool has_denorm_loss = __base::has_denorm_loss; +_LIBCPP_SUPPRESS_DEPRECATED_POP _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type infinity() _NOEXCEPT {return __base::infinity();} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type quiet_NaN() _NOEXCEPT {return __base::quiet_NaN();} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type signaling_NaN() _NOEXCEPT {return __base::signaling_NaN();} @@ -663,8 +667,10 @@ public: static _LIBCPP_CONSTEXPR const bool has_infinity = __base::has_infinity; static _LIBCPP_CONSTEXPR const bool has_quiet_NaN = __base::has_quiet_NaN; static _LIBCPP_CONSTEXPR const bool has_signaling_NaN = __base::has_signaling_NaN; - static _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = __base::has_denorm; - static _LIBCPP_CONSTEXPR const bool has_denorm_loss = __base::has_denorm_loss; +_LIBCPP_SUPPRESS_DEPRECATED_PUSH + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = __base::has_denorm; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const bool has_denorm_loss = __base::has_denorm_loss; +_LIBCPP_SUPPRESS_DEPRECATED_POP _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type infinity() _NOEXCEPT {return __base::infinity();} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type quiet_NaN() _NOEXCEPT {return __base::quiet_NaN();} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type signaling_NaN() _NOEXCEPT {return __base::signaling_NaN();} @@ -756,8 +762,10 @@ public: static _LIBCPP_CONSTEXPR const bool has_infinity = __base::has_infinity; static _LIBCPP_CONSTEXPR const bool has_quiet_NaN = __base::has_quiet_NaN; static _LIBCPP_CONSTEXPR const bool has_signaling_NaN = __base::has_signaling_NaN; - static _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = __base::has_denorm; - static _LIBCPP_CONSTEXPR const bool has_denorm_loss = __base::has_denorm_loss; +_LIBCPP_SUPPRESS_DEPRECATED_PUSH + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const float_denorm_style has_denorm = __base::has_denorm; + static _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_CONSTEXPR const bool has_denorm_loss = __base::has_denorm_loss; +_LIBCPP_SUPPRESS_DEPRECATED_POP _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type infinity() _NOEXCEPT {return __base::infinity();} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type quiet_NaN() _NOEXCEPT {return __base::quiet_NaN();} _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR type signaling_NaN() _NOEXCEPT {return __base::signaling_NaN();} diff --git a/libcxx/include/math.h b/libcxx/include/math.h index fdf3231c2978c..b068ea388f095 100644 --- a/libcxx/include/math.h +++ b/libcxx/include/math.h @@ -387,8 +387,19 @@ namespace __math { // fpclassify -template ::value, int> = 0> -_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI int fpclassify(_A1 __x) _NOEXCEPT { +// template on non-double overloads to make them weaker than same overloads from MSVC runtime +template +_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI int fpclassify(float __x) _NOEXCEPT { + return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x); +} + +template +_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI int fpclassify(double __x) _NOEXCEPT { + return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x); +} + +template +_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI int fpclassify(long double __x) _NOEXCEPT { return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x); } diff --git a/libcxx/include/memory b/libcxx/include/memory index cd6bcc7eaa35d..24ba82f43ddd3 100644 --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -867,6 +867,43 @@ template struct hash >; template inline constexpr bool uses_allocator_v = uses_allocator::value; +// [allocator.uses.construction], uses-allocator construction +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++20 + Args&&... args) noexcept; +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++20 + piecewise_construct_t, + Tuple1&& x, Tuple2&& y) noexcept; +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept; // since C++20 +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++20 + U&& u, V&& v) noexcept; +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++23 + pair& pr) noexcept; +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++20 + const pair& pr) noexcept; +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++20 + pair&& pr) noexcept; +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++23 + const pair&& pr) noexcept; +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++20 + P&& p) noexcept; +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // since C++20 + U&& u) noexcept; +template + constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); // since C++20 +template + constexpr T* uninitialized_construct_using_allocator(T* p, // since C++20 + const Alloc& alloc, Args&&... args); + // [ptr.align] void* align(size_t alignment, size_t size, void*& ptr, size_t& space); diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 6d9bb8653fcb5..26657b78b8440 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -2053,6 +2053,7 @@ module std_private_utility_cmp [system] { } module std_private_utility_convert_to_integral [system] { header "__utility/convert_to_integral.h" } module std_private_utility_declval [system] { header "__utility/declval.h" } +module std_private_utility_empty [system] { header "__utility/empty.h" } module std_private_utility_exception_guard [system] { header "__utility/exception_guard.h" } module std_private_utility_exchange [system] { header "__utility/exchange.h" } module std_private_utility_forward [system] { header "__utility/forward.h" } @@ -2088,7 +2089,6 @@ module std_private_utility_swap [system] { header "__utility/swap.h" export std_private_type_traits_is_swappable } -module std_private_utility_terminate_on_exception [system] { header "__utility/terminate_on_exception.h" } module std_private_utility_to_underlying [system] { header "__utility/to_underlying.h" } module std_private_utility_unreachable [system] { header "__utility/unreachable.h" } diff --git a/libcxx/include/sstream b/libcxx/include/sstream index 40930df24c6d0..47c2d0553a57c 100644 --- a/libcxx/include/sstream +++ b/libcxx/include/sstream @@ -1192,7 +1192,7 @@ swap(basic_stringstream<_CharT, _Traits, _Allocator>& __x, __x.swap(__y); } -#if defined(_LIBCPP_ABI_ENABLE_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1) +#ifndef _LIBCPP_AVAILABILITY_HAS_NO_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_stringbuf; extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_stringstream; extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_ostringstream; diff --git a/libcxx/src/future.cpp b/libcxx/src/future.cpp index fa1004e135712..3383b506a2fab 100644 --- a/libcxx/src/future.cpp +++ b/libcxx/src/future.cpp @@ -204,9 +204,7 @@ promise::~promise() { #ifndef _LIBCPP_HAS_NO_EXCEPTIONS if (!__state_->__has_value() && __state_->use_count() > 1) - __state_->set_exception(make_exception_ptr( - future_error(make_error_code(future_errc::broken_promise)) - )); + __state_->set_exception(make_exception_ptr(future_error(future_errc::broken_promise))); #endif // _LIBCPP_HAS_NO_EXCEPTIONS __state_->__release_shared(); } diff --git a/libcxx/src/ios.instantiations.cpp b/libcxx/src/ios.instantiations.cpp index 01fe199acb3c6..070f9891947c6 100644 --- a/libcxx/src/ios.instantiations.cpp +++ b/libcxx/src/ios.instantiations.cpp @@ -31,7 +31,7 @@ template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ostream; #endif // Additional instantiations added later. Whether programs rely on these being -// available is protected by _LIBCPP_ABI_ENABLE_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1. +// available is protected by _LIBCPP_AVAILABILITY_HAS_NO_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1. template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_stringbuf; template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_stringstream; template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ostringstream; diff --git a/libcxx/src/legacy_debug_handler.cpp b/libcxx/src/legacy_debug_handler.cpp deleted file mode 100644 index cb2025bfc9b6d..0000000000000 --- a/libcxx/src/legacy_debug_handler.cpp +++ /dev/null @@ -1,54 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include <__config> -#include -#include -#include - -// This file defines the legacy default debug handler and related mechanisms -// to set it. This is for backwards ABI compatibility with code that has been -// using this debug handler previously. - -_LIBCPP_BEGIN_NAMESPACE_STD - -struct _LIBCPP_TEMPLATE_VIS __libcpp_debug_info { - _LIBCPP_EXPORTED_FROM_ABI string what() const; - - const char* __file_; - int __line_; - const char* __pred_; - const char* __msg_; -}; - -std::string __libcpp_debug_info::what() const { - string msg = __file_; - msg += ":" + std::to_string(__line_) + ": _LIBCPP_ASSERT '"; - msg += __pred_; - msg += "' failed. "; - msg += __msg_; - return msg; -} - -_LIBCPP_NORETURN _LIBCPP_EXPORTED_FROM_ABI void __libcpp_abort_debug_function(__libcpp_debug_info const& info) { - std::fprintf(stderr, "%s\n", info.what().c_str()); - std::abort(); -} - -typedef void (*__libcpp_debug_function_type)(__libcpp_debug_info const&); - -_LIBCPP_EXPORTED_FROM_ABI -constinit __libcpp_debug_function_type __libcpp_debug_function = __libcpp_abort_debug_function; - -_LIBCPP_EXPORTED_FROM_ABI -bool __libcpp_set_debug_function(__libcpp_debug_function_type __func) { - __libcpp_debug_function = __func; - return true; -} - -_LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/CMakeLists.txt b/libcxx/test/CMakeLists.txt index 0d5fa6959f178..48dd233462ab3 100644 --- a/libcxx/test/CMakeLists.txt +++ b/libcxx/test/CMakeLists.txt @@ -1,3 +1,4 @@ +include(HandleLitArguments) add_subdirectory(tools) # By default, libcxx and libcxxabi share a library directory. @@ -9,40 +10,32 @@ endif() set(AUTO_GEN_COMMENT "## Autogenerated by libcxx configuration.\n# Do not edit!") set(SERIALIZED_LIT_PARAMS "# Lit parameters serialized here for llvm-lit to pick them up\n") -macro(serialize_lit_param param value) - string(APPEND SERIALIZED_LIT_PARAMS "config.${param} = ${value}\n") -endmacro() - if (LIBCXX_EXECUTOR) message(DEPRECATION "LIBCXX_EXECUTOR is deprecated, please add executor=... to LIBCXX_TEST_PARAMS") - serialize_lit_param(executor "\"${LIBCXX_EXECUTOR}\"") + serialize_lit_string_param(SERIALIZED_LIT_PARAMS executor "${LIBCXX_EXECUTOR}") endif() if (NOT LIBCXX_ENABLE_EXCEPTIONS) - serialize_lit_param(enable_exceptions False) + serialize_lit_param(SERIALIZED_LIT_PARAMS enable_exceptions False) endif() if (NOT LIBCXX_ENABLE_RTTI) - serialize_lit_param(enable_rtti False) + serialize_lit_param(SERIALIZED_LIT_PARAMS enable_rtti False) endif() -serialize_lit_param(hardening_mode "\"${LIBCXX_HARDENING_MODE}\"") +serialize_lit_string_param(SERIALIZED_LIT_PARAMS hardening_mode "${LIBCXX_HARDENING_MODE}") if (CMAKE_CXX_COMPILER_TARGET) - serialize_lit_param(target_triple "\"${CMAKE_CXX_COMPILER_TARGET}\"") + serialize_lit_string_param(SERIALIZED_LIT_PARAMS target_triple "${CMAKE_CXX_COMPILER_TARGET}") else() - serialize_lit_param(target_triple "\"${LLVM_DEFAULT_TARGET_TRIPLE}\"") + serialize_lit_string_param(SERIALIZED_LIT_PARAMS target_triple "${LLVM_DEFAULT_TARGET_TRIPLE}") endif() if (LLVM_USE_SANITIZER) - serialize_lit_param(use_sanitizer "\"${LLVM_USE_SANITIZER}\"") + serialize_lit_string_param(SERIALIZED_LIT_PARAMS use_sanitizer "${LLVM_USE_SANITIZER}") endif() -foreach(param IN LISTS LIBCXX_TEST_PARAMS) - string(REGEX REPLACE "(.+)=(.+)" "\\1" name "${param}") - string(REGEX REPLACE "(.+)=(.+)" "\\2" value "${param}") - serialize_lit_param("${name}" "\"${value}\"") -endforeach() +serialize_lit_params_list(SERIALIZED_LIT_PARAMS LIBCXX_TEST_PARAMS) if (NOT DEFINED LIBCXX_TEST_DEPS) message(FATAL_ERROR "Expected LIBCXX_TEST_DEPS to be defined") @@ -68,9 +61,9 @@ if (MSVC) set(cxx_lib "${cxx_lib}d") endif() - serialize_lit_param(dbg_include "\"${dbg_include}\"") - serialize_lit_param(fms_runtime_lib "\"${fms_runtime_lib}\"") - serialize_lit_param(cxx_lib "\"${cxx_lib}\"") + serialize_lit_string_param(SERIALIZED_LIT_PARAMS dbg_include "${dbg_include}") + serialize_lit_string_param(SERIALIZED_LIT_PARAMS fms_runtime_lib "${fms_runtime_lib}") + serialize_lit_string_param(SERIALIZED_LIT_PARAMS cxx_lib "${cxx_lib}") endif() if (LIBCXX_INCLUDE_TESTS) diff --git a/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp b/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp index 89349d1610d0d..e3733bf468da4 100644 --- a/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp +++ b/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp @@ -17,7 +17,9 @@ #include <__config> #include <__iterator/iterator_traits.h> #include <__iterator/readable_traits.h> +#include <__utility/empty.h> #include +#include struct TestPolicy {}; struct TestBackend {}; @@ -27,7 +29,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD bool pstl_any_of_called = false; template -bool __pstl_any_of(TestBackend, ForwardIterator, ForwardIterator, Pred) { +optional __pstl_any_of(TestBackend, ForwardIterator, ForwardIterator, Pred) { assert(!pstl_any_of_called); pstl_any_of_called = true; return true; @@ -36,7 +38,7 @@ bool __pstl_any_of(TestBackend, ForwardIterator, ForwardIterator, Pred) { bool pstl_all_of_called = false; template -bool __pstl_all_of(TestBackend, ForwardIterator, ForwardIterator, Pred) { +optional __pstl_all_of(TestBackend, ForwardIterator, ForwardIterator, Pred) { assert(!pstl_all_of_called); pstl_all_of_called = true; return true; @@ -45,25 +47,25 @@ bool __pstl_all_of(TestBackend, ForwardIterator, ForwardIterator, Pred) { bool pstl_copy_called = false; template -ForwardIterator __pstl_copy(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator) { +optional __pstl_copy(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator res) { assert(!pstl_copy_called); pstl_copy_called = true; - return 0; + return res; } bool pstl_copy_n_called = false; template -ForwardIterator __pstl_copy_n(TestBackend, ForwardIterator, Size, ForwardOutIterator) { +optional __pstl_copy_n(TestBackend, ForwardIterator, Size, ForwardOutIterator res) { assert(!pstl_copy_n_called); pstl_copy_n_called = true; - return 0; + return res; } bool pstl_count_called = false; template -typename std::iterator_traits::difference_type +optional::difference_type> __pstl_count(TestBackend, ForwardIterator, ForwardIterator, const T&) { assert(!pstl_count_called); pstl_count_called = true; @@ -73,7 +75,7 @@ __pstl_count(TestBackend, ForwardIterator, ForwardIterator, const T&) { bool pstl_count_if_called = false; template -typename std::iterator_traits::difference_type +optional::difference_type> __pstl_count_if(TestBackend, ForwardIterator, ForwardIterator, Pred) { assert(!pstl_count_if_called); pstl_count_if_called = true; @@ -83,23 +85,25 @@ __pstl_count_if(TestBackend, ForwardIterator, ForwardIterator, Pred) { bool pstl_generate_called = false; template -void __pstl_generate(TestBackend, ForwardIterator, ForwardIterator, Gen) { +optional<__empty> __pstl_generate(TestBackend, ForwardIterator, ForwardIterator, Gen) { assert(!pstl_generate_called); pstl_generate_called = true; + return __empty{}; } bool pstl_generate_n_called = false; template -void __pstl_generate_n(TestBackend, Size, ForwardIterator, Gen) { +optional<__empty> __pstl_generate_n(TestBackend, Size, ForwardIterator, Gen) { assert(!pstl_generate_n_called); pstl_generate_n_called = true; + return __empty{}; } bool pstl_none_of_called = false; template -bool __pstl_none_of(TestBackend, ForwardIterator, ForwardIterator, Pred) { +optional __pstl_none_of(TestBackend, ForwardIterator, ForwardIterator, Pred) { assert(!pstl_none_of_called); pstl_none_of_called = true; return true; @@ -108,164 +112,177 @@ bool __pstl_none_of(TestBackend, ForwardIterator, ForwardIterator, Pred) { bool pstl_find_called = false; template -ForwardIterator __pstl_find(TestBackend, ForwardIterator, ForwardIterator, Pred) { +optional __pstl_find(TestBackend, ForwardIterator first, ForwardIterator, Pred) { assert(!pstl_find_called); pstl_find_called = true; - return {}; + return first; } bool pstl_find_if_called = false; template -ForwardIterator __pstl_find_if(TestBackend, ForwardIterator, ForwardIterator, Pred) { +optional __pstl_find_if(TestBackend, ForwardIterator first, ForwardIterator, Pred) { assert(!pstl_find_if_called); pstl_find_if_called = true; - return {}; + return first; } bool pstl_find_if_not_called = false; template -ForwardIterator __pstl_find_if_not(TestBackend, ForwardIterator, ForwardIterator, Pred) { +optional __pstl_find_if_not(TestBackend, ForwardIterator first, ForwardIterator, Pred) { assert(!pstl_find_if_not_called); pstl_find_if_not_called = true; - return {}; + return first; } bool pstl_for_each_called = false; template -void __pstl_for_each(TestBackend, ForwardIterator, Size, Func) { +optional<__empty> __pstl_for_each(TestBackend, ForwardIterator, Size, Func) { assert(!pstl_for_each_called); pstl_for_each_called = true; + return __empty{}; } bool pstl_for_each_n_called = false; template -void __pstl_for_each_n(TestBackend, ForwardIterator, Size, Func) { +optional<__empty> __pstl_for_each_n(TestBackend, ForwardIterator, Size, Func) { assert(!pstl_for_each_n_called); pstl_for_each_n_called = true; + return __empty{}; } bool pstl_fill_called = false; template -void __pstl_fill(TestBackend, ForwardIterator, Size, Func) { +optional<__empty> __pstl_fill(TestBackend, ForwardIterator, Size, Func) { assert(!pstl_fill_called); pstl_fill_called = true; + return __empty{}; } bool pstl_fill_n_called = false; template -void __pstl_fill_n(TestBackend, ForwardIterator, Size, Func) { +optional<__empty> __pstl_fill_n(TestBackend, ForwardIterator, Size, Func) { assert(!pstl_fill_n_called); pstl_fill_n_called = true; + return __empty{}; } bool pstl_is_partitioned_called = false; template -bool __pstl_is_partitioned(TestBackend, ForwardIterator, ForwardIterator, Func) { +optional __pstl_is_partitioned(TestBackend, ForwardIterator, ForwardIterator, Func) { assert(!pstl_is_partitioned_called); pstl_is_partitioned_called = true; - return {}; + return true; } bool pstl_replace_called = false; template -void __pstl_replace(TestBackend, ForwardIterator, ForwardIterator, const T&, const T&) { +optional<__empty> __pstl_replace(TestBackend, ForwardIterator, ForwardIterator, const T&, const T&) { assert(!pstl_replace_called); pstl_replace_called = true; + return __empty{}; } bool pstl_replace_if_called = false; template -void __pstl_replace_if(TestBackend, ForwardIterator, ForwardIterator, Func, const T&) { +optional<__empty> __pstl_replace_if(TestBackend, ForwardIterator, ForwardIterator, Func, const T&) { assert(!pstl_replace_if_called); pstl_replace_if_called = true; + return __empty{}; } bool pstl_replace_copy_called = false; template -void __pstl_replace_copy(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, const T&, const T&) { +optional<__empty> +__pstl_replace_copy(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, const T&, const T&) { assert(!pstl_replace_copy_called); pstl_replace_copy_called = true; + return __empty{}; } bool pstl_replace_copy_if_called = false; template -void __pstl_replace_copy_if(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, Func, const T&) { +optional<__empty> +__pstl_replace_copy_if(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, Func, const T&) { assert(!pstl_replace_copy_if_called); pstl_replace_copy_if_called = true; + return __empty{}; } bool pstl_unary_transform_called = false; template -ForwardOutIterator __pstl_transform(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, UnaryOperation) { +optional +__pstl_transform(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator res, UnaryOperation) { assert(!pstl_unary_transform_called); pstl_unary_transform_called = true; - return {}; + return res; } bool pstl_binary_transform_called = false; template -ForwardOutIterator __pstl_transform( - TestBackend, ForwardIterator1, ForwardIterator1, ForwardIterator2, ForwardOutIterator, BinaryOperation) { +optional __pstl_transform( + TestBackend, ForwardIterator1, ForwardIterator1, ForwardIterator2, ForwardOutIterator res, BinaryOperation) { assert(!pstl_binary_transform_called); pstl_binary_transform_called = true; - return {}; + return res; } bool pstl_reduce_with_init_called = false; template -T __pstl_reduce(TestBackend, ForwardIterator, ForwardIterator, T, BinaryOperation) { +optional __pstl_reduce(TestBackend, ForwardIterator, ForwardIterator, T v, BinaryOperation) { assert(!pstl_reduce_with_init_called); pstl_reduce_with_init_called = true; - return {}; + return v; } bool pstl_reduce_without_init_called = false; template -typename std::iterator_traits::value_type -__pstl_reduce(TestBackend, ForwardIterator, ForwardIterator) { +optional::value_type> +__pstl_reduce(TestBackend, ForwardIterator first, ForwardIterator) { assert(!pstl_reduce_without_init_called); pstl_reduce_without_init_called = true; - return {}; + return *first; } bool pstl_sort_called = false; template -void __pstl_sort(TestBackend, RandomAccessIterator, RandomAccessIterator, Comp) { +optional<__empty> __pstl_sort(TestBackend, RandomAccessIterator, RandomAccessIterator, Comp) { assert(!pstl_sort_called); pstl_sort_called = true; + return __empty{}; } bool pstl_stable_sort_called = false; template -void __pstl_stable_sort(TestBackend, RandomAccessIterator, RandomAccessIterator, Comp) { +optional<__empty> __pstl_stable_sort(TestBackend, RandomAccessIterator, RandomAccessIterator, Comp) { assert(!pstl_stable_sort_called); pstl_stable_sort_called = true; + return __empty{}; } bool pstl_unary_transform_reduce_called = false; template -T __pstl_transform_reduce(TestBackend, ForwardIterator, ForwardIterator, T, UnaryOperation, BinaryOperation) { +T __pstl_transform_reduce(TestBackend, ForwardIterator, ForwardIterator, T v, UnaryOperation, BinaryOperation) { assert(!pstl_unary_transform_reduce_called); pstl_unary_transform_reduce_called = true; - return {}; + return v; } bool pstl_binary_transform_reduce_called = false; @@ -277,10 +294,10 @@ template typename std::iterator_traits::value_type __pstl_transform_reduce( - TestBackend, ForwardIterator1, ForwardIterator1, ForwardIterator2, T, BinaryOperation1, BinaryOperation2) { + TestBackend, ForwardIterator1, ForwardIterator1, ForwardIterator2, T v, BinaryOperation1, BinaryOperation2) { assert(!pstl_binary_transform_reduce_called); pstl_binary_transform_reduce_called = true; - return {}; + return v; } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/libcxx/memory/shared_ptr_array.pass.cpp b/libcxx/test/libcxx/memory/shared_ptr_array.pass.cpp new file mode 100644 index 0000000000000..772198304b415 --- /dev/null +++ b/libcxx/test/libcxx/memory/shared_ptr_array.pass.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// REQUIRES: -fsized-deallocation +// ADDITIONAL_COMPILE_FLAGS: -fsized-deallocation + +// This test will fail with ASan if the implementation passes different sizes +// to corresponding allocation and deallocation functions. + +#include + +int main(int, char**) { + std::allocate_shared(std::allocator{}, 10); + std::make_shared(10); + + std::allocate_shared(std::allocator{}); + std::make_shared(); + + return 0; +} diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv index 70dbad21780a1..f6aeb837a7292 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx03.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -6,7 +6,6 @@ algorithm cstddef algorithm cstdint algorithm cstdlib algorithm cstring -algorithm ctime algorithm cwchar algorithm execution algorithm initializer_list @@ -15,7 +14,7 @@ algorithm iterator algorithm limits algorithm memory algorithm new -algorithm ratio +algorithm optional algorithm stdexcept algorithm type_traits algorithm utility @@ -585,15 +584,12 @@ numeric cmath numeric concepts numeric cstddef numeric cstdint -numeric cstring -numeric ctime numeric execution numeric functional -numeric initializer_list numeric iterator numeric limits numeric new -numeric ratio +numeric optional numeric type_traits numeric version optional atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv index 1ee950f9fc30e..08fd94393f473 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx11.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -6,7 +6,6 @@ algorithm cstddef algorithm cstdint algorithm cstdlib algorithm cstring -algorithm ctime algorithm cwchar algorithm execution algorithm initializer_list @@ -15,7 +14,7 @@ algorithm iterator algorithm limits algorithm memory algorithm new -algorithm ratio +algorithm optional algorithm stdexcept algorithm type_traits algorithm utility @@ -590,15 +589,12 @@ numeric cmath numeric concepts numeric cstddef numeric cstdint -numeric cstring -numeric ctime numeric execution numeric functional -numeric initializer_list numeric iterator numeric limits numeric new -numeric ratio +numeric optional numeric type_traits numeric version optional atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv index 22e1d30f7fd67..33384a628e65c 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx14.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -6,7 +6,6 @@ algorithm cstddef algorithm cstdint algorithm cstdlib algorithm cstring -algorithm ctime algorithm cwchar algorithm execution algorithm initializer_list @@ -15,7 +14,7 @@ algorithm iterator algorithm limits algorithm memory algorithm new -algorithm ratio +algorithm optional algorithm stdexcept algorithm type_traits algorithm utility @@ -592,15 +591,12 @@ numeric cmath numeric concepts numeric cstddef numeric cstdint -numeric cstring -numeric ctime numeric execution numeric functional -numeric initializer_list numeric iterator numeric limits numeric new -numeric ratio +numeric optional numeric type_traits numeric version optional atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv index 22e1d30f7fd67..33384a628e65c 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx17.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -6,7 +6,6 @@ algorithm cstddef algorithm cstdint algorithm cstdlib algorithm cstring -algorithm ctime algorithm cwchar algorithm execution algorithm initializer_list @@ -15,7 +14,7 @@ algorithm iterator algorithm limits algorithm memory algorithm new -algorithm ratio +algorithm optional algorithm stdexcept algorithm type_traits algorithm utility @@ -592,15 +591,12 @@ numeric cmath numeric concepts numeric cstddef numeric cstdint -numeric cstring -numeric ctime numeric execution numeric functional -numeric initializer_list numeric iterator numeric limits numeric new -numeric ratio +numeric optional numeric type_traits numeric version optional atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv index 0cbd4c52c6e4c..8f6e8dd646df5 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx20.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -6,7 +6,6 @@ algorithm cstddef algorithm cstdint algorithm cstdlib algorithm cstring -algorithm ctime algorithm cwchar algorithm execution algorithm initializer_list @@ -15,7 +14,7 @@ algorithm iterator algorithm limits algorithm memory algorithm new -algorithm ratio +algorithm optional algorithm stdexcept algorithm type_traits algorithm utility @@ -597,15 +596,12 @@ numeric cmath numeric concepts numeric cstddef numeric cstdint -numeric cstring -numeric ctime numeric execution numeric functional -numeric initializer_list numeric iterator numeric limits numeric new -numeric ratio +numeric optional numeric type_traits numeric version optional atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv index 8b32cad73fb5a..d0d858056b1b0 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx23.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv @@ -9,6 +9,7 @@ algorithm initializer_list algorithm iosfwd algorithm limits algorithm new +algorithm optional algorithm ratio algorithm version any cstddef @@ -432,6 +433,7 @@ numeric execution numeric initializer_list numeric limits numeric new +numeric optional numeric ratio numeric version optional compare diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv index 8b32cad73fb5a..d0d858056b1b0 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx26.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv @@ -9,6 +9,7 @@ algorithm initializer_list algorithm iosfwd algorithm limits algorithm new +algorithm optional algorithm ratio algorithm version any cstddef @@ -432,6 +433,7 @@ numeric execution numeric initializer_list numeric limits numeric new +numeric optional numeric ratio numeric version optional compare diff --git a/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp b/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp index 7ba91f82bc3bb..1f5dae1232e37 100644 --- a/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp +++ b/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp @@ -17,7 +17,7 @@ // Test that we provide the non-trivial copy operations when _LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR // is specified. // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR -// ADDITIONAL_COMPILE_FLAGS: -Wno-macro-redefined +// ADDITIONAL_COMPILE_FLAGS: -Wno-macro-redefined -Wno-invalid-offsetof #include #include diff --git a/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/trivial_copy_move_ABI.pass.cpp b/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/trivial_copy_move_ABI.pass.cpp index 013b79b1425a2..fe098a7af7e8f 100644 --- a/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/trivial_copy_move_ABI.pass.cpp +++ b/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/trivial_copy_move_ABI.pass.cpp @@ -14,6 +14,7 @@ // FreeBSD still provides the old ABI for std::pair. // XFAIL: freebsd +// ADDITIONAL_COMPILE_FLAGS: -Wno-invalid-offsetof #include #include diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp new file mode 100644 index 0000000000000..f7279655cb129 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::fill(ExecutionPolicy) and std::fill_n(ExecutionPolicy) terminate on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct ThrowOnCopy { + ThrowOnCopy& operator=(const ThrowOnCopy&) { throw int{}; } +}; +#endif + +int main(int, char**) { + ThrowOnCopy a[2]{}; + int b[2]{}; + + test_execution_policies([&](auto&& policy) { + // std::fill + EXPECT_STD_TERMINATE([&] { (void)std::fill(policy, std::begin(a), std::end(a), ThrowOnCopy{}); }); + EXPECT_STD_TERMINATE([&] { + try { + (void)std::fill( + policy, util::throw_on_move_iterator(std::begin(b), 1), util::throw_on_move_iterator(std::end(b), 1), 0); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + // std::fill_n + EXPECT_STD_TERMINATE([&] { (void)std::fill_n(policy, std::begin(a), std::size(a), ThrowOnCopy{}); }); + EXPECT_STD_TERMINATE([&] { + try { + (void)std::fill_n(policy, util::throw_on_move_iterator(std::begin(b), 1), std::size(b), 0); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.pass.cpp index a341816b10b6e..556326fb0894c 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.pass.cpp @@ -61,24 +61,8 @@ struct Test { } }; -#ifndef TEST_HAS_NO_EXCEPTIONS -struct ThrowOnCopy { - ThrowOnCopy& operator=(const ThrowOnCopy&) { throw int{}; } -}; -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - ThrowOnCopy a[2]; - try { - (void)std::fill(std::execution::par, std::begin(a), std::end(a), ThrowOnCopy{}); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp index 594ac6a44bef4..4abbd6f7a17c3 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp @@ -61,24 +61,8 @@ struct Test { } }; -#ifndef TEST_HAS_NO_EXCEPTIONS -struct ThrowOnCopy { - ThrowOnCopy& operator=(const ThrowOnCopy&) { throw int{}; } -}; -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - ThrowOnCopy a[2]; - try { - (void)std::fill_n(std::execution::par, std::begin(a), std::size(a), ThrowOnCopy{}); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp new file mode 100644 index 0000000000000..98fde95fb0e44 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp @@ -0,0 +1,117 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::replace(ExecutionPolicy), std::replace_if(ExecutionPolicy), std::replace_copy(ExecutionPolicy) +// and std::replace_copy_if(ExecutionPolicy) terminate on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +struct ThrowOnCompare {}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } +#endif + +int main(int, char**) { + test_execution_policies([&](auto&& policy) { + // std::replace + EXPECT_STD_TERMINATE([&] { + ThrowOnCompare a[2]{}; + (void)std::replace(policy, std::begin(a), std::end(a), ThrowOnCompare{}, ThrowOnCompare{}); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::replace( + policy, util::throw_on_move_iterator(std::begin(a), 1), util::throw_on_move_iterator(std::end(a), 1), 1, 2); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + // std::replace_if + EXPECT_STD_TERMINATE([&] { + ThrowOnCompare a[2]{}; + (void)std::replace_if( + policy, std::begin(a), std::end(a), [](ThrowOnCompare&) -> bool { throw int{}; }, ThrowOnCompare{}); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::replace_if( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + [](int) { return true; }, + 2); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + // std::replace_copy + EXPECT_STD_TERMINATE([&] { + ThrowOnCompare a[2]{}; + (void)std::replace_copy(policy, std::begin(a), std::end(a), std::begin(a), ThrowOnCompare{}, ThrowOnCompare{}); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::replace_copy( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + 1, + 2); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + // std::replace_copy_if + EXPECT_STD_TERMINATE([&] { + ThrowOnCompare a[2]{}; + (void)std::replace_copy_if( + policy, + std::begin(a), + std::end(a), + std::begin(a), + [](ThrowOnCompare& i) { return i == i; }, + ThrowOnCompare{}); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::replace_copy_if( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + [](int) { return true; }, + 2); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp index 0b51d35cdeb99..751d6b74b0128 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp @@ -73,24 +73,8 @@ struct Test { } }; -struct ThrowOnCompare {}; - -#ifndef TEST_HAS_NO_EXCEPTIONS -bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - ThrowOnCompare a[2]; - try { - (void)std::replace(std::execution::par, std::begin(a), std::end(a), ThrowOnCompare{}, ThrowOnCompare{}); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp index 29c9692e0307a..f24bedabebccd 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp @@ -82,25 +82,8 @@ struct Test { } }; -struct ThrowOnCompare {}; - -#ifndef TEST_HAS_NO_EXCEPTIONS -bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - ThrowOnCompare a[2]; - try { - (void)std::replace_copy( - std::execution::par, std::begin(a), std::end(a), std::begin(a), ThrowOnCompare{}, ThrowOnCompare{}); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp index 965cedb91c4e1..f7c746f382d11 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp @@ -95,30 +95,8 @@ struct Test { } }; -struct ThrowOnCompare {}; - -#ifndef TEST_HAS_NO_EXCEPTIONS -bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - ThrowOnCompare a[2]; - try { - (void)std::replace_copy_if( - std::execution::par, - std::begin(a), - std::end(a), - std::begin(a), - [](ThrowOnCompare& i) { return i == i; }, - ThrowOnCompare{}); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp index 2f81955a029d6..3ffc1c021bb9c 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp @@ -78,25 +78,8 @@ struct Test { } }; -struct ThrowOnCompare {}; - -#ifndef TEST_HAS_NO_EXCEPTIONS -bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - ThrowOnCompare a[2]; - try { - (void)std::replace_if( - std::execution::par, std::begin(a), std::end(a), [](ThrowOnCompare&) { return false; }, ThrowOnCompare{}); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp new file mode 100644 index 0000000000000..6c7149f4048ad --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::transform(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([&](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + int a[2]{}; + int b[2]{}; + int c[2]{}; + (void)std::transform( + policy, std::begin(a), std::end(a), std::begin(b), std::begin(c), [](auto v, auto) -> decltype(v) { + throw int{}; + }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::transform( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + [](int i) { return i; }); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + EXPECT_STD_TERMINATE([&] { + int a[2]{}; + int b[2]{}; + (void)std::transform(policy, std::begin(a), std::end(a), std::begin(b), [](auto v) -> decltype(v) { + throw int{}; + }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::transform( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + std::plus{}); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.pass.cpp index 82ba4338886d6..a3af9b949bfd2 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.pass.cpp @@ -69,15 +69,5 @@ struct Test { int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - (void)std::all_of(std::execution::par, std::begin(a), std::end(a), [](int i) -> bool { throw i; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.cpp new file mode 100644 index 0000000000000..cc62979835361 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: no-exceptions + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::all_of(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + int a[] = {1, 2}; + (void)std::all_of(policy, std::begin(a), std::end(a), [](int i) -> bool { throw i; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::all_of( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + [](int) { return true; }); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.pass.cpp index c21ce8afe556b..229bf576dd801 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.pass.cpp @@ -63,15 +63,5 @@ struct Test { int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - (void)std::any_of(std::execution::par, std::begin(a), std::end(a), [](int i) -> bool { throw i; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp new file mode 100644 index 0000000000000..167c4ac4df95e --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::any_of(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + int a[] = {1, 2}; + (void)std::any_of(policy, std::begin(a), std::end(a), [](int i) -> bool { throw i; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::any_of( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + [](int) { return true; }); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp index 1cb45cff9c6d3..cc832febdba75 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp @@ -13,35 +13,50 @@ // constexpr Iter::difference_type // constexpr after C++17 // count(Iter first, Iter last, const T& value); +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=70000000 + #include #include +#include #include "test_macros.h" #include "test_iterators.h" - -#if TEST_STD_VER > 17 -TEST_CONSTEXPR bool test_constexpr() { - int ia[] = {0, 1, 2, 2, 0, 1, 2, 3}; - int ib[] = {1, 2, 3, 4, 5, 6}; - return (std::count(std::begin(ia), std::end(ia), 2) == 3) - && (std::count(std::begin(ib), std::end(ib), 9) == 0) - ; +#include "type_algorithms.h" + +struct Test { + template + TEST_CONSTEXPR_CXX20 void operator()() { + int ia[] = {0, 1, 2, 2, 0, 1, 2, 3}; + const unsigned sa = sizeof(ia) / sizeof(ia[0]); + assert(std::count(Iter(ia), Iter(ia + sa), 2) == 3); + assert(std::count(Iter(ia), Iter(ia + sa), 7) == 0); + assert(std::count(Iter(ia), Iter(ia), 2) == 0); + } +}; + +TEST_CONSTEXPR_CXX20 bool test() { + types::for_each(types::cpp17_input_iterator_list(), Test()); + + if (!TEST_IS_CONSTANT_EVALUATED || TEST_STD_VER >= 20) { + std::vector vec(256 + 64); + for (ptrdiff_t i = 0; i != 256; ++i) { + for (size_t offset = 0; offset != 64; ++offset) { + std::fill(vec.begin(), vec.end(), false); + std::fill(vec.begin() + offset, vec.begin() + i + offset, true); + assert(std::count(vec.begin() + offset, vec.begin() + offset + 256, true) == i); + assert(std::count(vec.begin() + offset, vec.begin() + offset + 256, false) == 256 - i); + } } -#endif + } + + return true; +} -int main(int, char**) -{ - int ia[] = {0, 1, 2, 2, 0, 1, 2, 3}; - const unsigned sa = sizeof(ia)/sizeof(ia[0]); - assert(std::count(cpp17_input_iterator(ia), - cpp17_input_iterator(ia + sa), 2) == 3); - assert(std::count(cpp17_input_iterator(ia), - cpp17_input_iterator(ia + sa), 7) == 0); - assert(std::count(cpp17_input_iterator(ia), - cpp17_input_iterator(ia), 2) == 0); - -#if TEST_STD_VER > 17 - static_assert(test_constexpr()); +int main(int, char**) { + test(); +#if TEST_STD_VER >= 20 + static_assert(test()); #endif return 0; diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp index b2ad0165036bb..b17272ea90cdd 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp @@ -10,6 +10,9 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=70000000 + // template S, class T, class Proj = identity> // requires indirect_binary_predicate, const T*> // constexpr iter_difference_t @@ -23,6 +26,7 @@ #include #include #include +#include #include "almost_satisfies_types.h" #include "test_iterators.h" @@ -253,6 +257,18 @@ constexpr bool test() { } } + { // check that __bit_iterator optimizations work as expected + std::vector vec(256 + 64); + for (ptrdiff_t i = 0; i != 256; ++i) { + for (size_t offset = 0; offset != 64; ++offset) { + std::fill(vec.begin(), vec.end(), false); + std::fill(vec.begin() + offset, vec.begin() + i + offset, true); + assert(std::ranges::count(vec.begin() + offset, vec.begin() + offset + 256, true) == i); + assert(std::ranges::count(vec.begin() + offset, vec.begin() + offset + 256, false) == 256 - i); + } + } + } + return true; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp new file mode 100644 index 0000000000000..06b0810c257b3 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::find(ExecutionPolicy), std::find_if(ExecutionPolicy) and std::find_if_not(ExecutionPolicy) terminate +// on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +struct ThrowOnCompare {}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } +#endif + +int main(int, char**) { + test_execution_policies([](auto&& policy) { + // std::find + EXPECT_STD_TERMINATE([&] { + ThrowOnCompare a[2] = {}; + (void)std::find(policy, std::begin(a), std::end(a), ThrowOnCompare{}); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::find( + policy, util::throw_on_move_iterator(std::begin(a), 1), util::throw_on_move_iterator(std::end(a), 1), 0); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + // std::find_if + EXPECT_STD_TERMINATE([&] { + int a[] = {1, 2}; + (void)std::find_if(policy, std::begin(a), std::end(a), [](int) -> bool { throw int{}; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::find_if( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + [](int) { return true; }); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + // std::find_if_not + EXPECT_STD_TERMINATE([&] { + int a[] = {1, 2}; + (void)std::find_if_not(policy, std::begin(a), std::end(a), [](int) -> bool { throw int{}; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::find_if_not( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + [](int) { return true; }); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp index 9822ffbff8b03..8a9eee81d95c0 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp @@ -61,24 +61,8 @@ struct Test { } }; -struct ThrowOnCompare {}; - -#ifndef TEST_HAS_NO_EXCEPTIONS -bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - ThrowOnCompare a[2]; - try { - (void)std::find(std::execution::par, std::begin(a), std::end(a), ThrowOnCompare{}); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp index c67868ccc8881..49eef2a7bc55f 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp @@ -70,15 +70,5 @@ struct Test { int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - (void)std::find_if(std::execution::par, std::begin(a), std::end(a), [](int) -> bool { throw int{}; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp index d536249f6f1e2..e5a242c57a2c4 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp @@ -71,15 +71,5 @@ struct Test { int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - (void)std::find_if_not(std::execution::par, std::begin(a), std::end(a), [](int) -> bool { throw int{}; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp new file mode 100644 index 0000000000000..ab15bdf5d8b99 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::for_each(ExecutionPolicy) and std::for_each_n(ExecutionPolicy) terminate on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([](auto&& policy) { + int a[] = {1, 2}; + // std::for_each + EXPECT_STD_TERMINATE([&] { std::for_each(policy, std::begin(a), std::end(a), [](int) { throw int{}; }); }); + EXPECT_STD_TERMINATE([&] { + try { + (void)std::for_each( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + [](int) {}); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + // std::for_each_n + EXPECT_STD_TERMINATE([&] { std::for_each_n(policy, std::data(a), std::size(a), [](int) { throw int{}; }); }); + EXPECT_STD_TERMINATE([&] { + try { + (void)std::for_each_n(policy, util::throw_on_move_iterator(std::begin(a), 1), std::size(a), [](int) {}); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp index 4f70c1be30745..b0e77094f0a42 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp @@ -51,15 +51,5 @@ struct Test { int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - std::for_each(std::execution::par, std::begin(a), std::end(a), [](int) { throw int{}; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp index 4efe19944183e..d5b42966b0000 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp @@ -50,15 +50,5 @@ struct Test { int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - std::for_each_n(std::execution::par, std::data(a), std::size(a), [](int) { throw int{}; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp new file mode 100644 index 0000000000000..9a6d8d636200c --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::none_of(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + int a[] = {1, 2}; + (void)std::none_of(policy, std::begin(a), std::end(a), [](int i) -> bool { throw i; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::none_of( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + [](int) { return true; }); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.pass.cpp index f6dfe0cbf7b3d..fb3e34a2bdec3 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.pass.cpp @@ -63,15 +63,5 @@ struct Test { int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - (void)std::none_of(std::execution::par, std::begin(a), std::end(a), [](int i) -> bool { throw i; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp new file mode 100644 index 0000000000000..b56959809829b --- /dev/null +++ b/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::merge(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + int a[] = {1, 2}; + std::merge(policy, std::begin(a), std::end(a), std::begin(a), std::end(a), std::begin(a), [](int, int) -> bool { + throw int{}; + }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::merge( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + std::less{}); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); + + return 0; +} diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp new file mode 100644 index 0000000000000..43ee937a8a185 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::stable_sort(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + int a[] = {1, 2}; + std::stable_sort(policy, std::begin(a), std::end(a), [](int, int) -> bool { throw int{}; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::stable_sort( + policy, util::throw_on_move_iterator(std::begin(a), 1), util::throw_on_move_iterator(std::end(a), 1)); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.pass.cpp index 0c4dda5b03ca5..e1a64f5185b5d 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.pass.cpp @@ -146,15 +146,5 @@ int main(int, char**) { types::random_access_iterator_list>{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - std::stable_sort(std::execution::par, std::begin(a), std::end(a), [](int, int) -> bool { throw int{}; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp new file mode 100644 index 0000000000000..65a112774ff76 --- /dev/null +++ b/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::reduce(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([&](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::reduce( + policy, util::throw_on_move_iterator(std::begin(a), 1), util::throw_on_move_iterator(std::end(a), 1)); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + EXPECT_STD_TERMINATE([&] { + int a[2]{}; + (void)std::reduce(policy, std::begin(a), std::end(a), 1, [](int, int) -> int { throw 1; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::reduce( + policy, util::throw_on_move_iterator(std::begin(a), 1), util::throw_on_move_iterator(std::end(a), 1), 1); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp new file mode 100644 index 0000000000000..d2df251d5c8ad --- /dev/null +++ b/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::reduce(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([&](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::transform_reduce( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + 1); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + EXPECT_STD_TERMINATE([&] { + int a[2]{}; + (void)std::transform_reduce( + policy, std::begin(a), std::end(a), 1, [](int, int) -> int { throw 1; }, [](int) -> int { return 0; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::transform_reduce( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + 1, + std::plus{}, + [](int) -> int { return 0; }); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/depr/depr.numeric.imits.has.denorm/deprecated.verify.cpp b/libcxx/test/std/depr/depr.numeric.imits.has.denorm/deprecated.verify.cpp new file mode 100644 index 0000000000000..98d49de80a58c --- /dev/null +++ b/libcxx/test/std/depr/depr.numeric.imits.has.denorm/deprecated.verify.cpp @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// ADDITIONAL_COMPILE_FLAGS: -Wno-unused-value + +#include + +#include "type_algorithms.h" + +void func() { + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::numeric_limits::has_denorm; // expected-warning {{'has_denorm' is deprecated}} + std::numeric_limits< + const volatile long double>::has_denorm_loss; // expected-warning {{'has_denorm_loss' is deprecated}} + std::numeric_limits::denorm_min(); + + std::denorm_indeterminate; // expected-warning {{'denorm_indeterminate' is deprecated}} + std::denorm_absent; // expected-warning {{'denorm_absent' is deprecated}} + std::denorm_present; // expected-warning {{'denorm_present' is deprecated}} +} diff --git a/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/const_data_members.pass.cpp b/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/const_data_members.pass.cpp index 1d4c2686c7bb1..9d0b27c24eb89 100644 --- a/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/const_data_members.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/const_data_members.pass.cpp @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS + #include #include "test_macros.h" diff --git a/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/has_denorm.pass.cpp b/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/has_denorm.pass.cpp index 7ca5a3defa8c0..ae9f3d733ea6e 100644 --- a/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/has_denorm.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/has_denorm.pass.cpp @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS + // test numeric_limits // has_denorm diff --git a/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/has_denorm_loss.pass.cpp b/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/has_denorm_loss.pass.cpp index 7b88f3c2b292d..e5eac655c18f1 100644 --- a/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/has_denorm_loss.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/has_denorm_loss.pass.cpp @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS + // test numeric_limits // has_denorm_loss diff --git a/libcxx/test/std/language.support/support.limits/limits/numeric.limits/default.pass.cpp b/libcxx/test/std/language.support/support.limits/limits/numeric.limits/default.pass.cpp index 88ca21fbba481..ab96903c24f03 100644 --- a/libcxx/test/std/language.support/support.limits/limits/numeric.limits/default.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/limits/numeric.limits/default.pass.cpp @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS + // test numeric_limits // The default numeric_limits template shall have all members, but with diff --git a/libcxx/test/std/language.support/support.limits/limits/round.style/check_values.pass.cpp b/libcxx/test/std/language.support/support.limits/limits/round.style/check_values.pass.cpp index bb47763f376c8..e40526c7d0224 100644 --- a/libcxx/test/std/language.support/support.limits/limits/round.style/check_values.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/limits/round.style/check_values.pass.cpp @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS + // test numeric_limits // float_denorm_style diff --git a/libcxx/test/std/numerics/c.math/cmath.pass.cpp b/libcxx/test/std/numerics/c.math/cmath.pass.cpp index e2062cc7ecfd9..11a3de748cb7a 100644 --- a/libcxx/test/std/numerics/c.math/cmath.pass.cpp +++ b/libcxx/test/std/numerics/c.math/cmath.pass.cpp @@ -603,12 +603,20 @@ void test_fpclassify() static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); + static_assert((std::is_same())), int>::value), ""); + static_assert((std::is_same())), int>::value), ""); + static_assert((std::is_same())), int>::value), ""); + ASSERT_NOEXCEPT(std::fpclassify((float)0)); + ASSERT_NOEXCEPT(std::fpclassify((double)0)); + ASSERT_NOEXCEPT(std::fpclassify((long double)0)); + ASSERT_NOEXCEPT(std::fpclassify(0)); assert(std::fpclassify(-1.0) == FP_NORMAL); assert(std::fpclassify(0) == FP_ZERO); assert(std::fpclassify(1) == FP_NORMAL); assert(std::fpclassify(-1) == FP_NORMAL); assert(std::fpclassify(std::numeric_limits::max()) == FP_NORMAL); assert(std::fpclassify(std::numeric_limits::min()) == FP_NORMAL); + assert(std::fpclassify(Value()) == FP_NORMAL); } void test_isfinite() diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp index 07092b74be873..b894bc542be10 100644 --- a/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp @@ -10,9 +10,10 @@ // constexpr auto size() const requires see below; -#include #include +#include #include +#include #include "test_macros.h" #include "types.h" @@ -89,6 +90,15 @@ constexpr bool test() { assert(io.size() == 0); } + // Make sure iota_view works properly. For details, + // see https://github.com/llvm/llvm-project/issues/67551. + { + static_assert(std::ranges::sized_range>); + std::ranges::iota_view io(10, 20); + std::same_as auto sz = io.size(); + assert(sz == 10); + } + return true; } diff --git a/libcxx/test/std/ranges/range.utility/range.subrange/operator.pair_like.pass.cpp b/libcxx/test/std/ranges/range.utility/range.subrange/operator.pair_like.pass.cpp new file mode 100644 index 0000000000000..1d0dfd05b3f7e --- /dev/null +++ b/libcxx/test/std/ranges/range.utility/range.subrange/operator.pair_like.pass.cpp @@ -0,0 +1,80 @@ + +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// template PairLike> +// requires pair-like-convertible-from +// constexpr operator PairLike() const; + +#include +#include +#include + +#include "test_macros.h" + +static_assert(std::convertible_to, std::pair>); +static_assert(std::convertible_to, std::tuple>); +static_assert(!std::convertible_to, std::pair>); +static_assert(!std::convertible_to, std::pair>); +static_assert(!std::convertible_to, std::pair>); +static_assert(!std::convertible_to, std::array>); + +constexpr bool test() { + // Check to std::pair + { + int data[] = {1, 2, 3, 4, 5}; + const std::ranges::subrange a(data); + { + std::pair p(a); + assert(p.first == data + 0); + assert(p.second == data + 5); + } + { + std::pair p{a}; + assert(p.first == data + 0); + assert(p.second == data + 5); + } + { + std::pair p = a; + assert(p.first == data + 0); + assert(p.second == data + 5); + } + } + + // Check to std::tuple + { + int data[] = {1, 2, 3, 4, 5}; + const std::ranges::subrange a(data); + { + std::tuple p(a); + assert(std::get<0>(p) == data + 0); + assert(std::get<1>(p) == data + 5); + } + { + std::tuple p{a}; + assert(std::get<0>(p) == data + 0); + assert(std::get<1>(p) == data + 5); + } + { + std::tuple p = a; + assert(std::get<0>(p) == data + 0); + assert(std::get<1>(p) == data + 5); + } + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/thread/futures/futures.future_error/code.pass.cpp b/libcxx/test/std/thread/futures/futures.future_error/code.pass.cpp index 99d2ade796e45..22d74bba803d9 100644 --- a/libcxx/test/std/thread/futures/futures.future_error/code.pass.cpp +++ b/libcxx/test/std/thread/futures/futures.future_error/code.pass.cpp @@ -9,49 +9,43 @@ // UNSUPPORTED: no-threads // - +// // class future_error -// future_error(error_code __ec); // exposition only -// explicit future_error(future_errc _Ev) : __ec_(make_error_code(_Ev)) {} // C++17 - -// const error_code& code() const throw(); +// +// const error_code& code() const noexcept; -#include #include +#include +#include #include "test_macros.h" -int main(int, char**) -{ - { - std::error_code ec = std::make_error_code(std::future_errc::broken_promise); - std::future_error f(ec); - assert(f.code() == ec); - } - { - std::error_code ec = std::make_error_code(std::future_errc::future_already_retrieved); - std::future_error f(ec); - assert(f.code() == ec); - } - { - std::error_code ec = std::make_error_code(std::future_errc::promise_already_satisfied); - std::future_error f(ec); - assert(f.code() == ec); - } - { - std::error_code ec = std::make_error_code(std::future_errc::no_state); - std::future_error f(ec); - assert(f.code() == ec); - } -#if TEST_STD_VER > 14 - { - std::future_error f(std::future_errc::broken_promise); - assert(f.code() == std::make_error_code(std::future_errc::broken_promise)); - } - { - std::future_error f(std::future_errc::no_state); - assert(f.code() == std::make_error_code(std::future_errc::no_state)); - } +int main(int, char**) { + ASSERT_NOEXCEPT(std::declval().code()); + ASSERT_SAME_TYPE(decltype(std::declval().code()), std::error_code const&); + + // Before C++17, we can't construct std::future_error directly in a standards-conforming way +#if TEST_STD_VER >= 17 + { + std::future_error const f(std::future_errc::broken_promise); + std::error_code const& code = f.code(); + assert(code == std::make_error_code(std::future_errc::broken_promise)); + } + { + std::future_error const f(std::future_errc::future_already_retrieved); + std::error_code const& code = f.code(); + assert(code == std::make_error_code(std::future_errc::future_already_retrieved)); + } + { + std::future_error const f(std::future_errc::promise_already_satisfied); + std::error_code const& code = f.code(); + assert(code == std::make_error_code(std::future_errc::promise_already_satisfied)); + } + { + std::future_error const f(std::future_errc::no_state); + std::error_code const& code = f.code(); + assert(code == std::make_error_code(std::future_errc::no_state)); + } #endif return 0; diff --git a/libcxx/test/std/thread/futures/futures.future_error/ctor.pass.cpp b/libcxx/test/std/thread/futures/futures.future_error/ctor.pass.cpp new file mode 100644 index 0000000000000..bce34105a5092 --- /dev/null +++ b/libcxx/test/std/thread/futures/futures.future_error/ctor.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// UNSUPPORTED: no-threads +// UNSUPPORTED: c++03, c++11, c++14 + +// + +// class future_error +// +// explicit future_error(future_errc e); // since C++17 + +#include +#include +#include + +int main(int, char**) { + { + std::future_error f(std::future_errc::broken_promise); + assert(f.code() == std::make_error_code(std::future_errc::broken_promise)); + } + { + std::future_error f(std::future_errc::future_already_retrieved); + assert(f.code() == std::make_error_code(std::future_errc::future_already_retrieved)); + } + { + std::future_error f(std::future_errc::promise_already_satisfied); + assert(f.code() == std::make_error_code(std::future_errc::promise_already_satisfied)); + } + { + std::future_error f(std::future_errc::no_state); + assert(f.code() == std::make_error_code(std::future_errc::no_state)); + } + + // Make sure the constructor is explicit + static_assert(!std::is_convertible_v); + + return 0; +} diff --git a/libcxx/test/std/thread/futures/futures.future_error/types.pass.cpp b/libcxx/test/std/thread/futures/futures.future_error/types.compile.pass.cpp similarity index 72% rename from libcxx/test/std/thread/futures/futures.future_error/types.pass.cpp rename to libcxx/test/std/thread/futures/futures.future_error/types.compile.pass.cpp index 8e77c01e73cea..478f0c2a676aa 100644 --- a/libcxx/test/std/thread/futures/futures.future_error/types.pass.cpp +++ b/libcxx/test/std/thread/futures/futures.future_error/types.compile.pass.cpp @@ -15,12 +15,4 @@ #include #include -#include "test_macros.h" - -int main(int, char**) -{ - static_assert((std::is_convertible::value), ""); - - return 0; -} +static_assert(std::is_convertible::value, ""); diff --git a/libcxx/test/std/thread/futures/futures.future_error/what.pass.cpp b/libcxx/test/std/thread/futures/futures.future_error/what.pass.cpp index 48ae35b6eb883..fba2bd80d7f89 100644 --- a/libcxx/test/std/thread/futures/futures.future_error/what.pass.cpp +++ b/libcxx/test/std/thread/futures/futures.future_error/what.pass.cpp @@ -13,39 +13,53 @@ // // XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{9|10|11}} -// +// VC Runtime's std::exception::what() method is not marked as noexcept, so +// this fails. +// UNSUPPORTED: target=x86_64-pc-windows-msvc +// +// // class future_error +// +// const char* what() const noexcept; -// const char* what() const throw(); - -#include -#include #include +#include +#include +#include #include "test_macros.h" -int main(int, char**) -{ - { - std::future_error f(std::make_error_code(std::future_errc::broken_promise)); - LIBCPP_ASSERT(std::strcmp(f.what(), "The associated promise has been destructed prior " - "to the associated state becoming ready.") == 0); - } - { - std::future_error f(std::make_error_code(std::future_errc::future_already_retrieved)); - LIBCPP_ASSERT(std::strcmp(f.what(), "The future has already been retrieved from " - "the promise or packaged_task.") == 0); - } - { - std::future_error f(std::make_error_code(std::future_errc::promise_already_satisfied)); - LIBCPP_ASSERT(std::strcmp(f.what(), "The state of the promise has already been set.") == 0); - } - { - std::future_error f(std::make_error_code(std::future_errc::no_state)); - LIBCPP_ASSERT(std::strcmp(f.what(), "Operation not permitted on an object without " - "an associated state.") == 0); - } +int main(int, char**) { + ASSERT_NOEXCEPT(std::declval().what()); + ASSERT_SAME_TYPE(decltype(std::declval().what()), char const*); + + // Before C++17, we can't construct std::future_error directly in a standards-conforming way +#if TEST_STD_VER >= 17 + { + std::future_error const f(std::future_errc::broken_promise); + char const* what = f.what(); + LIBCPP_ASSERT(what == std::string_view{"The associated promise has been destructed prior " + "to the associated state becoming ready."}); + } + { + std::future_error f(std::future_errc::future_already_retrieved); + char const* what = f.what(); + LIBCPP_ASSERT(what == std::string_view{"The future has already been retrieved from " + "the promise or packaged_task."}); + } + { + std::future_error f(std::future_errc::promise_already_satisfied); + char const* what = f.what(); + LIBCPP_ASSERT(what == std::string_view{"The state of the promise has already been set."}); + } + { + std::future_error f(std::future_errc::no_state); + char const* what = f.what(); + LIBCPP_ASSERT(what == std::string_view{"Operation not permitted on an object without " + "an associated state."}); + } +#endif return 0; } diff --git a/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp b/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp index 739278e74ddab..ab3c039497dd9 100644 --- a/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -28,25 +29,27 @@ constexpr decltype(auto) test_uses_allocator_construction_args(Args&&... args) { return std::uses_allocator_construction_args(std::forward(args)...); } -constexpr bool test() { +template