diff options
author | Amir Ayupov <aaupov@fb.com> | 2024-07-18 20:59:32 -0700 |
---|---|---|
committer | Amir Ayupov <aaupov@fb.com> | 2024-07-18 20:59:32 -0700 |
commit | 1f039a25ee9f32ddceae081125b51948013b58d9 (patch) | |
tree | 0469bddd47d51778d77629c5f16f24ab74f38a4d | |
parent | 99c26d6d379be17d4045685969654c0341b25425 (diff) | |
parent | 9b007a199d650f47072fe112b8315f3b3bebb27d (diff) | |
download | llvm-users/aaupov/spr/main.mcnfc-use-stdmap-for-addressprobesmap.zip llvm-users/aaupov/spr/main.mcnfc-use-stdmap-for-addressprobesmap.tar.gz llvm-users/aaupov/spr/main.mcnfc-use-stdmap-for-addressprobesmap.tar.bz2 |
[𝘀𝗽𝗿] changes introduced through rebaseusers/aaupov/spr/main.mcnfc-use-stdmap-for-addressprobesmap
Created using spr 1.3.4
[skip ci]
213 files changed, 5175 insertions, 1369 deletions
diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h index ea924eb..de9ba09 100644 --- a/bolt/include/bolt/Core/BinaryContext.h +++ b/bolt/include/bolt/Core/BinaryContext.h @@ -248,7 +248,7 @@ class BinaryContext { std::shared_ptr<DWARFContext> DWPContext; /// Decoded pseudo probes. - std::unique_ptr<MCPseudoProbeDecoder> PseudoProbeDecoder; + std::shared_ptr<MCPseudoProbeDecoder> PseudoProbeDecoder; /// A map of DWO Ids to CUs. using DWOIdToCUMapType = std::unordered_map<uint64_t, DWARFUnit *>; @@ -385,11 +385,9 @@ public: return PseudoProbeDecoder.get(); } - MCPseudoProbeDecoder & - setPseudoProbeDecoder(std::unique_ptr<MCPseudoProbeDecoder> Decoder) { + void setPseudoProbeDecoder(std::shared_ptr<MCPseudoProbeDecoder> Decoder) { assert(!PseudoProbeDecoder && "Cannot set pseudo probe decoder twice."); - PseudoProbeDecoder = std::move(Decoder); - return *PseudoProbeDecoder.get(); + PseudoProbeDecoder = Decoder; } /// Return BinaryFunction containing a given \p Address or nullptr if @@ -446,6 +444,9 @@ public: return nullptr; } + /// Deregister JumpTable registered at a given \p Address and delete it. + void deleteJumpTable(uint64_t Address); + unsigned getDWARFEncodingSize(unsigned Encoding) { if (Encoding == dwarf::DW_EH_PE_omit) return 0; diff --git a/bolt/include/bolt/Core/BinaryFunction.h b/bolt/include/bolt/Core/BinaryFunction.h index 4bebac3..da3fc43 100644 --- a/bolt/include/bolt/Core/BinaryFunction.h +++ b/bolt/include/bolt/Core/BinaryFunction.h @@ -416,9 +416,8 @@ private: /// different parameters by every pass. mutable uint64_t Hash{0}; - /// Function GUID assigned by the compiler to the source function. - /// If non-null, is a valid GUID in pseudo probe section. - uint64_t PseudoProbeGUID{0}; + /// Function GUID assigned externally. + uint64_t GUID{0}; /// For PLT functions it contains a symbol associated with a function /// reference. It is nullptr for non-PLT functions. @@ -2260,10 +2259,10 @@ public: /// Returns the last computed hash value of the function. size_t getHash() const { return Hash; } - /// Returns the function GUID from pseudo-probe description of the function. - uint64_t getPseudoProbeGUID() const { return PseudoProbeGUID; } + /// Returns the function GUID. + uint64_t getGUID() const { return GUID; } - void setPseudoProbeGUID(uint64_t GUID) { PseudoProbeGUID = GUID; } + void setGUID(uint64_t Id) { GUID = Id; } using OperandHashFuncTy = function_ref<typename std::string(const MCOperand &)>; diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h index c916c6f..32eda0b 100644 --- a/bolt/include/bolt/Core/MCPlusBuilder.h +++ b/bolt/include/bolt/Core/MCPlusBuilder.h @@ -58,6 +58,8 @@ enum class IndirectBranchType : char { POSSIBLE_PIC_JUMP_TABLE, /// Possibly a jump table for PIC. POSSIBLE_GOTO, /// Possibly a gcc's computed goto. POSSIBLE_FIXED_BRANCH, /// Possibly an indirect branch to a fixed location. + POSSIBLE_PIC_FIXED_BRANCH, /// Possibly an indirect jump to a fixed entry in a + /// PIC jump table. }; class MCPlusBuilder { @@ -1474,12 +1476,11 @@ public: /// will be set to the different components of the branch. \p MemLocInstr /// is the instruction that loads up the indirect function pointer. It may /// or may not be same as \p Instruction. - virtual IndirectBranchType - analyzeIndirectBranch(MCInst &Instruction, InstructionIterator Begin, - InstructionIterator End, const unsigned PtrSize, - MCInst *&MemLocInstr, unsigned &BaseRegNum, - unsigned &IndexRegNum, int64_t &DispValue, - const MCExpr *&DispExpr, MCInst *&PCRelBaseOut) const { + virtual IndirectBranchType analyzeIndirectBranch( + MCInst &Instruction, InstructionIterator Begin, InstructionIterator End, + const unsigned PtrSize, MCInst *&MemLocInstr, unsigned &BaseRegNum, + unsigned &IndexRegNum, int64_t &DispValue, const MCExpr *&DispExpr, + MCInst *&PCRelBaseOut, MCInst *&FixedEntryLoadInst) const { llvm_unreachable("not implemented"); return IndirectBranchType::UNKNOWN; } diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp index 0a1f1bb..035f68e 100644 --- a/bolt/lib/Core/BinaryContext.cpp +++ b/bolt/lib/Core/BinaryContext.cpp @@ -2523,6 +2523,16 @@ BinaryFunction *BinaryContext::getBinaryFunctionAtAddress(uint64_t Address) { return nullptr; } +/// Deregister JumpTable registered at a given \p Address and delete it. +void BinaryContext::deleteJumpTable(uint64_t Address) { + assert(JumpTables.count(Address) && "Must have a jump table at address"); + JumpTable *JT = JumpTables.at(Address); + for (BinaryFunction *Parent : JT->Parents) + Parent->JumpTables.erase(Address); + JumpTables.erase(Address); + delete JT; +} + DebugAddressRangesVector BinaryContext::translateModuleAddressRanges( const DWARFAddressRangesVector &InputRanges) const { DebugAddressRangesVector OutputRanges; diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index 282638f..ea09371 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -780,6 +780,9 @@ BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size, // setting the value of the register used by the branch. MCInst *MemLocInstr; + // The instruction loading the fixed PIC jump table entry value. + MCInst *FixedEntryLoadInstr; + // Address of the table referenced by MemLocInstr. Could be either an // array of function pointers, or a jump table. uint64_t ArrayStart = 0; @@ -811,7 +814,7 @@ BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size, IndirectBranchType BranchType = BC.MIB->analyzeIndirectBranch( Instruction, Begin, Instructions.end(), PtrSize, MemLocInstr, BaseRegNum, - IndexRegNum, DispValue, DispExpr, PCRelBaseInstr); + IndexRegNum, DispValue, DispExpr, PCRelBaseInstr, FixedEntryLoadInstr); if (BranchType == IndirectBranchType::UNKNOWN && !MemLocInstr) return BranchType; @@ -877,6 +880,43 @@ BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size, if (BaseRegNum == BC.MRI->getProgramCounter()) ArrayStart += getAddress() + Offset + Size; + if (FixedEntryLoadInstr) { + assert(BranchType == IndirectBranchType::POSSIBLE_PIC_FIXED_BRANCH && + "Invalid IndirectBranch type"); + MCInst::iterator FixedEntryDispOperand = + BC.MIB->getMemOperandDisp(*FixedEntryLoadInstr); + assert(FixedEntryDispOperand != FixedEntryLoadInstr->end() && + "Invalid memory instruction"); + const MCExpr *FixedEntryDispExpr = FixedEntryDispOperand->getExpr(); + const uint64_t EntryAddress = getExprValue(FixedEntryDispExpr); + uint64_t EntrySize = BC.getJumpTableEntrySize(JumpTable::JTT_PIC); + ErrorOr<int64_t> Value = + BC.getSignedValueAtAddress(EntryAddress, EntrySize); + if (!Value) + return IndirectBranchType::UNKNOWN; + + BC.outs() << "BOLT-INFO: fixed PIC indirect branch detected in " << *this + << " at 0x" << Twine::utohexstr(getAddress() + Offset) + << " referencing data at 0x" << Twine::utohexstr(EntryAddress) + << " the destination value is 0x" + << Twine::utohexstr(ArrayStart + *Value) << '\n'; + + TargetAddress = ArrayStart + *Value; + + // Remove spurious JumpTable at EntryAddress caused by PIC reference from + // the load instruction. + BC.deleteJumpTable(EntryAddress); + + // Replace FixedEntryDispExpr used in target address calculation with outer + // jump table reference. + JumpTable *JT = BC.getJumpTableContainingAddress(ArrayStart); + assert(JT && "Must have a containing jump table for PIC fixed branch"); + BC.MIB->replaceMemOperandDisp(*FixedEntryLoadInstr, JT->getFirstLabel(), + EntryAddress - ArrayStart, &*BC.Ctx); + + return BranchType; + } + LLVM_DEBUG(dbgs() << "BOLT-DEBUG: addressed memory is 0x" << Twine::utohexstr(ArrayStart) << '\n'); @@ -1126,6 +1166,7 @@ void BinaryFunction::handleIndirectBranch(MCInst &Instruction, uint64_t Size, } case IndirectBranchType::POSSIBLE_JUMP_TABLE: case IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE: + case IndirectBranchType::POSSIBLE_PIC_FIXED_BRANCH: if (opts::JumpTables == JTS_NONE) IsSimple = false; break; @@ -1878,9 +1919,11 @@ bool BinaryFunction::postProcessIndirectBranches( int64_t DispValue; const MCExpr *DispExpr; MCInst *PCRelBaseInstr; + MCInst *FixedEntryLoadInstr; IndirectBranchType Type = BC.MIB->analyzeIndirectBranch( Instr, BB.begin(), II, PtrSize, MemLocInstr, BaseRegNum, - IndexRegNum, DispValue, DispExpr, PCRelBaseInstr); + IndexRegNum, DispValue, DispExpr, PCRelBaseInstr, + FixedEntryLoadInstr); if (Type != IndirectBranchType::UNKNOWN || MemLocInstr != nullptr) continue; diff --git a/bolt/lib/Passes/IndirectCallPromotion.cpp b/bolt/lib/Passes/IndirectCallPromotion.cpp index a73eb86..2b5a591 100644 --- a/bolt/lib/Passes/IndirectCallPromotion.cpp +++ b/bolt/lib/Passes/IndirectCallPromotion.cpp @@ -386,13 +386,15 @@ IndirectCallPromotion::maybeGetHotJumpTableTargets(BinaryBasicBlock &BB, JumpTableInfoType HotTargets; MCInst *MemLocInstr; MCInst *PCRelBaseOut; + MCInst *FixedEntryLoadInstr; unsigned BaseReg, IndexReg; int64_t DispValue; const MCExpr *DispExpr; MutableArrayRef<MCInst> Insts(&BB.front(), &CallInst); const IndirectBranchType Type = BC.MIB->analyzeIndirectBranch( CallInst, Insts.begin(), Insts.end(), BC.AsmInfo->getCodePointerSize(), - MemLocInstr, BaseReg, IndexReg, DispValue, DispExpr, PCRelBaseOut); + MemLocInstr, BaseReg, IndexReg, DispValue, DispExpr, PCRelBaseOut, + FixedEntryLoadInstr); assert(MemLocInstr && "There should always be a load for jump tables"); if (!MemLocInstr) diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp index beb03a9..fd0a526 100644 --- a/bolt/lib/Profile/DataAggregator.cpp +++ b/bolt/lib/Profile/DataAggregator.cpp @@ -2401,7 +2401,7 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC, YamlBF.Blocks[BlockIndex].ExecCount += BI.Branches; } if (PseudoProbeDecoder) { - if ((YamlBF.GUID = BF->getPseudoProbeGUID())) { + if ((YamlBF.GUID = BF->getGUID())) { const MCPseudoProbeFuncDesc *FuncDesc = PseudoProbeDecoder->getFuncDescForGUID(YamlBF.GUID); YamlBF.PseudoProbeDescHash = FuncDesc->FuncHash; diff --git a/bolt/lib/Profile/YAMLProfileWriter.cpp b/bolt/lib/Profile/YAMLProfileWriter.cpp index 38345da..82d70e5 100644 --- a/bolt/lib/Profile/YAMLProfileWriter.cpp +++ b/bolt/lib/Profile/YAMLProfileWriter.cpp @@ -71,7 +71,7 @@ YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS, YamlBF.NumBasicBlocks = BF.size(); YamlBF.ExecCount = BF.getKnownExecutionCount(); if (PseudoProbeDecoder) { - if ((YamlBF.GUID = BF.getPseudoProbeGUID())) { + if ((YamlBF.GUID = BF.getGUID())) { const MCPseudoProbeFuncDesc *FuncDesc = PseudoProbeDecoder->getFuncDescForGUID(YamlBF.GUID); YamlBF.PseudoProbeDescHash = FuncDesc->FuncHash; diff --git a/bolt/lib/Rewrite/PseudoProbeRewriter.cpp b/bolt/lib/Rewrite/PseudoProbeRewriter.cpp index 9249861b..3704a9b 100644 --- a/bolt/lib/Rewrite/PseudoProbeRewriter.cpp +++ b/bolt/lib/Rewrite/PseudoProbeRewriter.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/LEB128.h" +#include <memory> #undef DEBUG_TYPE #define DEBUG_TYPE "pseudo-probe-rewriter" @@ -72,16 +73,19 @@ class PseudoProbeRewriter final : public MetadataRewriter { void parsePseudoProbe(); /// PseudoProbe decoder - MCPseudoProbeDecoder &ProbeDecoder; + std::shared_ptr<MCPseudoProbeDecoder> ProbeDecoderPtr; public: PseudoProbeRewriter(BinaryContext &BC) : MetadataRewriter("pseudo-probe-rewriter", BC), - ProbeDecoder(BC.setPseudoProbeDecoder( - std::make_unique<MCPseudoProbeDecoder>())) {} + ProbeDecoderPtr(std::make_shared<MCPseudoProbeDecoder>()) { + BC.setPseudoProbeDecoder(ProbeDecoderPtr); + } Error preCFGInitializer() override; Error postEmitFinalizer() override; + + ~PseudoProbeRewriter() override { ProbeDecoderPtr.reset(); } }; Error PseudoProbeRewriter::preCFGInitializer() { @@ -97,6 +101,7 @@ Error PseudoProbeRewriter::postEmitFinalizer() { } void PseudoProbeRewriter::parsePseudoProbe() { + MCPseudoProbeDecoder &ProbeDecoder(*ProbeDecoderPtr); PseudoProbeDescSection = BC.getUniqueSectionByName(".pseudo_probe_desc"); PseudoProbeSection = BC.getUniqueSectionByName(".pseudo_probe"); @@ -152,11 +157,12 @@ void PseudoProbeRewriter::parsePseudoProbe() { continue; BinaryFunction *BF = BC.getBinaryFunctionAtAddress(FuncStartAddrs[GUID]); assert(BF); - BF->setPseudoProbeGUID(GUID); + BF->setGUID(GUID); } } void PseudoProbeRewriter::updatePseudoProbes() { + MCPseudoProbeDecoder &ProbeDecoder(*ProbeDecoderPtr); // check if there is pseudo probe section decoded if (ProbeDecoder.getAddress2ProbesMap().empty()) return; @@ -257,6 +263,7 @@ void PseudoProbeRewriter::updatePseudoProbes() { } void PseudoProbeRewriter::encodePseudoProbes() { + MCPseudoProbeDecoder &ProbeDecoder(*ProbeDecoderPtr); // Buffer for new pseudo probes section SmallString<8> Contents; MCDecodedPseudoProbe *LastProbe = nullptr; diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp index 1a2327d..f58f785 100644 --- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp +++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp @@ -852,16 +852,19 @@ public: return Uses; } - IndirectBranchType analyzeIndirectBranch( - MCInst &Instruction, InstructionIterator Begin, InstructionIterator End, - const unsigned PtrSize, MCInst *&MemLocInstrOut, unsigned &BaseRegNumOut, - unsigned &IndexRegNumOut, int64_t &DispValueOut, - const MCExpr *&DispExprOut, MCInst *&PCRelBaseOut) const override { + IndirectBranchType + analyzeIndirectBranch(MCInst &Instruction, InstructionIterator Begin, + InstructionIterator End, const unsigned PtrSize, + MCInst *&MemLocInstrOut, unsigned &BaseRegNumOut, + unsigned &IndexRegNumOut, int64_t &DispValueOut, + const MCExpr *&DispExprOut, MCInst *&PCRelBaseOut, + MCInst *&FixedEntryLoadInstr) const override { MemLocInstrOut = nullptr; BaseRegNumOut = AArch64::NoRegister; IndexRegNumOut = AArch64::NoRegister; DispValueOut = 0; DispExprOut = nullptr; + FixedEntryLoadInstr = nullptr; // An instruction referencing memory used by jump instruction (directly or // via register). This location could be an array of function pointers diff --git a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp index eb3f38a..f8c83b0 100644 --- a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp +++ b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp @@ -176,13 +176,14 @@ public: MCInst &Instruction, InstructionIterator Begin, InstructionIterator End, const unsigned PtrSize, MCInst *&MemLocInstr, unsigned &BaseRegNum, unsigned &IndexRegNum, int64_t &DispValue, const MCExpr *&DispExpr, - MCInst *&PCRelBaseOut) const override { + MCInst *&PCRelBaseOut, MCInst *&FixedEntryLoadInst) const override { MemLocInstr = nullptr; BaseRegNum = 0; IndexRegNum = 0; DispValue = 0; DispExpr = nullptr; PCRelBaseOut = nullptr; + FixedEntryLoadInst = nullptr; // Check for the following long tail call sequence: // 1: auipc xi, %pcrel_hi(sym) diff --git a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp index e46c425..63086c06 100644 --- a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp +++ b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp @@ -1866,8 +1866,11 @@ public: return true; } + /// Analyzes PIC-style jump table code template and return identified + /// IndirectBranchType, MemLocInstr (all cases) and FixedEntryLoadInstr + /// (POSSIBLE_PIC_FIXED_BRANCH case). template <typename Itr> - std::pair<IndirectBranchType, MCInst *> + std::tuple<IndirectBranchType, MCInst *, MCInst *> analyzePICJumpTable(Itr II, Itr IE, MCPhysReg R1, MCPhysReg R2) const { // Analyze PIC-style jump table code template: // @@ -1876,6 +1879,13 @@ public: // add %r2, %r1 // jmp *%r1 // + // or a fixed indirect jump template: + // + // movslq En(%rip), {%r2|%r1} <- FixedEntryLoadInstr + // lea PIC_JUMP_TABLE(%rip), {%r1|%r2} <- MemLocInstr + // add %r2, %r1 + // jmp *%r1 + // // (with any irrelevant instructions in-between) // // When we call this helper we've already determined %r1 and %r2, and @@ -1916,8 +1926,13 @@ public: MO.SegRegNum == X86::NoRegister; }; LLVM_DEBUG(dbgs() << "Checking for PIC jump table\n"); - MCInst *MemLocInstr = nullptr; - const MCInst *MovInstr = nullptr; + MCInst *FirstInstr = nullptr; + MCInst *SecondInstr = nullptr; + enum { + NOMATCH = 0, + MATCH_JUMP_TABLE, + MATCH_FIXED_BRANCH, + } MatchingState = NOMATCH; while (++II != IE) { MCInst &Instr = *II; const MCInstrDesc &InstrDesc = Info->get(Instr.getOpcode()); @@ -1926,68 +1941,76 @@ public: // Ignore instructions that don't affect R1, R2 registers. continue; } - if (!MovInstr) { - // Expect to see MOV instruction. - if (!isMOVSX64rm32(Instr)) { - LLVM_DEBUG(dbgs() << "MOV instruction expected.\n"); + const bool IsMOVSXInstr = isMOVSX64rm32(Instr); + const bool IsLEAInstr = isLEA64r(Instr); + if (MatchingState == NOMATCH) { + if (IsMOVSXInstr) + MatchingState = MATCH_JUMP_TABLE; + else if (IsLEAInstr) + MatchingState = MATCH_FIXED_BRANCH; + else break; - } - // Check if it's setting %r1 or %r2. In canonical form it sets %r2. - // If it sets %r1 - rename the registers so we have to only check - // a single form. - unsigned MovDestReg = Instr.getOperand(0).getReg(); - if (MovDestReg != R2) + // Check if the first instruction is setting %r1 or %r2. In canonical + // form lea sets %r1 and mov sets %r2. If it's the opposite - rename so + // we have to only check a single form. + unsigned DestReg = Instr.getOperand(0).getReg(); + MCPhysReg &ExpectReg = MatchingState == MATCH_JUMP_TABLE ? R2 : R1; + if (DestReg != ExpectReg) std::swap(R1, R2); - if (MovDestReg != R2) { - LLVM_DEBUG(dbgs() << "MOV instruction expected to set %r2\n"); + if (DestReg != ExpectReg) break; - } - // Verify operands for MOV. + // Verify operands std::optional<X86MemOperand> MO = evaluateX86MemoryOperand(Instr); if (!MO) break; - if (!isIndexed(*MO, R1)) - // POSSIBLE_PIC_JUMP_TABLE + if ((MatchingState == MATCH_JUMP_TABLE && isIndexed(*MO, R1)) || + (MatchingState == MATCH_FIXED_BRANCH && isRIPRel(*MO))) + FirstInstr = &Instr; + else break; - MovInstr = &Instr; } else { - if (!InstrDesc.hasDefOfPhysReg(Instr, R1, *RegInfo)) + unsigned ExpectReg = MatchingState == MATCH_JUMP_TABLE ? R1 : R2; + if (!InstrDesc.hasDefOfPhysReg(Instr, ExpectReg, *RegInfo)) continue; - if (!isLEA64r(Instr)) { - LLVM_DEBUG(dbgs() << "LEA instruction expected\n"); + if ((MatchingState == MATCH_JUMP_TABLE && !IsLEAInstr) || + (MatchingState == MATCH_FIXED_BRANCH && !IsMOVSXInstr)) break; - } - if (Instr.getOperand(0).getReg() != R1) { - LLVM_DEBUG(dbgs() << "LEA instruction expected to set %r1\n"); + if (Instr.getOperand(0).getReg() != ExpectReg) break; - } - // Verify operands for LEA. + // Verify operands. std::optional<X86MemOperand> MO = evaluateX86MemoryOperand(Instr); if (!MO) break; if (!isRIPRel(*MO)) break; - MemLocInstr = &Instr; + SecondInstr = &Instr; break; } } - if (!MemLocInstr) - return std::make_pair(IndirectBranchType::UNKNOWN, nullptr); + if (!SecondInstr) + return std::make_tuple(IndirectBranchType::UNKNOWN, nullptr, nullptr); + if (MatchingState == MATCH_FIXED_BRANCH) { + LLVM_DEBUG(dbgs() << "checking potential fixed indirect branch\n"); + return std::make_tuple(IndirectBranchType::POSSIBLE_PIC_FIXED_BRANCH, + FirstInstr, SecondInstr); + } LLVM_DEBUG(dbgs() << "checking potential PIC jump table\n"); - return std::make_pair(IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE, - MemLocInstr); + return std::make_tuple(IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE, + SecondInstr, nullptr); } - IndirectBranchType analyzeIndirectBranch( - MCInst &Instruction, InstructionIterator Begin, InstructionIterator End, - const unsigned PtrSize, MCInst *&MemLocInstrOut, unsigned &BaseRegNumOut, - unsigned &IndexRegNumOut, int64_t &DispValueOut, - const MCExpr *&DispExprOut, MCInst *&PCRelBaseOut) const override { + IndirectBranchType + analyzeIndirectBranch(MCInst &Instruction, InstructionIterator Begin, + InstructionIterator End, const unsigned PtrSize, + MCInst *&MemLocInstrOut, unsigned &BaseRegNumOut, + unsigned &IndexRegNumOut, int64_t &DispValueOut, + const MCExpr *&DispExprOut, MCInst *&PCRelBaseOut, + MCInst *&FixedEntryLoadInst) const override { // Try to find a (base) memory location from where the address for // the indirect branch is loaded. For X86-64 the memory will be specified // in the following format: @@ -2014,6 +2037,7 @@ public: IndexRegNumOut = X86::NoRegister; DispValueOut = 0; DispExprOut = nullptr; + FixedEntryLoadInst = nullptr; std::reverse_iterator<InstructionIterator> II(End); std::reverse_iterator<InstructionIterator> IE(Begin); @@ -2046,7 +2070,8 @@ public: unsigned R2 = PrevInstr.getOperand(2).getReg(); if (R1 == R2) return IndirectBranchType::UNKNOWN; - std::tie(Type, MemLocInstr) = analyzePICJumpTable(PrevII, IE, R1, R2); + std::tie(Type, MemLocInstr, FixedEntryLoadInst) = + analyzePICJumpTable(PrevII, IE, R1, R2); break; } return IndirectBranchType::UNKNOWN; @@ -2090,6 +2115,8 @@ public: if (MO->ScaleImm != 1 || MO->BaseRegNum != RIPRegister) return IndirectBranchType::UNKNOWN; break; + case IndirectBranchType::POSSIBLE_PIC_FIXED_BRANCH: + break; default: if (MO->ScaleImm != PtrSize) return IndirectBranchType::UNKNOWN; diff --git a/bolt/test/X86/Inputs/jump-table-fixed-ref-pic.s b/bolt/test/X86/Inputs/jump-table-fixed-ref-pic.s index 66629a4..6407964 100644 --- a/bolt/test/X86/Inputs/jump-table-fixed-ref-pic.s +++ b/bolt/test/X86/Inputs/jump-table-fixed-ref-pic.s @@ -6,7 +6,7 @@ main: jae .L4 cmpq $0x1, %rdi jne .L4 - mov .Ljt_pic+8(%rip), %rax + movslq .Ljt_pic+8(%rip), %rax lea .Ljt_pic(%rip), %rdx add %rdx, %rax jmpq *%rax diff --git a/bolt/test/X86/jump-table-fixed-ref-pic.test b/bolt/test/X86/jump-table-fixed-ref-pic.test index c8b6eda..d215c56 100644 --- a/bolt/test/X86/jump-table-fixed-ref-pic.test +++ b/bolt/test/X86/jump-table-fixed-ref-pic.test @@ -1,9 +1,13 @@ ## Verify that BOLT detects fixed destination of indirect jump for PIC ## case. -XFAIL: * - RUN: %clang %cflags -no-pie %S/Inputs/jump-table-fixed-ref-pic.s -Wl,-q -o %t -RUN: llvm-bolt %t --relocs -o %t.null 2>&1 | FileCheck %s +RUN: llvm-bolt %t --relocs -o %t.null -print-cfg 2>&1 | FileCheck %s + +CHECK: BOLT-INFO: fixed PIC indirect branch detected in main {{.*}} the destination value is 0x[[#TGT:]] +CHECK: Binary Function "main" after building cfg -CHECK: BOLT-INFO: fixed indirect branch detected in main +CHECK: movslq ".rodata/1"+8(%rip), %rax +CHECK-NEXT: leaq ".rodata/1"(%rip), %rdx +CHECK-NEXT: addq %rdx, %rax +CHECK-NEXT: jmpq *%rax # UNKNOWN CONTROL FLOW diff --git a/clang/include/clang/Basic/BuiltinsAMDGPU.def b/clang/include/clang/Basic/BuiltinsAMDGPU.def index e62315e..ab29ef3 100644 --- a/clang/include/clang/Basic/BuiltinsAMDGPU.def +++ b/clang/include/clang/Basic/BuiltinsAMDGPU.def @@ -149,12 +149,18 @@ BUILTIN(__builtin_amdgcn_mqsad_pk_u16_u8, "WUiWUiUiWUi", "nc") BUILTIN(__builtin_amdgcn_mqsad_u32_u8, "V4UiWUiUiV4Ui", "nc") BUILTIN(__builtin_amdgcn_make_buffer_rsrc, "Qbv*sii", "nc") -BUILTIN(__builtin_amdgcn_raw_buffer_store_b8, "vcQbiiIi", "n") -BUILTIN(__builtin_amdgcn_raw_buffer_store_b16, "vsQbiiIi", "n") -BUILTIN(__builtin_amdgcn_raw_buffer_store_b32, "viQbiiIi", "n") -BUILTIN(__builtin_amdgcn_raw_buffer_store_b64, "vV2iQbiiIi", "n") -BUILTIN(__builtin_amdgcn_raw_buffer_store_b96, "vV3iQbiiIi", "n") -BUILTIN(__builtin_amdgcn_raw_buffer_store_b128, "vV4iQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_store_b8, "vUcQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_store_b16, "vUsQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_store_b32, "vUiQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_store_b64, "vV2UiQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_store_b96, "vV3UiQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_store_b128, "vV4UiQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_load_b8, "UcQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_load_b16, "UsQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_load_b32, "UiQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_load_b64, "V2UiQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_load_b96, "V3UiQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_load_b128, "V4UiQbiiIi", "n") //===----------------------------------------------------------------------===// // Ballot builtins. diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index cfa897f..26a9792 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -156,6 +156,8 @@ def err_drv_unsupported_rtlib_for_platform : Error< "unsupported runtime library '%0' for platform '%1'">; def err_drv_invalid_unwindlib_name : Error< "invalid unwind library name in argument '%0'">; +def err_drv_unsupported_unwind_for_platform : Error< + "unsupported unwind library '%0' for platform '%1'">; def err_drv_incompatible_unwindlib : Error< "--rtlib=libgcc requires --unwindlib=libgcc">; def err_drv_incompatible_options : Error< diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 2ad62d6..2d32a85 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -688,7 +688,34 @@ static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *FD, const CallExpr *E, llvm::Constant *calleeValue) { CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E); CGCallee callee = CGCallee::forDirect(calleeValue, GlobalDecl(FD)); - return CGF.EmitCall(E->getCallee()->getType(), callee, E, ReturnValueSlot()); + RValue Call = + CGF.EmitCall(E->getCallee()->getType(), callee, E, ReturnValueSlot()); + + // Check the supported intrinsic. + if (unsigned BuiltinID = FD->getBuiltinID()) { + auto IsErrnoIntrinsic = [&]() -> unsigned { + switch (BuiltinID) { + case Builtin::BIexpf: + case Builtin::BI__builtin_expf: + case Builtin::BI__builtin_expf128: + return true; + } + // TODO: support more FP math libcalls + return false; + }(); + + // Restrict to target with errno, for example, MacOS doesn't set errno. + if (IsErrnoIntrinsic && CGF.CGM.getLangOpts().MathErrno && + !CGF.Builder.getIsFPConstrained()) { + ASTContext &Context = CGF.getContext(); + // Emit "int" TBAA metadata on FP math libcalls. + clang::QualType IntTy = Context.IntTy; + TBAAAccessInfo TBAAInfo = CGF.CGM.getTBAAAccessInfo(IntTy); + Instruction *Inst = cast<llvm::Instruction>(Call.getScalarVal()); + CGF.CGM.DecorateInstructionWithTBAA(Inst, TBAAInfo); + } + } + return Call; } /// Emit a call to llvm.{sadd,uadd,ssub,usub,smul,umul}.with.overflow.* @@ -19185,6 +19212,39 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, case AMDGPU::BI__builtin_amdgcn_raw_buffer_store_b128: return emitBuiltinWithOneOverloadedType<5>( *this, E, Intrinsic::amdgcn_raw_ptr_buffer_store); + case AMDGPU::BI__builtin_amdgcn_raw_buffer_load_b8: + case AMDGPU::BI__builtin_amdgcn_raw_buffer_load_b16: + case AMDGPU::BI__builtin_amdgcn_raw_buffer_load_b32: + case AMDGPU::BI__builtin_amdgcn_raw_buffer_load_b64: + case AMDGPU::BI__builtin_amdgcn_raw_buffer_load_b96: + case AMDGPU::BI__builtin_amdgcn_raw_buffer_load_b128: { + llvm::Type *RetTy = nullptr; + switch (BuiltinID) { + case AMDGPU::BI__builtin_amdgcn_raw_buffer_load_b8: + RetTy = Int8Ty; + break; + case AMDGPU::BI__builtin_amdgcn_raw_buffer_load_b16: + RetTy = Int16Ty; + break; + case AMDGPU::BI__builtin_amdgcn_raw_buffer_load_b32: + RetTy = Int32Ty; + break; + case AMDGPU::BI__builtin_amdgcn_raw_buffer_load_b64: + RetTy = llvm::FixedVectorType::get(Int32Ty, /*NumElements=*/2); + break; + case AMDGPU::BI__builtin_amdgcn_raw_buffer_load_b96: + RetTy = llvm::FixedVectorType::get(Int32Ty, /*NumElements=*/3); + break; + case AMDGPU::BI__builtin_amdgcn_raw_buffer_load_b128: + RetTy = llvm::FixedVectorType::get(Int32Ty, /*NumElements=*/4); + break; + } + Function *F = + CGM.getIntrinsic(Intrinsic::amdgcn_raw_ptr_buffer_load, RetTy); + return Builder.CreateCall( + F, {EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)), + EmitScalarExpr(E->getArg(2)), EmitScalarExpr(E->getArg(3))}); + } default: return nullptr; } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 6a0af00..c5341e4 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1071,21 +1071,20 @@ using RecIndicesTy = SmallVector<std::pair<const RecordDecl *, llvm::Value *>, 8>; static bool getGEPIndicesToField(CodeGenFunction &CGF, const RecordDecl *RD, - const FieldDecl *FD, RecIndicesTy &Indices) { + const FieldDecl *Field, + RecIndicesTy &Indices) { const CGRecordLayout &Layout = CGF.CGM.getTypes().getCGRecordLayout(RD); int64_t FieldNo = -1; - for (const Decl *D : RD->decls()) { - if (const auto *Field = dyn_cast<FieldDecl>(D)) { - FieldNo = Layout.getLLVMFieldNo(Field); - if (FD == Field) { - Indices.emplace_back(std::make_pair(RD, CGF.Builder.getInt32(FieldNo))); - return true; - } + for (const FieldDecl *FD : RD->fields()) { + FieldNo = Layout.getLLVMFieldNo(FD); + if (FD == Field) { + Indices.emplace_back(std::make_pair(RD, CGF.Builder.getInt32(FieldNo))); + return true; } - if (const auto *Record = dyn_cast<RecordDecl>(D)) { - ++FieldNo; - if (getGEPIndicesToField(CGF, Record, FD, Indices)) { + QualType Ty = FD->getType(); + if (Ty->isRecordType()) { + if (getGEPIndicesToField(CGF, Ty->getAsRecordDecl(), Field, Indices)) { if (RD->isUnion()) FieldNo = 0; Indices.emplace_back(std::make_pair(RD, CGF.Builder.getInt32(FieldNo))); diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp index 12b3b99..2978139 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -366,11 +366,14 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, options::OPT_t, options::OPT_u_Group}); AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); + ToolChain::UnwindLibType UNW = HTC.GetUnwindLibType(Args); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (NeedsSanitizerDeps) { linkSanitizerRuntimeDeps(HTC, Args, CmdArgs); - CmdArgs.push_back("-lunwind"); + if (UNW != ToolChain::UNW_None) + CmdArgs.push_back("-lunwind"); } if (NeedsXRayDeps) linkXRayRuntimeDeps(HTC, Args, CmdArgs); @@ -618,13 +621,24 @@ HexagonToolChain::~HexagonToolChain() {} void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CXXStdlibType Type = GetCXXStdlibType(Args); + ToolChain::UnwindLibType UNW = GetUnwindLibType(Args); + if (UNW != ToolChain::UNW_None && UNW != ToolChain::UNW_CompilerRT) { + const Arg *A = Args.getLastArg(options::OPT_unwindlib_EQ); + if (A) { + getDriver().Diag(diag::err_drv_unsupported_unwind_for_platform) + << A->getValue() << getTriple().normalize(); + return; + } + } + switch (Type) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); if (Args.hasArg(options::OPT_fexperimental_library)) CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); - CmdArgs.push_back("-lunwind"); + if (UNW != ToolChain::UNW_None) + CmdArgs.push_back("-lunwind"); break; case ToolChain::CST_Libstdcxx: diff --git a/clang/lib/Lex/DependencyDirectivesScanner.cpp b/clang/lib/Lex/DependencyDirectivesScanner.cpp index 57652be..8a020d0 100644 --- a/clang/lib/Lex/DependencyDirectivesScanner.cpp +++ b/clang/lib/Lex/DependencyDirectivesScanner.cpp @@ -660,7 +660,18 @@ bool Scanner::lexModule(const char *&First, const char *const End) { // an import. switch (*First) { - case ':': + case ':': { + // `module :` is never the start of a valid module declaration. + if (Id == "module") { + skipLine(First, End); + return false; + } + // `import:(type)name` is a valid ObjC method decl, so check one more token. + (void)lexToken(First, End); + if (!tryLexIdentifierOrSkipLine(First, End)) + return false; + break; + } case '<': case '"': break; diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index 79922eb..32db136 100644 --- a/clang/test/CodeGen/attr-counted-by.c +++ b/clang/test/CodeGen/attr-counted-by.c @@ -1852,3 +1852,57 @@ struct annotated_struct_array { void test29(struct annotated_struct_array *ann, int idx1, int idx2) { ann->ann_array[idx1]->array[idx2] = __builtin_dynamic_object_size(ann->ann_array[idx1]->array, 1); } + +typedef struct { + char __padding[0]; +} test30_spinlock_t; + +struct test30_struct { + struct test30_decl *name_node; + int priv_len; + test30_spinlock_t pcpu_refcnt; + char priv[] __counted_by(priv_len); +}; + +// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test30( +// SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR5]] { +// SANITIZE-WITH-ATTR-NEXT: entry: +// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[IDX]] to i64, !nosanitize [[META2]] +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB39:[0-9]+]], i64 [[TMP0]]) #[[ATTR10]], !nosanitize [[META2]] +// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]] +// +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test30( +// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// NO-SANITIZE-WITH-ATTR-NEXT: entry: +// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 8 +// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 4) +// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i8 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = add i8 [[TMP1]], 12 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i8 0, i8 [[TMP2]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[PCPU_REFCNT:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 12 +// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[PCPU_REFCNT]], i64 0, i64 [[IDXPROM]] +// NO-SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]] +// NO-SANITIZE-WITH-ATTR-NEXT: ret void +// +// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test30( +// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] { +// SANITIZE-WITHOUT-ATTR-NEXT: entry: +// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[IDX]] to i64, !nosanitize [[META9]] +// SANITIZE-WITHOUT-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB15:[0-9]+]], i64 [[TMP0]]) #[[ATTR8]], !nosanitize [[META9]] +// SANITIZE-WITHOUT-ATTR-NEXT: unreachable, !nosanitize [[META9]] +// +// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test30( +// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry: +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[PCPU_REFCNT:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 12 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[PCPU_REFCNT]], i64 0, i64 [[IDXPROM]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +void test30(struct test30_struct *ptr, int idx) { + ptr->pcpu_refcnt.__padding[idx] = __builtin_dynamic_object_size(ptr, 1); +} diff --git a/clang/test/CodeGen/math-libcalls-tbaa.cpp b/clang/test/CodeGen/math-libcalls-tbaa.cpp index 0b231d4..f15938d 100644 --- a/clang/test/CodeGen/math-libcalls-tbaa.cpp +++ b/clang/test/CodeGen/math-libcalls-tbaa.cpp @@ -12,9 +12,8 @@ extern "C" float expf(float); // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 40 // CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2:![0-9]+]] -// CHECK-NEXT: [[CALL:%.*]] = tail call float @expf(float noundef [[TMP0]]) #[[ATTR2:[0-9]+]] -// CHECK-NEXT: [[TMP1:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] -// CHECK-NEXT: [[MUL:%.*]] = fmul float [[CALL]], [[TMP1]] +// CHECK-NEXT: [[CALL:%.*]] = tail call float @expf(float noundef [[TMP0]]) #[[ATTR2:[0-9]+]], !tbaa [[TBAA6:![0-9]+]] +// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP0]], [[CALL]] // CHECK-NEXT: ret float [[MUL]] // extern "C" float foo (float num[], float r2inv, int n) { @@ -27,11 +26,15 @@ extern "C" float foo (float num[], float r2inv, int n) { // NoNewStructPathTBAA: [[META3]] = !{!"float", [[META4:![0-9]+]], i64 0} // NoNewStructPathTBAA: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0} // NoNewStructPathTBAA: [[META5]] = !{!"Simple C++ TBAA"} +// NoNewStructPathTBAA: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0} +// NoNewStructPathTBAA: [[META7]] = !{!"int", [[META4]], i64 0} //. // NewStructPathTBAA: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0, i64 4} // NewStructPathTBAA: [[META3]] = !{[[META4:![0-9]+]], i64 4, !"float"} // NewStructPathTBAA: [[META4]] = !{[[META5:![0-9]+]], i64 1, !"omnipotent char"} // NewStructPathTBAA: [[META5]] = !{!"Simple C++ TBAA"} +// NewStructPathTBAA: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0, i64 4} +// NewStructPathTBAA: [[META7]] = !{[[META4]], i64 4, !"int"} //. //// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: // NewStructPathTBAA: {{.*}} diff --git a/clang/test/CodeGenOpenCL/builtins-amdgcn-raw-buffer-load.cl b/clang/test/CodeGenOpenCL/builtins-amdgcn-raw-buffer-load.cl new file mode 100644 index 0000000..3403b69 --- /dev/null +++ b/clang/test/CodeGenOpenCL/builtins-amdgcn-raw-buffer-load.cl @@ -0,0 +1,172 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// REQUIRES: amdgpu-registered-target +// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -target-cpu verde -emit-llvm -o - %s | FileCheck %s + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned int v2u32 __attribute__((ext_vector_type(2))); +typedef unsigned int v3u32 __attribute__((ext_vector_type(3))); +typedef unsigned int v4u32 __attribute__((ext_vector_type(4))); + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call i8 @llvm.amdgcn.raw.ptr.buffer.load.i8(ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) +// CHECK-NEXT: ret i8 [[TMP0]] +// +u8 test_amdgcn_raw_ptr_buffer_load_b8(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b8(rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.amdgcn.raw.ptr.buffer.load.i16(ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) +// CHECK-NEXT: ret i16 [[TMP0]] +// +u16 test_amdgcn_raw_ptr_buffer_load_b16(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b16(rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) +// CHECK-NEXT: ret i32 [[TMP0]] +// +u32 test_amdgcn_raw_ptr_buffer_load_b32(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b32(rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <2 x i32> @llvm.amdgcn.raw.ptr.buffer.load.v2i32(ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) +// CHECK-NEXT: ret <2 x i32> [[TMP0]] +// +v2u32 test_amdgcn_raw_ptr_buffer_load_b64(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b64(rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b96( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <3 x i32> @llvm.amdgcn.raw.ptr.buffer.load.v3i32(ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) +// CHECK-NEXT: ret <3 x i32> [[TMP0]] +// +v3u32 test_amdgcn_raw_ptr_buffer_load_b96(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b96(rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b128( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <4 x i32> @llvm.amdgcn.raw.ptr.buffer.load.v4i32(ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) +// CHECK-NEXT: ret <4 x i32> [[TMP0]] +// +v4u32 test_amdgcn_raw_ptr_buffer_load_b128(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b128(rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b8_non_const_offset( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call i8 @llvm.amdgcn.raw.ptr.buffer.load.i8(ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) +// CHECK-NEXT: ret i8 [[TMP0]] +// +u8 test_amdgcn_raw_ptr_buffer_load_b8_non_const_offset(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b8(rsrc, offset, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b16_non_const_offset( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.amdgcn.raw.ptr.buffer.load.i16(ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) +// CHECK-NEXT: ret i16 [[TMP0]] +// +u16 test_amdgcn_raw_ptr_buffer_load_b16_non_const_offset(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b16(rsrc, offset, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b32_non_const_offset( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) +// CHECK-NEXT: ret i32 [[TMP0]] +// +u32 test_amdgcn_raw_ptr_buffer_load_b32_non_const_offset(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b32(rsrc, offset, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b64_non_const_offset( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <2 x i32> @llvm.amdgcn.raw.ptr.buffer.load.v2i32(ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) +// CHECK-NEXT: ret <2 x i32> [[TMP0]] +// +v2u32 test_amdgcn_raw_ptr_buffer_load_b64_non_const_offset(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b64(rsrc, offset, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b96_non_const_offset( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <3 x i32> @llvm.amdgcn.raw.ptr.buffer.load.v3i32(ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) +// CHECK-NEXT: ret <3 x i32> [[TMP0]] +// +v3u32 test_amdgcn_raw_ptr_buffer_load_b96_non_const_offset(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b96(rsrc, offset, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b128_non_const_offset( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <4 x i32> @llvm.amdgcn.raw.ptr.buffer.load.v4i32(ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) +// CHECK-NEXT: ret <4 x i32> [[TMP0]] +// +v4u32 test_amdgcn_raw_ptr_buffer_load_b128_non_const_offset(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b128(rsrc, offset, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b8_non_const_soffset( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call i8 @llvm.amdgcn.raw.ptr.buffer.load.i8(ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) +// CHECK-NEXT: ret i8 [[TMP0]] +// +u8 test_amdgcn_raw_ptr_buffer_load_b8_non_const_soffset(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b8(rsrc, /*offset=*/0, soffset, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b16_non_const_soffset( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.amdgcn.raw.ptr.buffer.load.i16(ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) +// CHECK-NEXT: ret i16 [[TMP0]] +// +u16 test_amdgcn_raw_ptr_buffer_load_b16_non_const_soffset(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b16(rsrc, /*offset=*/0, soffset, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b32_non_const_soffset( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) +// CHECK-NEXT: ret i32 [[TMP0]] +// +u32 test_amdgcn_raw_ptr_buffer_load_b32_non_const_soffset(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b32(rsrc, /*offset=*/0, soffset, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b64_non_const_soffset( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <2 x i32> @llvm.amdgcn.raw.ptr.buffer.load.v2i32(ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) +// CHECK-NEXT: ret <2 x i32> [[TMP0]] +// +v2u32 test_amdgcn_raw_ptr_buffer_load_b64_non_const_soffset(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b64(rsrc, /*offset=*/0, soffset, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b96_non_const_soffset( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <3 x i32> @llvm.amdgcn.raw.ptr.buffer.load.v3i32(ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) +// CHECK-NEXT: ret <3 x i32> [[TMP0]] +// +v3u32 test_amdgcn_raw_ptr_buffer_load_b96_non_const_soffset(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b96(rsrc, /*offset=*/0, soffset, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_load_b128_non_const_soffset( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <4 x i32> @llvm.amdgcn.raw.ptr.buffer.load.v4i32(ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) +// CHECK-NEXT: ret <4 x i32> [[TMP0]] +// +v4u32 test_amdgcn_raw_ptr_buffer_load_b128_non_const_soffset(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + return __builtin_amdgcn_raw_buffer_load_b128(rsrc, /*offset=*/0, soffset, /*aux=*/0); +} diff --git a/clang/test/CodeGenOpenCL/builtins-amdgcn-raw-buffer-store.cl b/clang/test/CodeGenOpenCL/builtins-amdgcn-raw-buffer-store.cl index 37975d5..097c545 100644 --- a/clang/test/CodeGenOpenCL/builtins-amdgcn-raw-buffer-store.cl +++ b/clang/test/CodeGenOpenCL/builtins-amdgcn-raw-buffer-store.cl @@ -2,19 +2,19 @@ // REQUIRES: amdgpu-registered-target // RUN: %clang_cc1 -triple amdgcn-unknown-unknown -target-cpu verde -emit-llvm -o - %s | FileCheck %s -typedef char i8; -typedef short i16; -typedef int i32; -typedef int i64 __attribute__((ext_vector_type(2))); -typedef int i96 __attribute__((ext_vector_type(3))); -typedef int i128 __attribute__((ext_vector_type(4))); +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned int v2u32 __attribute__((ext_vector_type(2))); +typedef unsigned int v3u32 __attribute__((ext_vector_type(3))); +typedef unsigned int v4u32 __attribute__((ext_vector_type(4))); // CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b8( // CHECK-NEXT: entry: // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i8(i8 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b8(i8 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b8(u8 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b8(vdata, rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); } @@ -23,7 +23,7 @@ void test_amdgcn_raw_ptr_buffer_store_b8(i8 vdata, __amdgpu_buffer_rsrc_t rsrc, // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i16(i16 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b16(i16 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b16(u16 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b16(vdata, rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); } @@ -32,7 +32,7 @@ void test_amdgcn_raw_ptr_buffer_store_b16(i16 vdata, __amdgpu_buffer_rsrc_t rsrc // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b32(i32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b32(u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b32(vdata, rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); } @@ -41,7 +41,7 @@ void test_amdgcn_raw_ptr_buffer_store_b32(i32 vdata, __amdgpu_buffer_rsrc_t rsrc // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v2i32(<2 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b64(i64 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b64(v2u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b64(vdata, rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); } @@ -50,7 +50,7 @@ void test_amdgcn_raw_ptr_buffer_store_b64(i64 vdata, __amdgpu_buffer_rsrc_t rsrc // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v3i32(<3 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b96(i96 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b96(v3u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b96(vdata, rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); } @@ -59,7 +59,7 @@ void test_amdgcn_raw_ptr_buffer_store_b96(i96 vdata, __amdgpu_buffer_rsrc_t rsrc // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v4i32(<4 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b128(i128 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b128(v4u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b128(vdata, rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); } @@ -68,7 +68,7 @@ void test_amdgcn_raw_ptr_buffer_store_b128(i128 vdata, __amdgpu_buffer_rsrc_t rs // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i8(i8 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b8_non_const_offset(i8 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b8_non_const_offset(u8 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b8(vdata, rsrc, offset, /*soffset=*/0, /*aux=*/0); } @@ -77,7 +77,7 @@ void test_amdgcn_raw_ptr_buffer_store_b8_non_const_offset(i8 vdata, __amdgpu_buf // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i16(i16 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b16_non_const_offset(i16 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b16_non_const_offset(u16 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b16(vdata, rsrc, offset, /*soffset=*/0, /*aux=*/0); } @@ -86,7 +86,7 @@ void test_amdgcn_raw_ptr_buffer_store_b16_non_const_offset(i16 vdata, __amdgpu_b // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b32_non_const_offset(i32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b32_non_const_offset(u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b32(vdata, rsrc, offset, /*soffset=*/0, /*aux=*/0); } @@ -95,7 +95,7 @@ void test_amdgcn_raw_ptr_buffer_store_b32_non_const_offset(i32 vdata, __amdgpu_b // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v2i32(<2 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b64_non_const_offset(i64 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b64_non_const_offset(v2u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b64(vdata, rsrc, offset, /*soffset=*/0, /*aux=*/0); } @@ -104,7 +104,7 @@ void test_amdgcn_raw_ptr_buffer_store_b64_non_const_offset(i64 vdata, __amdgpu_b // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v3i32(<3 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b96_non_const_offset(i96 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b96_non_const_offset(v3u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b96(vdata, rsrc, offset, /*soffset=*/0, /*aux=*/0); } @@ -113,7 +113,7 @@ void test_amdgcn_raw_ptr_buffer_store_b96_non_const_offset(i96 vdata, __amdgpu_b // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v4i32(<4 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b128_non_const_offset(i128 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b128_non_const_offset(v4u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b128(vdata, rsrc, offset, /*soffset=*/0, /*aux=*/0); } @@ -122,7 +122,7 @@ void test_amdgcn_raw_ptr_buffer_store_b128_non_const_offset(i128 vdata, __amdgpu // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i8(i8 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b8_non_const_soffset(i8 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b8_non_const_soffset(u8 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b8(vdata, rsrc, /*offset=*/0, soffset, /*aux=*/0); } @@ -131,7 +131,7 @@ void test_amdgcn_raw_ptr_buffer_store_b8_non_const_soffset(i8 vdata, __amdgpu_bu // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i16(i16 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b16_non_const_soffset(i16 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b16_non_const_soffset(u16 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b16(vdata, rsrc, /*offset=*/0, soffset, /*aux=*/0); } @@ -140,7 +140,7 @@ void test_amdgcn_raw_ptr_buffer_store_b16_non_const_soffset(i16 vdata, __amdgpu_ // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b32_non_const_soffset(i32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b32_non_const_soffset(u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b32(vdata, rsrc, /*offset=*/0, soffset, /*aux=*/0); } @@ -149,7 +149,7 @@ void test_amdgcn_raw_ptr_buffer_store_b32_non_const_soffset(i32 vdata, __amdgpu_ // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v2i32(<2 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b64_non_const_soffset(i64 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b64_non_const_soffset(v2u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b64(vdata, rsrc, /*offset=*/0, soffset, /*aux=*/0); } @@ -158,7 +158,7 @@ void test_amdgcn_raw_ptr_buffer_store_b64_non_const_soffset(i64 vdata, __amdgpu_ // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v3i32(<3 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b96_non_const_soffset(i96 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b96_non_const_soffset(v3u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b96(vdata, rsrc, /*offset=*/0, soffset, /*aux=*/0); } @@ -167,6 +167,6 @@ void test_amdgcn_raw_ptr_buffer_store_b96_non_const_soffset(i96 vdata, __amdgpu_ // CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v4i32(<4 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) // CHECK-NEXT: ret void // -void test_amdgcn_raw_ptr_buffer_store_b128_non_const_soffset(i128 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { +void test_amdgcn_raw_ptr_buffer_store_b128_non_const_soffset(v4u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { __builtin_amdgcn_raw_buffer_store_b128(vdata, rsrc, /*offset=*/0, soffset, /*aux=*/0); } diff --git a/clang/test/Driver/hexagon-toolchain-linux.c b/clang/test/Driver/hexagon-toolchain-linux.c index fe32638..86cc9a3 100644 --- a/clang/test/Driver/hexagon-toolchain-linux.c +++ b/clang/test/Driver/hexagon-toolchain-linux.c @@ -119,3 +119,36 @@ // CHECK010: crt1.o // CHECK010: "-L/tmp" // CHECK010-NOT: "-lstandalone" + +// ----------------------------------------------------------------------------- +// unwindlib +// ----------------------------------------------------------------------------- +// RUN: %clangxx --unwindlib=none \ +// RUN: --target=hexagon-unknown-linux-musl %s -### 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK011 %s +// CHECK011: InstalledDir: [[INSTALLED_DIR:.+]] +// CHECK011: crt1.o +// CHECK011-NOT: "-lunwind" +// CHECK011-NOT: "-lgcc_eh" +// CHECK012-NOT: "-lgcc_s" + + +// RUN: %clangxx --rtlib=compiler-rt --unwindlib=libunwind \ +// RUN: --target=hexagon-unknown-linux-musl %s -### 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK012 %s +// RUN: %clangxx \ +// RUN: --target=hexagon-unknown-linux-musl %s -### 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK012 %s +// CHECK012: InstalledDir: [[INSTALLED_DIR:.+]] +// CHECK012: crt1.o +// CHECK012: "-lunwind" +// CHECK012-NOT: "-lgcc_eh" +// CHECK012-NOT: "-lgcc_s" + +// RUN: not %clangxx --rtlib=compiler-rt --unwindlib=libgcc \ +// RUN: --target=hexagon-unknown-linux-musl %s -### 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK013 %s +// CHECK013: error: unsupported unwind library 'libgcc' for platform 'hexagon-unknown-linux-musl' +// CHECK013-NOT: "-lgcc_eh" +// CHECK013-NOT: "-lgcc_s" +// CHECK013-NOT: "-lunwind" diff --git a/clang/test/Preprocessor/aarch64-target-features.c b/clang/test/Preprocessor/aarch64-target-features.c index d811cb3..71cc36a 100644 --- a/clang/test/Preprocessor/aarch64-target-features.c +++ b/clang/test/Preprocessor/aarch64-target-features.c @@ -291,309 +291,54 @@ // RUN: %clang -target aarch64 -mtune=CYCLONE -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MTUNE-CYCLONE %s // CHECK-MTUNE-CYCLONE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8a" -// RUN: %clang -target aarch64 -mcpu=apple-a7 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-APPLE-A7 %s -// RUN: %clang -target aarch64 -mcpu=apple-a8 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-APPLE-A7 %s -// RUN: %clang -target aarch64 -mcpu=apple-a9 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-APPLE-A7 %s -// RUN: %clang -target aarch64 -mcpu=apple-a10 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-APPLE-A10 %s -// RUN: %clang -target aarch64 -mcpu=apple-a11 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-APPLE-A11 %s -// RUN: %clang -target aarch64 -mcpu=apple-a12 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-APPLE-A12 %s -// RUN: %clang -target aarch64 -mcpu=apple-a13 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-APPLE-A13 %s -// RUN: %clang -target aarch64 -mcpu=apple-s4 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-APPLE-A12 %s -// RUN: %clang -target aarch64 -mcpu=apple-s5 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-APPLE-A12 %s -// RUN: %clang -target aarch64 -mcpu=cyclone -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-APPLE-A7 %s -// RUN: %clang -target aarch64 -mcpu=cortex-a34 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-A34 %s -// RUN: %clang -target aarch64 -mcpu=cortex-a35 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-A35 %s -// RUN: %clang -target aarch64 -mcpu=cortex-a53 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-A53 %s -// RUN: %clang -target aarch64 -mcpu=cortex-a57 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-A57 %s -// RUN: %clang -target aarch64 -mcpu=cortex-a72 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-A72 %s -// RUN: %clang -target aarch64 -mcpu=cortex-a73 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-CORTEX-A73 %s -// RUN: %clang -target aarch64 -mcpu=cortex-r82 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-CORTEX-R82 %s -// RUN: %clang -target aarch64 -mcpu=exynos-m3 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-M3 %s -// RUN: %clang -target aarch64 -mcpu=exynos-m4 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-M4 %s -// RUN: %clang -target aarch64 -mcpu=exynos-m5 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-M4 %s -// RUN: %clang -target aarch64 -mcpu=kryo -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-KRYO %s -// RUN: %clang -target aarch64 -mcpu=thunderx2t99 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-THUNDERX2T99 %s -// RUN: %clang -target aarch64 -mcpu=a64fx -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-A64FX %s -// RUN: %clang -target aarch64 -mcpu=carmel -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck -check-prefix=CHECK-MCPU-CARMEL %s -// CHECK-MCPU-APPLE-A7-LABEL: "-target-cpu" "apple-a7" -// CHECK-MCPU-APPLE-A7-NEXT: "-target-feature" "+zcm" -// CHECK-MCPU-APPLE-A7-NEXT: "-target-feature" "+zcz" -// CHECK-MCPU-APPLE-A7-NEXT: "-target-feature" "+v8a" -// CHECK-MCPU-APPLE-A7-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-APPLE-A7-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-APPLE-A7-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-APPLE-A7-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-APPLE-A7-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-APPLE-A7-NEXT: "-target-abi" -// CHECK-MCPU-APPLE-A10-LABEL: "-target-cpu" "apple-a10" -// CHECK-MCPU-APPLE-A10-NEXT: "-target-feature" "+zcm" -// CHECK-MCPU-APPLE-A10-NEXT: "-target-feature" "+zcz" -// CHECK-MCPU-APPLE-A10-NEXT: "-target-feature" "+v8a" -// CHECK-MCPU-APPLE-A10-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-APPLE-A10-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-APPLE-A10-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-APPLE-A10-NEXT: "-target-feature" "+lor" -// CHECK-MCPU-APPLE-A10-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-APPLE-A10-NEXT: "-target-feature" "+pan" -// CHECK-MCPU-APPLE-A10-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-APPLE-A10-NEXT: "-target-feature" "+rdm" -// CHECK-MCPU-APPLE-A10-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-APPLE-A10-NEXT: "-target-feature" "+vh" -// CHECK-MCPU-APPLE-A10-NEXT: "-target-abi" -// CHECK-MCPU-APPLE-A11-LABEL: "-target-cpu" "apple-a11" -// CHECK-MCPU-APPLE-A11-NEXT: "-target-feature" "+zcm" -// CHECK-MCPU-APPLE-A11-NEXT: "-target-feature" "+zcz" -// CHECK-MCPU-APPLE-A11-NEXT: "-target-feature" "+v8.2a" -// CHECK-MCPU-APPLE-A11-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-APPLE-A11-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-APPLE-A11-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-APPLE-A11-NEXT: "-target-feature" "+fullfp16" -// CHECK-MCPU-APPLE-A11-NEXT: "-target-feature" "+lse" -// CHECK-MCPU-APPLE-A11-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-APPLE-A11-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-APPLE-A11-NEXT: "-target-feature" "+ras" -// CHECK-MCPU-APPLE-A11-NEXT: "-target-feature" "+rdm" -// CHECK-MCPU-APPLE-A11-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-APPLE-A11-NEXT: "-target-abi" -// CHECK-MCPU-APPLE-A12-LABEL: "-target-cpu" "apple-a12" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+zcm" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+zcz" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+v8.3a" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+complxnum" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+fullfp16" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+jsconv" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+lse" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+pauth" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+ras" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+rcpc" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+rdm" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-APPLE-A12-NEXT: "-target-abi" -// CHECK-MCPU-A34-LABEL: "-target-cpu" "cortex-a34" -// CHECK-MCPU-A34-NEXT: "-target-feature" "+v8a" -// CHECK-MCPU-A34-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-A34-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-A34-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-A34-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-A34-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-A34-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-A34-NEXT: "-target-abi" -// CHECK-MCPU-APPLE-A13-LABEL: "-target-cpu" "apple-a13" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+zcm" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+zcz" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+v8.4a" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+complxnum" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+dotprod" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+fp16fml" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+fullfp16" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+jsconv" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+lse" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+pauth" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+ras" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+rcpc" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+rdm" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-feature" "+sha3" -// CHECK-MCPU-APPLE-A13-NEXT: "-target-abi" -// CHECK-MCPU-A35-LABEL: "-target-cpu" "cortex-a35" -// CHECK-MCPU-A35-NEXT: "-target-feature" "+v8a" -// CHECK-MCPU-A35-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-A35-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-A35-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-A35-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-A35-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-A35-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-A35-NEXT: "-target-abi" -// CHECK-MCPU-A53-LABEL: "-target-cpu" "cortex-a53" -// CHECK-MCPU-A53-NEXT: "-target-feature" "+v8a" -// CHECK-MCPU-A53-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-A53-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-A53-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-A53-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-A53-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-A53-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-A53-NEXT: "-target-abi" -// CHECK-MCPU-A57-LABEL: "-target-cpu" "cortex-a57" -// CHECK-MCPU-A57-NEXT: "-target-feature" "+v8a" -// CHECK-MCPU-A57-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-A57-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-A57-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-A57-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-A57-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-A57-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-A57-NEXT: "-target-abi" -// CHECK-MCPU-A72-LABEL: "-target-cpu" "cortex-a72" -// CHECK-MCPU-A72-NEXT: "-target-feature" "+v8a" -// CHECK-MCPU-A72-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-A72-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-A72-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-A72-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-A72-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-A72-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-A72-NEXT: "-target-abi" -// CHECK-MCPU-CORTEX-A73-LABEL: "-target-cpu" "cortex-a73" -// CHECK-MCPU-CORTEX-A73-NEXT: "-target-feature" "+v8a" -// CHECK-MCPU-CORTEX-A73-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-CORTEX-A73-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-CORTEX-A73-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-CORTEX-A73-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-CORTEX-A73-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-CORTEX-A73-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-CORTEX-A73-NEXT: "-target-abi" -// CHECK-MCPU-CORTEX-R82-LABEL: "-target-cpu" "cortex-r82" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+v8r" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+ccdp" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+complxnum" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+dotprod" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+flagm" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+fp16fml" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+fullfp16" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+jsconv" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+lse" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+pauth" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+predres" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+ras" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+rcpc" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+rdm" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+sb" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-feature" "+ssbs" -// CHECK-MCPU-CORTEX-R82-NEXT: "-target-abi" -// CHECK-MCPU-M3-LABEL: "-target-cpu" "exynos-m3" -// CHECK-MCPU-M3-NEXT: "-target-feature" "+v8a" -// CHECK-MCPU-M3-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-M3-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-M3-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-M3-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-M3-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-M3-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-M3-NEXT: "-target-abi" -// CHECK-MCPU-M4-LABEL: "-target-cpu" "exynos-m{{[45]}}" -// CHECK-MCPU-M4-NEXT: "-target-feature" "+v8.2a" -// CHECK-MCPU-M4-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-M4-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-M4-NEXT: "-target-feature" "+dotprod" -// CHECK-MCPU-M4-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-M4-NEXT: "-target-feature" "+fullfp16" -// CHECK-MCPU-M4-NEXT: "-target-feature" "+lse" -// CHECK-MCPU-M4-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-M4-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-M4-NEXT: "-target-feature" "+ras" -// CHECK-MCPU-M4-NEXT: "-target-feature" "+rdm" -// CHECK-MCPU-M4-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-M4-NEXT: "-target-abi" -// CHECK-MCPU-KRYO-LABEL: "-target-cpu" "kryo" -// CHECK-MCPU-KRYO-NEXT: "-target-feature" "+v8a" -// CHECK-MCPU-KRYO-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-KRYO-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-KRYO-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-KRYO-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-KRYO-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-KRYO-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-KRYO-NEXT: "-target-abi" -// CHECK-MCPU-THUNDERX2T99-LABEL: "-target-cpu" "thunderx2t99" -// CHECK-MCPU-THUNDERX2T99-NEXT: "-target-feature" "+v8.1a" -// CHECK-MCPU-THUNDERX2T99-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-THUNDERX2T99-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-THUNDERX2T99-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-THUNDERX2T99-NEXT: "-target-feature" "+lse" -// CHECK-MCPU-THUNDERX2T99-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-THUNDERX2T99-NEXT: "-target-feature" "+rdm" -// CHECK-MCPU-THUNDERX2T99-NEXT: "-target-feature" "+sha2 -// CHECK-MCPU-THUNDERX2T99-NEXT: "-target-abi" -// CHECK-MCPU-A64FX-LABEL: "-target-cpu" "a64fx" -// CHECK-MCPU-A64FX-NEXT: "-target-feature" "+v8.2a" -// CHECK-MCPU-A64FX-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-A64FX-NEXT: "-target-feature" "+complxnum" -// CHECK-MCPU-A64FX-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-A64FX-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-A64FX-NEXT: "-target-feature" "+fullfp16" -// CHECK-MCPU-A64FX-NEXT: "-target-feature" "+lse" -// CHECK-MCPU-A64FX-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-A64FX-NEXT: "-target-feature" "+perfmon" -// CHECK-MCPU-A64FX-NEXT: "-target-feature" "+ras" -// CHECK-MCPU-A64FX-NEXT: "-target-feature" "+rdm" -// CHECK-MCPU-A64FX-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-A64FX-NEXT: "-target-feature" "+sve" -// CHECK-MCPU-A64FX-NEXT: "-target-abi" -// CHECK-MCPU-CARMEL-LABEL: "-target-cpu" "carmel" -// CHECK-MCPU-CARMEL-NEXT: "-target-feature" "+v8.2a" -// CHECK-MCPU-CARMEL-NEXT: "-target-feature" "+aes" -// CHECK-MCPU-CARMEL-NEXT: "-target-feature" "+crc" -// CHECK-MCPU-CARMEL-NEXT: "-target-feature" "+fp-armv8" -// CHECK-MCPU-CARMEL-NEXT: "-target-feature" "+fullfp16" -// CHECK-MCPU-CARMEL-NEXT: "-target-feature" "+lse" -// CHECK-MCPU-CARMEL-NEXT: "-target-feature" "+neon" -// CHECK-MCPU-CARMEL-NEXT: "-target-feature" "+ras" -// CHECK-MCPU-CARMEL-NEXT: "-target-feature" "+rdm" -// CHECK-MCPU-CARMEL-NEXT: "-target-feature" "+sha2" -// CHECK-MCPU-CARMEL-NEXT: "-target-abi" - - -// RUN: %clang -target x86_64-apple-macosx -arch arm64 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck --check-prefix=CHECK-ARCH-ARM64 %s -// CHECK-ARCH-ARM64-LABEL: "-target-cpu" "apple-m1" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+zcm" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+zcz" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+v8.4a" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+aes" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+altnzcv" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+ccdp" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+complxnum" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+crc" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+dotprod" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+fp-armv8" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+fp16fml" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+fptoint" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+fullfp16" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+jsconv" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+lse" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+neon" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+pauth" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+perfmon" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+predres" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+ras" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+rcpc" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+rdm" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+sb" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+sha2" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+sha3" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+specrestrict" -// CHECK-ARCH-ARM64-NEXT: "-target-feature" "+ssbs" -// CHECK-ARCH-ARM64-NEXT: "-target-abi" - -// RUN: %clang -target x86_64-apple-macosx -arch arm64_32 -### -c %s 2>&1 | sed -e 's/"-/\n"-/g' | FileCheck --check-prefix=CHECK-ARCH-ARM64_32 %s -// CHECK-ARCH-ARM64_32-LABEL: "-target-cpu" "apple-s4" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+zcm" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+zcz" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+v8.3a" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+aes" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+complxnum" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+crc" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+fp-armv8" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+fullfp16" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+jsconv" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+lse" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+neon" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+pauth" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+perfmon" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+ras" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+rcpc" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+rdm" -// CHECK-ARCH-ARM64_32-NEXT: "-target-feature" "+sha2" -// CHECK-ARCH-ARM64_32-NEXT: "-target-abi" +// RUN: %clang -target aarch64 -mcpu=apple-a7 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-APPLE-A7 %s +// RUN: %clang -target aarch64 -mcpu=apple-a8 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-APPLE-A7 %s +// RUN: %clang -target aarch64 -mcpu=apple-a9 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-APPLE-A7 %s +// RUN: %clang -target aarch64 -mcpu=apple-a10 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-APPLE-A10 %s +// RUN: %clang -target aarch64 -mcpu=apple-a11 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-APPLE-A11 %s +// RUN: %clang -target aarch64 -mcpu=apple-a12 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-APPLE-A12 %s +// RUN: %clang -target aarch64 -mcpu=apple-a13 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-APPLE-A13 %s +// RUN: %clang -target aarch64 -mcpu=apple-s4 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-APPLE-A12 %s +// RUN: %clang -target aarch64 -mcpu=apple-s5 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-APPLE-A12 %s +// RUN: %clang -target aarch64 -mcpu=cyclone -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-APPLE-A7 %s +// RUN: %clang -target aarch64 -mcpu=cortex-a34 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-A34 %s +// RUN: %clang -target aarch64 -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-A35 %s +// RUN: %clang -target aarch64 -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-A53 %s +// RUN: %clang -target aarch64 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-A57 %s +// RUN: %clang -target aarch64 -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-A72 %s +// RUN: %clang -target aarch64 -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-CORTEX-A73 %s +// RUN: %clang -target aarch64 -mcpu=cortex-r82 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-CORTEX-R82 %s +// RUN: %clang -target aarch64 -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-M3 %s +// RUN: %clang -target aarch64 -mcpu=exynos-m4 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-M4 %s +// RUN: %clang -target aarch64 -mcpu=exynos-m5 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-M4 %s +// RUN: %clang -target aarch64 -mcpu=kryo -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-KRYO %s +// RUN: %clang -target aarch64 -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-THUNDERX2T99 %s +// RUN: %clang -target aarch64 -mcpu=a64fx -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-A64FX %s +// RUN: %clang -target aarch64 -mcpu=carmel -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-CARMEL %s +// CHECK-MCPU-APPLE-A7: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-APPLE-A10: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lor" "-target-feature" "+neon" "-target-feature" "+pan" "-target-feature" "+perfmon" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+vh" +// CHECK-MCPU-APPLE-A11: "-cc1"{{.*}} "-triple" "aarch64{{.*}}"{{.*}}"-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" +// CHECK-MCPU-APPLE-A12: "-cc1"{{.*}} "-triple" "aarch64"{{.*}} "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.3a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" +// CHECK-MCPU-A34: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-APPLE-A13: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.4a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+sha3" +// CHECK-MCPU-A35: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-A53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-A57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-A72: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-CORTEX-A73: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-CORTEX-R82: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8r" "-target-feature" "+ccdp" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+flagm" "-target-feature" "+fp-armv8" "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+predres" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sb" "-target-feature" "+ssbs" +// CHECK-MCPU-M3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-M4: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" +// CHECK-MCPU-KRYO: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-THUNDERX2T99: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+rdm" "-target-feature" "+sha2 +// CHECK-MCPU-A64FX: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+sve" +// CHECK-MCPU-CARMEL: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" + +// RUN: %clang -target x86_64-apple-macosx -arch arm64 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH-ARM64 %s +// CHECK-ARCH-ARM64: "-target-cpu" "apple-m1" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.4a" "-target-feature" "+aes" "-target-feature" "+altnzcv" "-target-feature" "+ccdp" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fp16fml" "-target-feature" "+fptoint" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+predres" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sb" "-target-feature" "+sha2" "-target-feature" "+sha3" "-target-feature" "+specrestrict" "-target-feature" "+ssbs" + +// RUN: %clang -target x86_64-apple-macosx -arch arm64_32 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH-ARM64_32 %s +// CHECK-ARCH-ARM64_32: "-target-cpu" "apple-s4" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.3a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" // RUN: %clang -target aarch64 -march=armv8-a+fp+simd+crc+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-1 %s // RUN: %clang -target aarch64 -march=armv8-a+nofp+nosimd+nocrc+nocrypto+fp+simd+crc+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-1 %s diff --git a/clang/test/SemaOpenCL/builtins-amdgcn-raw-buffer-load-error.cl b/clang/test/SemaOpenCL/builtins-amdgcn-raw-buffer-load-error.cl new file mode 100644 index 0000000..5d123c8 --- /dev/null +++ b/clang/test/SemaOpenCL/builtins-amdgcn-raw-buffer-load-error.cl @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -target-cpu verde -S -verify -o - %s +// REQUIRES: amdgpu-registered-target + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned int v2u32 __attribute__((ext_vector_type(2))); +typedef unsigned int v3u32 __attribute__((ext_vector_type(3))); +typedef unsigned int v4u32 __attribute__((ext_vector_type(4))); + +u8 test_amdgcn_raw_ptr_buffer_load_b8(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { + return __builtin_amdgcn_raw_buffer_load_b8(rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_load_b8' must be a constant integer}} +} + +u16 test_amdgcn_raw_ptr_buffer_load_b16(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { + return __builtin_amdgcn_raw_buffer_load_b16(rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_load_b16' must be a constant integer}} +} + +u32 test_amdgcn_raw_ptr_buffer_load_b32(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { + return __builtin_amdgcn_raw_buffer_load_b32(rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_load_b32' must be a constant integer}} +} + +v2u32 test_amdgcn_raw_ptr_buffer_load_b64(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { + return __builtin_amdgcn_raw_buffer_load_b64(rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_load_b64' must be a constant integer}} +} + +v3u32 test_amdgcn_raw_ptr_buffer_load_b96(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { + return __builtin_amdgcn_raw_buffer_load_b96(rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_load_b96' must be a constant integer}} +} + +v4u32 test_amdgcn_raw_ptr_buffer_load_b128(__amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { + return __builtin_amdgcn_raw_buffer_load_b128(rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_load_b128' must be a constant integer}} +} diff --git a/clang/test/SemaOpenCL/builtins-amdgcn-raw-buffer-store-error.cl b/clang/test/SemaOpenCL/builtins-amdgcn-raw-buffer-store-error.cl index 356c031..119adcd 100644 --- a/clang/test/SemaOpenCL/builtins-amdgcn-raw-buffer-store-error.cl +++ b/clang/test/SemaOpenCL/builtins-amdgcn-raw-buffer-store-error.cl @@ -3,33 +3,33 @@ #pragma OPENCL EXTENSION cl_khr_fp16 : enable -typedef char i8; -typedef short i16; -typedef int i32; -typedef int i64 __attribute__((ext_vector_type(2))); -typedef int i96 __attribute__((ext_vector_type(3))); -typedef int i128 __attribute__((ext_vector_type(4))); - -void test_amdgcn_raw_ptr_buffer_store_b8(i8 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned int v2u32 __attribute__((ext_vector_type(2))); +typedef unsigned int v3u32 __attribute__((ext_vector_type(3))); +typedef unsigned int v4u32 __attribute__((ext_vector_type(4))); + +void test_amdgcn_raw_ptr_buffer_store_b8(u8 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { __builtin_amdgcn_raw_buffer_store_b8(vdata, rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_store_b8' must be a constant integer}} } -void test_amdgcn_raw_ptr_buffer_store_b16(i16 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { +void test_amdgcn_raw_ptr_buffer_store_b16(u16 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { __builtin_amdgcn_raw_buffer_store_b16(vdata, rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_store_b16' must be a constant integer}} } -void test_amdgcn_raw_ptr_buffer_store_b32(i32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { +void test_amdgcn_raw_ptr_buffer_store_b32(u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { __builtin_amdgcn_raw_buffer_store_b32(vdata, rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_store_b32' must be a constant integer}} } -void test_amdgcn_raw_ptr_buffer_store_b64(i64 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { +void test_amdgcn_raw_ptr_buffer_store_b64(v2u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { __builtin_amdgcn_raw_buffer_store_b64(vdata, rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_store_b64' must be a constant integer}} } -void test_amdgcn_raw_ptr_buffer_store_b96(i96 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { +void test_amdgcn_raw_ptr_buffer_store_b96(v3u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { __builtin_amdgcn_raw_buffer_store_b96(vdata, rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_store_b96' must be a constant integer}} } -void test_amdgcn_raw_ptr_buffer_store_b128(i128 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { +void test_amdgcn_raw_ptr_buffer_store_b128(v4u32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { __builtin_amdgcn_raw_buffer_store_b128(vdata, rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_store_b128' must be a constant integer}} } diff --git a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp index 94af968..23304ff 100644 --- a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp +++ b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp @@ -970,6 +970,23 @@ ort \ EXPECT_EQ(Directives[1].Kind, cxx_export_module_decl); } +TEST(MinimizeSourceToDependencyDirectivesTest, ObjCMethodArgs) { + SmallVector<char, 128> Out; + + StringRef Source = R"( + @interface SomeObjcClass + - (void)func:(int)otherData + module:(int)module + import:(int)import; + @end + )"; + + ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out)); + // `module :` and `import :` not followed by an identifier are not treated as + // directive lines because they can be method argument decls. + EXPECT_STREQ("<TokBeforeEOF>\n", Out.data()); +} + TEST(MinimizeSourceToDependencyDirectivesTest, TokensBeforeEOF) { SmallString<128> Out; diff --git a/compiler-rt/cmake/base-config-ix.cmake b/compiler-rt/cmake/base-config-ix.cmake index 80bbca1..5a97992 100644 --- a/compiler-rt/cmake/base-config-ix.cmake +++ b/compiler-rt/cmake/base-config-ix.cmake @@ -43,7 +43,7 @@ if (LLVM_TREE_AVAILABLE) get_clang_resource_dir(COMPILER_RT_OUTPUT_DIR PREFIX ${LLVM_LIBRARY_OUTPUT_INTDIR}/..) set(COMPILER_RT_EXEC_OUTPUT_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR}) get_clang_resource_dir(COMPILER_RT_INSTALL_PATH) - option(COMPILER_RT_INCLUDE_TESTS "Generate and build compiler-rt unit tests." + option(COMPILER_RT_INCLUDE_TESTS "Generate and build compiler-rt tests." ${LLVM_INCLUDE_TESTS}) option(COMPILER_RT_ENABLE_WERROR "Fail and stop if warning is triggered" ${LLVM_ENABLE_WERROR}) @@ -70,7 +70,7 @@ else() "Path where built compiler-rt executables should be stored.") set(COMPILER_RT_INSTALL_PATH "" CACHE PATH "Prefix for directories where built compiler-rt artifacts should be installed.") - option(COMPILER_RT_INCLUDE_TESTS "Generate and build compiler-rt unit tests." OFF) + option(COMPILER_RT_INCLUDE_TESTS "Generate and build compiler-rt tests." OFF) option(COMPILER_RT_ENABLE_WERROR "Fail and stop if warning is triggered" OFF) # Use a host compiler to compile/link tests. set(COMPILER_RT_TEST_COMPILER ${CMAKE_C_COMPILER} CACHE PATH "Compiler to use for testing") diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h index 16cdc4c..0b0bdb0 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -316,13 +316,13 @@ class SizeClassAllocator64 { Printf( "%s %02zd (%6zd): mapped: %6zdK allocs: %7zd frees: %7zd inuse: %6zd " "num_freed_chunks %7zd avail: %6zd rss: %6zdK releases: %6zd " - "last released: %6lldK region: 0x%zx\n", + "last released: %6lldK region: %p\n", region->exhausted ? "F" : " ", class_id, ClassIdToSize(class_id), region->mapped_user >> 10, region->stats.n_allocated, region->stats.n_freed, in_use, region->num_freed_chunks, avail_chunks, rss >> 10, region->rtoi.num_releases, region->rtoi.last_released_bytes >> 10, - SpaceBeg() + kRegionSize * class_id); + (void *)(SpaceBeg() + kRegionSize * class_id)); } void PrintStats() { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp index ce43269..506659a 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp @@ -75,7 +75,8 @@ static void SanitizerDumpCoverage(const uptr* unsorted_pcs, uptr len) { if (!pc) continue; if (!GetModuleAndOffsetForPc(pc, nullptr, 0, &pcs[i])) { - Printf("ERROR: unknown pc 0x%zx (may happen if dlclose is used)\n", pc); + Printf("ERROR: unknown pc %p (may happen if dlclose is used)\n", + (void*)pc); continue; } uptr module_base = pc - pcs[i]; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp index b7fc944..f0e1e3d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp @@ -105,8 +105,8 @@ void LibIgnore::OnLibraryLoaded(const char *name) { continue; if (IsPcInstrumented(range.beg) && IsPcInstrumented(range.end - 1)) continue; - VReport(1, "Adding instrumented range 0x%zx-0x%zx from library '%s'\n", - range.beg, range.end, mod.full_name()); + VReport(1, "Adding instrumented range %p-%p from library '%s'\n", + (void *)range.beg, (void *)range.end, mod.full_name()); const uptr idx = atomic_load(&instrumented_ranges_count_, memory_order_relaxed); CHECK_LT(idx, ARRAY_SIZE(instrumented_code_ranges_)); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp index 794e3e7..47f9f0c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -2118,8 +2118,124 @@ bool SignalContext::IsTrueFaultingAddress() const { return si->si_signo == SIGSEGV && si->si_code != 128; } +UNUSED +static const char *RegNumToRegName(int reg) { + switch (reg) { +# if defined(__x86_64__) + case REG_RAX: + return "rax"; + case REG_RBX: + return "rbx"; + case REG_RCX: + return "rcx"; + case REG_RDX: + return "rdx"; + case REG_RDI: + return "rdi"; + case REG_RSI: + return "rsi"; + case REG_RBP: + return "rbp"; + case REG_RSP: + return "rsp"; + case REG_R8: + return "r8"; + case REG_R9: + return "r9"; + case REG_R10: + return "r10"; + case REG_R11: + return "r11"; + case REG_R12: + return "r12"; + case REG_R13: + return "r13"; + case REG_R14: + return "r14"; + case REG_R15: + return "r15"; +# elif defined(__i386__) + case REG_EAX: + return "eax"; + case REG_EBX: + return "ebx"; + case REG_ECX: + return "ecx"; + case REG_EDX: + return "edx"; + case REG_EDI: + return "edi"; + case REG_ESI: + return "esi"; + case REG_EBP: + return "ebp"; + case REG_ESP: + return "esp"; +# endif + default: + return NULL; + } + return NULL; +} + +UNUSED +static void DumpSingleReg(ucontext_t *ctx, int RegNum) { + const char *RegName = RegNumToRegName(RegNum); +# if defined(__x86_64__) + Printf("%s%s = 0x%016llx ", internal_strlen(RegName) == 2 ? " " : "", + RegName, ctx->uc_mcontext.gregs[RegNum]); +# elif defined(__i386__) + Printf("%s = 0x%08x ", RegName, ctx->uc_mcontext.gregs[RegNum]); +# else + (void)RegName; +# endif +} + void SignalContext::DumpAllRegisters(void *context) { - // FIXME: Implement this. +# if SANITIZER_LINUX + ucontext_t *ucontext = (ucontext_t *)context; +# if defined(__x86_64__) + Report("Register values:\n"); + DumpSingleReg(ucontext, REG_RAX); + DumpSingleReg(ucontext, REG_RBX); + DumpSingleReg(ucontext, REG_RCX); + DumpSingleReg(ucontext, REG_RDX); + Printf("\n"); + DumpSingleReg(ucontext, REG_RDI); + DumpSingleReg(ucontext, REG_RSI); + DumpSingleReg(ucontext, REG_RBP); + DumpSingleReg(ucontext, REG_RSP); + Printf("\n"); + DumpSingleReg(ucontext, REG_R8); + DumpSingleReg(ucontext, REG_R9); + DumpSingleReg(ucontext, REG_R10); + DumpSingleReg(ucontext, REG_R11); + Printf("\n"); + DumpSingleReg(ucontext, REG_R12); + DumpSingleReg(ucontext, REG_R13); + DumpSingleReg(ucontext, REG_R14); + DumpSingleReg(ucontext, REG_R15); + Printf("\n"); +# elif defined(__i386__) + // Duplication of this report print is caused by partial support + // of register values dumping. In case of unsupported yet architecture let's + // avoid printing 'Register values:' without actual values in the following + // output. + Report("Register values:\n"); + DumpSingleReg(ucontext, REG_EAX); + DumpSingleReg(ucontext, REG_EBX); + DumpSingleReg(ucontext, REG_ECX); + DumpSingleReg(ucontext, REG_EDX); + Printf("\n"); + DumpSingleReg(ucontext, REG_EDI); + DumpSingleReg(ucontext, REG_ESI); + DumpSingleReg(ucontext, REG_EBP); + DumpSingleReg(ucontext, REG_ESP); + Printf("\n"); +# endif + (void)ucontext; +# endif + // FIXME: Implement this for other OSes and architectures. } static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp index cbdf3e9..8ebe37d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp @@ -1372,8 +1372,8 @@ void DumpProcessMap() { for (uptr i = 0; i < modules.size(); ++i) { char uuid_str[128]; FormatUUID(uuid_str, sizeof(uuid_str), modules[i].uuid()); - Printf("0x%zx-0x%zx %s (%s) %s\n", modules[i].base_address(), - modules[i].max_address(), modules[i].full_name(), + Printf("%p-%p %s (%s) %s\n", (void *)modules[i].base_address(), + (void *)modules[i].max_address(), modules[i].full_name(), ModuleArchToString(modules[i].arch()), uuid_str); } Printf("End of module map.\n"); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp index 969327a..7d7d575 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp @@ -130,8 +130,8 @@ static void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem, if (tolerate_enomem && reserrno == ENOMEM) return nullptr; char mem_type[40]; - internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", - fixed_addr); + internal_snprintf(mem_type, sizeof(mem_type), "memory at address %p", + (void *)fixed_addr); ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); } IncreaseTotalMmap(size); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index ece2d7d..9ffb36f 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -327,9 +327,10 @@ static bool MmapFixed(uptr fixed_addr, uptr size, int additional_flags, MAP_PRIVATE | MAP_FIXED | additional_flags | MAP_ANON, name); int reserrno; if (internal_iserror(p, &reserrno)) { - Report("ERROR: %s failed to " - "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n", - SanitizerToolName, size, size, fixed_addr, reserrno); + Report( + "ERROR: %s failed to " + "allocate 0x%zx (%zd) bytes at address %p (errno: %d)\n", + SanitizerToolName, size, size, (void *)fixed_addr, reserrno); return false; } IncreaseTotalMmap(size); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp index b23796f..dddae44 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp @@ -192,7 +192,7 @@ void FormattedStackTracePrinter::RenderFrame(InternalScopedString *buffer, buffer->AppendF("%u", frame_no); break; case 'p': - buffer->AppendF("0x%zx", address); + buffer->AppendF("%p", (void *)address); break; case 'm': buffer->AppendF("%s", StripPathPrefix(info->module, strip_path_prefix)); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp index 25c4af7..526a71c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp @@ -257,8 +257,8 @@ static void TracerThreadDieCallback() { static void TracerThreadSignalHandler(int signum, __sanitizer_siginfo *siginfo, void *uctx) { SignalContext ctx(siginfo, uctx); - Printf("Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n", signum, - ctx.addr, ctx.pc, ctx.sp); + Printf("Tracer caught signal %d: addr=%p pc=%p sp=%p\n", signum, + (void *)ctx.addr, (void *)ctx.pc, (void *)ctx.sp); ThreadSuspender *inst = thread_suspender_instance; if (inst) { if (signum == SIGABRT) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp index 701db72..58a0cfd 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp @@ -158,8 +158,8 @@ static void TracerThreadDieCallback() { static void TracerThreadSignalHandler(int signum, __sanitizer_siginfo *siginfo, void *uctx) { SignalContext ctx(siginfo, uctx); - Printf("Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n", signum, - ctx.addr, ctx.pc, ctx.sp); + Printf("Tracer caught signal %d: addr=%p pc=%p sp=%p\n", signum, + (void *)ctx.addr, (void *)ctx.pc, (void *)ctx.sp); ThreadSuspender *inst = thread_suspender_instance; if (inst) { if (signum == SIGABRT) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cpp index 252979f..ee293bb 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cpp @@ -121,25 +121,26 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res, uptr tls_size = 0; uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset - kDtvOffset; VReport(2, - "__tls_get_addr: %p {0x%zx,0x%zx} => %p; tls_beg: 0x%zx; sp: %p " + "__tls_get_addr: %p {0x%zx,0x%zx} => %p; tls_beg: %p; sp: %p " "num_live_dtls %zd\n", - (void *)arg, arg->dso_id, arg->offset, res, tls_beg, (void *)&tls_beg, + (void *)arg, arg->dso_id, arg->offset, res, (void *)tls_beg, + (void *)&tls_beg, atomic_load(&number_of_live_dtls, memory_order_relaxed)); if (dtls.last_memalign_ptr == tls_beg) { tls_size = dtls.last_memalign_size; - VReport(2, "__tls_get_addr: glibc <=2.24 suspected; tls={0x%zx,0x%zx}\n", - tls_beg, tls_size); + VReport(2, "__tls_get_addr: glibc <=2.24 suspected; tls={%p,0x%zx}\n", + (void *)tls_beg, tls_size); } else if (tls_beg >= static_tls_begin && tls_beg < static_tls_end) { // This is the static TLS block which was initialized / unpoisoned at thread // creation. - VReport(2, "__tls_get_addr: static tls: 0x%zx\n", tls_beg); + VReport(2, "__tls_get_addr: static tls: %p\n", (void *)tls_beg); tls_size = 0; } else if (const void *start = __sanitizer_get_allocated_begin((void *)tls_beg)) { tls_beg = (uptr)start; tls_size = __sanitizer_get_allocated_size(start); - VReport(2, "__tls_get_addr: glibc >=2.25 suspected; tls={0x%zx,0x%zx}\n", - tls_beg, tls_size); + VReport(2, "__tls_get_addr: glibc >=2.25 suspected; tls={%p,0x%zx}\n", + (void *)tls_beg, tls_size); } else { VReport(2, "__tls_get_addr: Can't guess glibc version\n"); // This may happen inside the DTOR of main thread, so just ignore it. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp index 0b19889..995f00e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp @@ -276,8 +276,8 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) { MEM_COMMIT, PAGE_READWRITE); if (p == 0) { char mem_type[30]; - internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", - fixed_addr); + internal_snprintf(mem_type, sizeof(mem_type), "memory at address %p", + (void *)fixed_addr); ReportMmapFailureAndDie(size, mem_type, "allocate", GetLastError()); } return p; @@ -308,8 +308,8 @@ void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) { MEM_COMMIT, PAGE_READWRITE); if (p == 0) { char mem_type[30]; - internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", - fixed_addr); + internal_snprintf(mem_type, sizeof(mem_type), "memory at address %p", + (void *)fixed_addr); return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); } return p; diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cpp index e810122..0283388 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cpp @@ -100,11 +100,11 @@ TEST_F(StackDepotTest, Print) { }; EXPECT_EXIT( (StackDepotPrintAll(), exit(0)), ::testing::ExitedWithCode(0), - fix_regex("Stack for id .*#0 0x1.*#1 0x2.*#2 0x3.*#3 0x4.*#4 0x7.*")); - EXPECT_EXIT( - (StackDepotPrintAll(), exit(0)), ::testing::ExitedWithCode(0), fix_regex( - "Stack for id .*#0 0x1.*#1 0x2.*#2 0x3.*#3 0x4.*#4 0x8.*#5 0x9.*")); + "Stack for id .*#0 0x0*1.*#1 0x0*2.*#2 0x0*3.*#3 0x0*4.*#4 0x0*7.*")); + EXPECT_EXIT((StackDepotPrintAll(), exit(0)), ::testing::ExitedWithCode(0), + fix_regex("Stack for id .*#0 0x0*1.*#1 0x0*2.*#2 0x0*3.*#3 " + "0x0*4.*#4 0x0*8.*#5 0x0*9.*")); } TEST_F(StackDepotTest, PrintNoLock) { diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cpp index 9602ba3..76a434b 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cpp @@ -11,9 +11,12 @@ //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_stacktrace_printer.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" #include "interception/interception.h" +using testing::MatchesRegex; + namespace __sanitizer { class TestFormattedStackTracePrinter final : public FormattedStackTracePrinter { @@ -96,10 +99,12 @@ TEST(FormattedStackTracePrinter, RenderFrame) { "Function:%f FunctionOffset:%q Source:%s Line:%l " "Column:%c", frame_no, info.address, &info, false, "/path/to/"); - EXPECT_STREQ("% Frame:42 PC:0x400000 Module:my/module ModuleOffset:0x200 " - "Function:foo FunctionOffset:0x100 Source:my/source Line:10 " - "Column:5", - str.data()); + EXPECT_THAT( + str.data(), + MatchesRegex( + "% Frame:42 PC:0x0*400000 Module:my/module ModuleOffset:0x200 " + "Function:foo FunctionOffset:0x100 Source:my/source Line:10 " + "Column:5")); str.clear(); // Check that RenderFrame() strips interceptor prefixes. @@ -109,10 +114,12 @@ TEST(FormattedStackTracePrinter, RenderFrame) { "Function:%f FunctionOffset:%q Source:%s Line:%l " "Column:%c", frame_no, info.address, &info, false, "/path/to/"); - EXPECT_STREQ("% Frame:42 PC:0x400000 Module:my/module ModuleOffset:0x200 " - "Function:bar FunctionOffset:0x100 Source:my/source Line:10 " - "Column:5", - str.data()); + EXPECT_THAT( + str.data(), + MatchesRegex( + "% Frame:42 PC:0x0*400000 Module:my/module ModuleOffset:0x200 " + "Function:bar FunctionOffset:0x100 Source:my/source Line:10 " + "Column:5")); info.Clear(); str.clear(); diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cpp index 769a9b9..11ca1fd 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cpp @@ -284,7 +284,7 @@ TEST(GetCurrentPc, Basic) { StackTrace::GetCurrentPc(), }; for (uptr i = 0; i < ARRAY_SIZE(pcs); i++) - Printf("pc%zu: 0x%zx\n", i, pcs[i]); + Printf("pc%zu: %p\n", i, (void *)(pcs[i])); for (uptr i = 1; i < ARRAY_SIZE(pcs); i++) { EXPECT_GT(pcs[i], pcs[0]); EXPECT_LT(pcs[i], pcs[0] + 1000); diff --git a/compiler-rt/test/CMakeLists.txt b/compiler-rt/test/CMakeLists.txt index 83e4439..84a98f3 100644 --- a/compiler-rt/test/CMakeLists.txt +++ b/compiler-rt/test/CMakeLists.txt @@ -48,7 +48,7 @@ umbrella_lit_testsuite_begin(check-compiler-rt) function(compiler_rt_test_runtime runtime) string(TOUPPER ${runtime} runtime_uppercase) - if(COMPILER_RT_HAS_${runtime_uppercase}) + if(COMPILER_RT_HAS_${runtime_uppercase} AND COMPILER_RT_INCLUDE_TESTS) if (${runtime} STREQUAL cfi AND NOT COMPILER_RT_HAS_UBSAN) # CFI tests require diagnostic mode, which is implemented in UBSan. elseif (${runtime} STREQUAL scudo_standalone) diff --git a/compiler-rt/test/asan/CMakeLists.txt b/compiler-rt/test/asan/CMakeLists.txt index 2d683e6..fb9e81b 100644 --- a/compiler-rt/test/asan/CMakeLists.txt +++ b/compiler-rt/test/asan/CMakeLists.txt @@ -130,39 +130,37 @@ if(APPLE) endif() # Add unit tests. -if(COMPILER_RT_INCLUDE_TESTS) - foreach(arch ${ASAN_TEST_ARCH}) - string(TOUPPER ${arch} ARCH_UPPER_CASE) - set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config) - set(CONFIG_NAME_DYNAMIC ${ARCH_UPPER_CASE}${OS_NAME}DynamicConfig) +foreach(arch ${ASAN_TEST_ARCH}) + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config) + set(CONFIG_NAME_DYNAMIC ${ARCH_UPPER_CASE}${OS_NAME}DynamicConfig) - if(NOT MINGW) - # MinGW environments don't provide a statically linked CRT, so only the - # dynamic asan test configuration can be expected to work. - set(ASAN_TEST_DYNAMIC False) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in - ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}/lit.site.cfg.py) + if(NOT MINGW) + # MinGW environments don't provide a statically linked CRT, so only the + # dynamic asan test configuration can be expected to work. + set(ASAN_TEST_DYNAMIC False) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}/lit.site.cfg.py) + endif() + if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) + set(ASAN_TEST_DYNAMIC True) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME_DYNAMIC}/lit.site.cfg.py) + endif() + # FIXME: support unit test in the android test runner + if (NOT ANDROID) + if (NOT MINGW) + list(APPEND ASAN_TEST_DEPS AsanUnitTests) + list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}) endif() if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) - set(ASAN_TEST_DYNAMIC True) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in - ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME_DYNAMIC}/lit.site.cfg.py) + list(APPEND ASAN_DYNAMIC_TEST_DEPS AsanDynamicUnitTests) + list(APPEND ASAN_DYNAMIC_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME_DYNAMIC}) endif() - # FIXME: support unit test in the android test runner - if (NOT ANDROID) - if (NOT MINGW) - list(APPEND ASAN_TEST_DEPS AsanUnitTests) - list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}) - endif() - if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) - list(APPEND ASAN_DYNAMIC_TEST_DEPS AsanDynamicUnitTests) - list(APPEND ASAN_DYNAMIC_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME_DYNAMIC}) - endif() - endif() - endforeach() -endif() + endif() +endforeach() if (SHADOW_MAPPING_UNRELIABLE) set(exclude_from_check_all.g "EXCLUDE_FROM_CHECK_ALL") diff --git a/compiler-rt/test/ctx_profile/CMakeLists.txt b/compiler-rt/test/ctx_profile/CMakeLists.txt index 371f1a2..fc3b3f3 100644 --- a/compiler-rt/test/ctx_profile/CMakeLists.txt +++ b/compiler-rt/test/ctx_profile/CMakeLists.txt @@ -25,17 +25,15 @@ foreach(arch ${CTX_PROFILE_SUPPORTED_ARCH}) endforeach() # Add unit tests. -if(COMPILER_RT_INCLUDE_TESTS) - foreach(arch ${CTX_PROFILE_SUPPORTED_ARCH}) - string(TOUPPER ${arch} ARCH_UPPER_CASE) - set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in - ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}/lit.site.cfg.py) - list(APPEND CTX_PROFILE_TEST_DEPS CtxProfileUnitTests) - list(APPEND CTX_PROFILE_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}) - endforeach() -endif() +foreach(arch ${CTX_PROFILE_SUPPORTED_ARCH}) + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}/lit.site.cfg.py) + list(APPEND CTX_PROFILE_TEST_DEPS CtxProfileUnitTests) + list(APPEND CTX_PROFILE_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}) +endforeach() add_lit_testsuite(check-ctx_profile "Running the Contextual Profiler tests" ${CTX_PROFILE_TESTSUITES} diff --git a/compiler-rt/test/fuzzer/CMakeLists.txt b/compiler-rt/test/fuzzer/CMakeLists.txt index 8d29a4b..b19f52e 100644 --- a/compiler-rt/test/fuzzer/CMakeLists.txt +++ b/compiler-rt/test/fuzzer/CMakeLists.txt @@ -22,20 +22,16 @@ if (APPLE) darwin_filter_host_archs(FUZZER_SUPPORTED_ARCH FUZZER_TEST_ARCH) endif() -if(COMPILER_RT_INCLUDE_TESTS) - list(APPEND LIBFUZZER_TEST_DEPS FuzzerUnitTests) - list(APPEND LIBFUZZER_TEST_DEPS FuzzedDataProviderUnitTests) -endif() +list(APPEND LIBFUZZER_TEST_DEPS FuzzerUnitTests) +list(APPEND LIBFUZZER_TEST_DEPS FuzzedDataProviderUnitTests) set(LIBFUZZER_TESTSUITES) -if(COMPILER_RT_INCLUDE_TESTS) - # libFuzzer unit tests. - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/unit/lit.site.cfg.py.in - ${CMAKE_CURRENT_BINARY_DIR}/unit/lit.site.cfg.py) - list(APPEND LIBFUZZER_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/unit) -endif() +# libFuzzer unit tests. +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/unit/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/unit/lit.site.cfg.py) +list(APPEND LIBFUZZER_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/unit) macro(test_fuzzer stdlib) cmake_parse_arguments(TEST "" "" "DEPS" ${ARGN}) diff --git a/compiler-rt/test/gwp_asan/CMakeLists.txt b/compiler-rt/test/gwp_asan/CMakeLists.txt index f9580e2..6ffa36e 100644 --- a/compiler-rt/test/gwp_asan/CMakeLists.txt +++ b/compiler-rt/test/gwp_asan/CMakeLists.txt @@ -14,7 +14,7 @@ set(GWP_ASAN_TEST_DEPS # exported libc++ from the Android NDK is x86-64, even though it's part of the # ARM[64] toolchain... See similar measures for ASan and sanitizer-common that # disable unit tests for Android. -if (COMPILER_RT_INCLUDE_TESTS AND NOT ANDROID) +if (NOT ANDROID) list(APPEND GWP_ASAN_TEST_DEPS GwpAsanUnitTests) configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/unit/lit.site.cfg.py.in @@ -22,7 +22,7 @@ if (COMPILER_RT_INCLUDE_TESTS AND NOT ANDROID) list(APPEND GWP_ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/unit) endif() -if (COMPILER_RT_INCLUDE_TESTS AND COMPILER_RT_HAS_SCUDO_STANDALONE) +if (COMPILER_RT_HAS_SCUDO_STANDALONE) foreach(arch ${GWP_ASAN_SUPPORTED_ARCH}) set(GWP_ASAN_TEST_TARGET_ARCH ${arch}) string(TOLOWER "-${arch}" GWP_ASAN_TEST_CONFIG_SUFFIX) diff --git a/compiler-rt/test/interception/CMakeLists.txt b/compiler-rt/test/interception/CMakeLists.txt index df69453..8ed1a00 100644 --- a/compiler-rt/test/interception/CMakeLists.txt +++ b/compiler-rt/test/interception/CMakeLists.txt @@ -3,7 +3,7 @@ set(INTERCEPTION_TESTSUITES) # Unit tests. There are currently no unit tests capable to running on Apple or # Android targets. -if(COMPILER_RT_INCLUDE_TESTS AND NOT ANDROID AND NOT APPLE) +if(NOT ANDROID AND NOT APPLE) configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py) diff --git a/compiler-rt/test/memprof/CMakeLists.txt b/compiler-rt/test/memprof/CMakeLists.txt index 0012452..4c50ae6 100644 --- a/compiler-rt/test/memprof/CMakeLists.txt +++ b/compiler-rt/test/memprof/CMakeLists.txt @@ -44,17 +44,15 @@ foreach(arch ${MEMPROF_TEST_ARCH}) endforeach() # Add unit tests. -if(COMPILER_RT_INCLUDE_TESTS) - foreach(arch ${MEMPROF_TEST_ARCH}) - string(TOUPPER ${arch} ARCH_UPPER_CASE) - set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in - ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}/lit.site.cfg.py) - list(APPEND MEMPROF_TEST_DEPS MemProfUnitTests) - list(APPEND MEMPROF_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}) - endforeach() -endif() +foreach(arch ${MEMPROF_TEST_ARCH}) + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}/lit.site.cfg.py) + list(APPEND MEMPROF_TEST_DEPS MemProfUnitTests) + list(APPEND MEMPROF_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}) +endforeach() add_lit_testsuite(check-memprof "Running the MemProfiler tests" ${MEMPROF_TESTSUITES} diff --git a/compiler-rt/test/msan/CMakeLists.txt b/compiler-rt/test/msan/CMakeLists.txt index ff19c11..df571976 100644 --- a/compiler-rt/test/msan/CMakeLists.txt +++ b/compiler-rt/test/msan/CMakeLists.txt @@ -41,9 +41,7 @@ foreach(arch ${MSAN_TEST_ARCH}) endif() endforeach() -if(COMPILER_RT_INCLUDE_TESTS AND - COMPILER_RT_LIBCXX_PATH AND - COMPILER_RT_LIBCXXABI_PATH) +if(COMPILER_RT_LIBCXX_PATH AND COMPILER_RT_LIBCXXABI_PATH) configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py) diff --git a/compiler-rt/test/nsan/CMakeLists.txt b/compiler-rt/test/nsan/CMakeLists.txt index fb73587..d702e12 100644 --- a/compiler-rt/test/nsan/CMakeLists.txt +++ b/compiler-rt/test/nsan/CMakeLists.txt @@ -3,9 +3,7 @@ set(NSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(NSAN_TESTSUITES) set(NSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS} nsan) -if(COMPILER_RT_INCLUDE_TESTS AND - COMPILER_RT_LIBCXX_PATH AND - COMPILER_RT_LIBCXXABI_PATH) +if(COMPILER_RT_LIBCXX_PATH AND COMPILER_RT_LIBCXXABI_PATH) configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py) diff --git a/compiler-rt/test/rtsan/CMakeLists.txt b/compiler-rt/test/rtsan/CMakeLists.txt index 2a59a57..e1f9eb3 100644 --- a/compiler-rt/test/rtsan/CMakeLists.txt +++ b/compiler-rt/test/rtsan/CMakeLists.txt @@ -34,20 +34,18 @@ foreach(arch ${RTSAN_TEST_ARCH}) list(APPEND RTSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) endforeach() -if(COMPILER_RT_INCLUDE_TESTS) +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py) +if(COMPILER_RT_RTSAN_HAS_STATIC_RUNTIME) configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in - ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py) - if(COMPILER_RT_RTSAN_HAS_STATIC_RUNTIME) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in - ${CMAKE_CURRENT_BINARY_DIR}/Unit/dynamic/lit.site.cfg.py) - endif() - list(APPEND RTSAN_TEST_DEPS RtsanUnitTests) - list(APPEND RTSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit) - if(COMPILER_RT_RTSAN_HAS_STATIC_RUNTIME) - list(APPEND RTSAN_DYNAMIC_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/dynamic) - endif() + ${CMAKE_CURRENT_BINARY_DIR}/Unit/dynamic/lit.site.cfg.py) +endif() +list(APPEND RTSAN_TEST_DEPS RtsanUnitTests) +list(APPEND RTSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit) +if(COMPILER_RT_RTSAN_HAS_STATIC_RUNTIME) + list(APPEND RTSAN_DYNAMIC_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/dynamic) endif() add_lit_testsuite(check-rtsan "Running the Rtsan tests" diff --git a/compiler-rt/test/sanitizer_common/CMakeLists.txt b/compiler-rt/test/sanitizer_common/CMakeLists.txt index edecc04..fa06b82 100644 --- a/compiler-rt/test/sanitizer_common/CMakeLists.txt +++ b/compiler-rt/test/sanitizer_common/CMakeLists.txt @@ -99,15 +99,13 @@ foreach(tool ${SUPPORTED_TOOLS}) endforeach() # Unit tests. -if(COMPILER_RT_INCLUDE_TESTS) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in - ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py) - # FIXME: support unit test in the android test runner - if (NOT ANDROID) - list(APPEND SANITIZER_COMMON_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit) - list(APPEND SANITIZER_COMMON_TEST_DEPS SanitizerUnitTests) - endif() +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py) +# FIXME: support unit test in the android test runner +if (NOT ANDROID) + list(APPEND SANITIZER_COMMON_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit) + list(APPEND SANITIZER_COMMON_TEST_DEPS SanitizerUnitTests) endif() if(SANITIZER_COMMON_TESTSUITES) diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_i386.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_i386.cpp new file mode 100644 index 0000000..74aea4d --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_i386.cpp @@ -0,0 +1,17 @@ +// Check that sanitizer prints registers dump_registers on dump_registers=1 +// RUN: %clangxx %s -o %t +// RUN: %env_tool_opts=dump_registers=0 not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK-NODUMP --strict-whitespace +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK-DUMP --strict-whitespace +// +// REQUIRES: i386-target-arch + +#include <signal.h> + +int main() { + raise(SIGSEGV); + // CHECK-DUMP: Register values + // CHECK-DUMP-NEXT: eax = {{0x[0-9a-f]+}} ebx = {{0x[0-9a-f]+}} ecx = {{0x[0-9a-f]+}} edx = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT: edi = {{0x[0-9a-f]+}} esi = {{0x[0-9a-f]+}} ebp = {{0x[0-9a-f]+}} esp = {{0x[0-9a-f]+}} + // CHECK-NODUMP-NOT: Register values + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_x86_64.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_x86_64.cpp new file mode 100644 index 0000000..3d11ef0 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_x86_64.cpp @@ -0,0 +1,19 @@ +// Check that sanitizer prints registers dump_registers on dump_registers=1 +// RUN: %clangxx %s -o %t +// RUN: %env_tool_opts=dump_registers=0 not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK-NODUMP --strict-whitespace +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK-DUMP --strict-whitespace +// +// REQUIRES: x86_64-target-arch + +#include <signal.h> + +int main() { + raise(SIGSEGV); + // CHECK-DUMP: Register values + // CHECK-DUMP-NEXT: rax = {{0x[0-9a-f]+}} rbx = {{0x[0-9a-f]+}} rcx = {{0x[0-9a-f]+}} rdx = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT: rdi = {{0x[0-9a-f]+}} rsi = {{0x[0-9a-f]+}} rbp = {{0x[0-9a-f]+}} rsp = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT: r8 = {{0x[0-9a-f]+}} r9 = {{0x[0-9a-f]+}} r10 = {{0x[0-9a-f]+}} r11 = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT: r12 = {{0x[0-9a-f]+}} r13 = {{0x[0-9a-f]+}} r14 = {{0x[0-9a-f]+}} r15 = {{0x[0-9a-f]+}} + // CHECK-NODUMP-NOT: Register values + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_test.cpp b/compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_test.cpp index 286eafc..21ffe13 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_test.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_test.cpp @@ -14,15 +14,12 @@ int main(int argc, char **argv) { sprintf(buff, "%s.report_path/report", argv[0]); __sanitizer_set_report_path(buff); assert(strncmp(buff, __sanitizer_get_report_path(), strlen(buff)) == 0); - printf("Path %s\n", __sanitizer_get_report_path()); - fflush(stdout); // Try setting again with an invalid/inaccessible directory. - sprintf(buff, "%s/report", argv[0]); - __sanitizer_set_report_path(buff); - printf("Path %s\n", __sanitizer_get_report_path()); + char buff_bad[1000]; + sprintf(buff_bad, "%s/report", argv[0]); + __sanitizer_set_report_path(buff_bad); + assert(strncmp(buff, __sanitizer_get_report_path(), strlen(buff)) == 0); } -// CHECK: Path {{.*}}Posix/Output/sanitizer_set_report_path_test.cpp.tmp.report_path/report. // CHECK: ERROR: Can't create directory: {{.*}}Posix/Output/sanitizer_set_report_path_test.cpp.tmp -// CHECK-NOT: Path {{.*}}Posix/Output/sanitizer_set_report_path_test.cpp.tmp diff --git a/compiler-rt/test/scudo/standalone/CMakeLists.txt b/compiler-rt/test/scudo/standalone/CMakeLists.txt index 0034cea..3e6c8ab 100644 --- a/compiler-rt/test/scudo/standalone/CMakeLists.txt +++ b/compiler-rt/test/scudo/standalone/CMakeLists.txt @@ -1,21 +1,19 @@ -if(COMPILER_RT_INCLUDE_TESTS) +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/unit/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/unit/lit.site.cfg.py) +list(APPEND SCUDO_STANDALONE_TEST_DEPS ScudoUnitTests) +list(APPEND SCUDO_STANDALONE_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/unit) +if (COMPILER_RT_HAS_GWP_ASAN) configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/unit/lit.site.cfg.py.in - ${CMAKE_CURRENT_BINARY_DIR}/unit/lit.site.cfg.py) - list(APPEND SCUDO_STANDALONE_TEST_DEPS ScudoUnitTests) - list(APPEND SCUDO_STANDALONE_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/unit) - if (COMPILER_RT_HAS_GWP_ASAN) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/unit/gwp_asan/lit.site.cfg.py.in - ${CMAKE_CURRENT_BINARY_DIR}/unit/gwp_asan/lit.site.cfg.py) - list(APPEND SCUDO_STANDALONE_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/unit/gwp_asan) - endif() + ${CMAKE_CURRENT_SOURCE_DIR}/unit/gwp_asan/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/unit/gwp_asan/lit.site.cfg.py) + list(APPEND SCUDO_STANDALONE_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/unit/gwp_asan) +endif() - add_lit_testsuite(check-scudo_standalone - "Running Scudo Standalone tests" - ${SCUDO_STANDALONE_TESTSUITES} - DEPENDS ${SCUDO_STANDALONE_TEST_DEPS}) +add_lit_testsuite(check-scudo_standalone + "Running Scudo Standalone tests" + ${SCUDO_STANDALONE_TESTSUITES} + DEPENDS ${SCUDO_STANDALONE_TEST_DEPS}) - set_target_properties(check-scudo_standalone - PROPERTIES FOLDER "Compiler-RT Tests") -endif() +set_target_properties(check-scudo_standalone + PROPERTIES FOLDER "Compiler-RT Tests") diff --git a/compiler-rt/test/tsan/CMakeLists.txt b/compiler-rt/test/tsan/CMakeLists.txt index 31cda53..163355d 100644 --- a/compiler-rt/test/tsan/CMakeLists.txt +++ b/compiler-rt/test/tsan/CMakeLists.txt @@ -111,20 +111,18 @@ if(APPLE) endforeach() endif() -if(COMPILER_RT_INCLUDE_TESTS) +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py) +if(COMPILER_RT_TSAN_HAS_STATIC_RUNTIME) configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in - ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py) - if(COMPILER_RT_TSAN_HAS_STATIC_RUNTIME) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in - ${CMAKE_CURRENT_BINARY_DIR}/Unit/dynamic/lit.site.cfg.py) - endif() - list(APPEND TSAN_TEST_DEPS TsanUnitTests) - list(APPEND TSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit) - if(COMPILER_RT_TSAN_HAS_STATIC_RUNTIME) - list(APPEND TSAN_DYNAMIC_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/dynamic) - endif() + ${CMAKE_CURRENT_BINARY_DIR}/Unit/dynamic/lit.site.cfg.py) +endif() +list(APPEND TSAN_TEST_DEPS TsanUnitTests) +list(APPEND TSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit) +if(COMPILER_RT_TSAN_HAS_STATIC_RUNTIME) + list(APPEND TSAN_DYNAMIC_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/dynamic) endif() add_lit_testsuite(check-tsan "Running ThreadSanitizer tests" diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md index 82f9a02..093596c 100644 --- a/flang/docs/Extensions.md +++ b/flang/docs/Extensions.md @@ -134,6 +134,13 @@ end implicitly simply appearing in an asynchronous data transfer statement, without the attribute being visible in the procedure's explicit interface. +* When the name of an extended derived type's base type is the + result of `USE` association with renaming, the name of the extended + derived type's parent component is the new name by which the base + is known in the scope of the extended derived type, not the original. + This interpretation has usability advantages and is what six other + Fortran compilers do, but is not conforming now that J3 approved an + "interp" in June 2024 to the contrary. ## Extensions, deletions, and legacy features supported by default diff --git a/flang/lib/Parser/Fortran-parsers.cpp b/flang/lib/Parser/Fortran-parsers.cpp index 746d04a..0bdc4c4 100644 --- a/flang/lib/Parser/Fortran-parsers.cpp +++ b/flang/lib/Parser/Fortran-parsers.cpp @@ -1304,10 +1304,16 @@ TYPE_PARSER(extension<LanguageFeature::CUDA>(construct<CUDAAttributesStmt>( defaulted( maybe("::"_tok) >> nonemptyList("expected names"_err_en_US, name))))) -// Subtle: the name includes the surrounding slashes, which avoids +// Subtle: A structure's name includes the surrounding slashes, which avoids // clashes with other uses of the name in the same scope. -TYPE_PARSER(construct<StructureStmt>( - "STRUCTURE" >> maybe(sourced("/" >> name / "/")), optionalList(entityDecl))) +constexpr auto structureName{maybe(sourced("/" >> name / "/"))}; + +// Note that Parser<StructureStmt>{} has a mandatory list of entity-decls +// and is used only by NestedStructureStmt{}.Parse() in user-state.cpp. +TYPE_PARSER(construct<StructureStmt>("STRUCTURE" >> structureName, + localRecovery( + "entity declarations are required on a nested structure"_err_en_US, + nonemptyList(entityDecl), ok))) constexpr auto nestedStructureDef{ CONTEXT_PARSER("nested STRUCTURE definition"_en_US, @@ -1323,7 +1329,9 @@ TYPE_PARSER(construct<StructureField>(statement(StructureComponents{})) || TYPE_CONTEXT_PARSER("STRUCTURE definition"_en_US, extension<LanguageFeature::DECStructures>( "nonstandard usage: STRUCTURE"_port_en_US, - construct<StructureDef>(statement(Parser<StructureStmt>{}), + construct<StructureDef>( + statement(construct<StructureStmt>( + "STRUCTURE" >> structureName, optionalList(entityDecl))), many(Parser<StructureField>{}), statement(construct<StructureDef::EndStructureStmt>( "END STRUCTURE"_tok))))) diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp index ca6a823..aa45548 100644 --- a/flang/lib/Parser/prescan.cpp +++ b/flang/lib/Parser/prescan.cpp @@ -189,11 +189,19 @@ void Prescanner::Statement() { // a comment marker or directive sentinel. If so, disable line // continuation, so that NextToken() won't consume anything from // following lines. - if (IsLegalIdentifierStart(*at_) && NextToken(tokens) && - tokens.SizeInTokens() > 0) { - if (CharBlock id{tokens.TokenAt(0)}; preprocessor_.IsNameDefined(id) && + if (IsLegalIdentifierStart(*at_)) { + // TODO: Only bother with these cases when any keyword macro has + // been defined with replacement text that could begin a comment + // or directive sentinel. + const char *p{at_}; + while (IsLegalInIdentifier(*++p)) { + } + CharBlock id{at_, static_cast<std::size_t>(p - at_)}; + if (preprocessor_.IsNameDefined(id) && !preprocessor_.IsFunctionLikeDefinition(id)) { - if (auto replaced{preprocessor_.MacroReplacement(tokens, *this)}) { + TokenSequence toks; + toks.Put(id, GetProvenance(at_)); + if (auto replaced{preprocessor_.MacroReplacement(toks, *this)}) { auto newLineClass{ClassifyLine(*replaced, GetCurrentProvenance())}; disableSourceContinuation_ = newLineClass.kind != LineClassification::Kind::Source; diff --git a/flang/lib/Semantics/definable.cpp b/flang/lib/Semantics/definable.cpp index 96af46a..d594b1e 100644 --- a/flang/lib/Semantics/definable.cpp +++ b/flang/lib/Semantics/definable.cpp @@ -178,7 +178,10 @@ static std::optional<parser::Message> WhyNotDefinableBase(parser::CharBlock at, static std::optional<parser::Message> WhyNotDefinableLast(parser::CharBlock at, const Scope &scope, DefinabilityFlags flags, const Symbol &original) { const Symbol &ultimate{original.GetUltimate()}; - if (const auto *association{ultimate.detailsIf<AssocEntityDetails>()}) { + if (const auto *association{ultimate.detailsIf<AssocEntityDetails>()}; + association && + (association->rank().has_value() || + !flags.test(DefinabilityFlag::PointerDefinition))) { if (auto dataRef{ evaluate::ExtractDataRef(*association->expr(), true, true)}) { return WhyNotDefinableLast(at, scope, flags, dataRef->GetLastSymbol()); diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp index 2d91962..4413d77 100644 --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -4533,6 +4533,8 @@ std::optional<ProcedureRef> ArgumentAnalyzer::TryDefinedAssignment() { !OkLogicalIntegerAssignment(lhsType->category(), rhsType->category())) { SayNoMatch("ASSIGNMENT(=)", true); } + } else if (!fatalErrors_) { + CheckAssignmentConformance(); } return std::nullopt; } diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp index a11f444..5c5bca8 100644 --- a/flang/runtime/unit.cpp +++ b/flang/runtime/unit.cpp @@ -268,6 +268,7 @@ void ExternalFileUnit::FinishReadingRecord(IoErrorHandler &handler) { recordOffsetInFrame_ = 0; } BeginRecord(); + leftTabLimit.reset(); } bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) { diff --git a/flang/test/Preprocessing/directive-contin-with-pp.F90 b/flang/test/Preprocessing/directive-contin-with-pp.F90 index 64f1dc4..544c6619f 100644 --- a/flang/test/Preprocessing/directive-contin-with-pp.F90 +++ b/flang/test/Preprocessing/directive-contin-with-pp.F90 @@ -11,7 +11,7 @@ module m contains - subroutine s(x1, x2, x3, x4, x5, x6, x7) + subroutine s1(x1, x2, x3, x4, x5, x6, x7) !dir$ ignore_tkr x1 @@ -51,11 +51,18 @@ OMP_CONT reduction(+:x) do j3 = 1, n end do end -end + +COMMENT & + subroutine s2 + end subroutine +COMMENT& + subroutine s3 + end subroutine +end module !CHECK: MODULE m !CHECK: CONTAINS -!CHECK: SUBROUTINE s (x1, x2, x3, x4, x5, x6, x7) +!CHECK: SUBROUTINE s1 (x1, x2, x3, x4, x5, x6, x7) !CHECK: !DIR$ IGNORE_TKR x1 !CHECK: !DIR$ IGNORE_TKR x2 !CHECK: !DIR$ IGNORE_TKR x3 @@ -73,4 +80,8 @@ end !CHECK: DO j3=1_4,n !CHECK: END DO !CHECK: END SUBROUTINE +!CHECK: SUBROUTINE s2 +!CHECK: END SUBROUTINE +!CHECK: SUBROUTINE s3 +!CHECK: END SUBROUTINE !CHECK: END MODULE diff --git a/flang/test/Semantics/array-constr-values.f90 b/flang/test/Semantics/array-constr-values.f90 index b93f774..6742cd3 100644 --- a/flang/test/Semantics/array-constr-values.f90 +++ b/flang/test/Semantics/array-constr-values.f90 @@ -35,8 +35,10 @@ subroutine arrayconstructorvalues() intarray = [integer:: EMPLOYEE (19, "Jack"), 2, 3, 4, 5] ! C7112 + !ERROR: Dimension 1 of left-hand side has extent 3, but right-hand side has extent 2 !ERROR: Value in array constructor of type 'INTEGER(4)' could not be converted to the type of the array 'employee' emparray = (/ EMPLOYEE:: EMPLOYEE(19, "Ganesh"), EMPLOYEE(22, "Omkar"), 19 /) + !ERROR: Dimension 1 of left-hand side has extent 3, but right-hand side has extent 2 !ERROR: Value in array constructor of type 'employeer' could not be converted to the type of the array 'employee' emparray = (/ EMPLOYEE:: EMPLOYEE(19, "Ganesh"), EMPLOYEE(22, "Ram"),EMPLOYEER("ShriniwasPvtLtd") /) diff --git a/flang/test/Semantics/assign10.f90 b/flang/test/Semantics/assign10.f90 index 6b98097b..f0ea4b2 100644 --- a/flang/test/Semantics/assign10.f90 +++ b/flang/test/Semantics/assign10.f90 @@ -1,7 +1,11 @@ ! RUN: %python %S/test_errors.py %s %flang_fc1 ! Shape conformance checks on assignments program test + type t + integer n + end type real :: a0, a1a(2), a1b(3), a2a(2,3), a2b(3,2) + type(t) c(10) a0 = 0. ! ok !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches scalar REAL(4) and rank 1 array of REAL(4) a0 = [0.] @@ -20,4 +24,6 @@ program test a2a(1,:) = a1a !ERROR: Dimension 1 of left-hand side has extent 2, but right-hand side has extent 3 a2a = a2b + !ERROR: Dimension 1 of left-hand side has extent 10, but right-hand side has extent 0 + c(1:10) = c(10:1) end diff --git a/flang/test/Semantics/associate03.f90 b/flang/test/Semantics/associate03.f90 new file mode 100644 index 0000000..f57dc17 --- /dev/null +++ b/flang/test/Semantics/associate03.f90 @@ -0,0 +1,79 @@ +! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic +! A construct entity does not have the POINTER or ALLOCATABLE attribute, +! except in SELECT RANK. + +subroutine test(up,ua,rp,ra) + class(*), pointer :: up + class(*), allocatable :: ua + real, pointer :: rp(..) + real, allocatable :: ra(..) + real, target :: x + real, pointer :: p + real, allocatable :: a + associate (s => p) + !ERROR: The left-hand side of a pointer assignment is not definable + !BECAUSE: 's' is not a pointer + s => x + !ERROR: Entity in ALLOCATE statement must have the ALLOCATABLE or POINTER attribute + allocate(s) + !ERROR: Name in DEALLOCATE statement must have the ALLOCATABLE or POINTER attribute + deallocate(s) + !ERROR: 's' may not appear in NULLIFY + !BECAUSE: 's' is not a pointer + nullify(s) + end associate + select type(s => up) + type is (real) + !ERROR: The left-hand side of a pointer assignment is not definable + !BECAUSE: 's' is not a pointer + s => x + !ERROR: Entity in ALLOCATE statement must have the ALLOCATABLE or POINTER attribute + allocate(s) + !ERROR: Name in DEALLOCATE statement must have the ALLOCATABLE or POINTER attribute + deallocate(s) + !ERROR: 's' may not appear in NULLIFY + !BECAUSE: 's' is not a pointer + nullify(s) + end select + select rank(s => rp) + rank(0) + s => x ! ok + allocate(s) ! ok + deallocate(s) ! ok + nullify(s) ! ok + !ERROR: RANK (*) cannot be used when selector is POINTER or ALLOCATABLE + rank(*) + rank default + !ERROR: The left-hand side of a pointer assignment must not be an assumed-rank dummy argument + !ERROR: pointer 's' associated with object 'x' with incompatible type or shape + s => x + !ERROR: An assumed-rank dummy argument may not appear in an ALLOCATE statement + allocate(s) + deallocate(s) ! ok + nullify(s) ! ok + end select + associate (s => a) + !ERROR: Entity in ALLOCATE statement must have the ALLOCATABLE or POINTER attribute + allocate(s) + !ERROR: Name in DEALLOCATE statement must have the ALLOCATABLE or POINTER attribute + deallocate(s) + end associate + select type(s => ua) + type is (real) + !ERROR: Entity in ALLOCATE statement must have the ALLOCATABLE or POINTER attribute + allocate(s) + !ERROR: Name in DEALLOCATE statement must have the ALLOCATABLE or POINTER attribute + deallocate(s) + end select + select rank(s => ra) + rank(0) + allocate(s) ! ok + deallocate(s) ! ok + !ERROR: RANK (*) cannot be used when selector is POINTER or ALLOCATABLE + rank(*) + rank default + !ERROR: An assumed-rank dummy argument may not appear in an ALLOCATE statement + allocate(s) + deallocate(s) ! ok + end select +end diff --git a/flang/test/Semantics/parent-comp-name.f90 b/flang/test/Semantics/parent-comp-name.f90 new file mode 100644 index 0000000..d787843 --- /dev/null +++ b/flang/test/Semantics/parent-comp-name.f90 @@ -0,0 +1,70 @@ +! RUN: %python %S/test_errors.py %s %flang_fc1 +! Every other Fortran compiler (but one) interprets the names of parent +! components like this when the names of their types are the product of +! USE association with renaming. + +module m1 + type originalName + integer m + end type +end + +module m2 + use m1, newName => originalName + type, extends(newName) :: extended + integer n + end type + type, extends(newName) :: extended2 + integer originalName ! ok + end type + contains + subroutine s1 + type(extended) x + type(extended2) x2 + print *, x%newName%m ! ok + !ERROR: Component 'originalname' not found in derived type 'extended' + print *, x%originalName + print *, extended(newName=newName(m=1),n=2) ! ok + !ERROR: Structure constructor lacks a value for component 'm' + !ERROR: Keyword 'originalname=' does not name a component of derived type 'extended' + !ERROR: Keyword 'm=' may not appear in a reference to a procedure with an implicit interface + print *, extended(originalName=originalName(m=1),n=2) + !ERROR: Value in structure constructor of type 'REAL(4)' is incompatible with component 'newname' of type 'newname' + !ERROR: Keyword 'm=' may not appear in a reference to a procedure with an implicit interface + print *, extended(newName=originalName(m=1),n=2) + !ERROR: Structure constructor lacks a value for component 'm' + !ERROR: Keyword 'originalname=' does not name a component of derived type 'extended' + print *, extended(originalName=newName(m=1),n=2) + print *, x2%newName%m ! ok + print *, x2%originalName ! ok + print *, extended2(newName=newName(m=1),originalName=2) ! ok + end +end + +module m3 + use m2 + contains + ! Same as above, but not in the same module as the derived + ! types' definitions. + subroutine s2 + type(extended) x + type(extended2) x2 + print *, x%newName%m ! ok + !ERROR: Component 'originalname' not found in derived type 'extended' + print *, x%originalName + print *, extended(newName=newName(m=1),n=2) ! ok + !ERROR: Structure constructor lacks a value for component 'm' + !ERROR: Keyword 'originalname=' does not name a component of derived type 'extended' + !ERROR: Keyword 'm=' may not appear in a reference to a procedure with an implicit interface + print *, extended(originalName=originalName(m=1),n=2) + !ERROR: Value in structure constructor of type 'REAL(4)' is incompatible with component 'newname' of type 'newname' + !ERROR: Keyword 'm=' may not appear in a reference to a procedure with an implicit interface + print *, extended(newName=originalName(m=1),n=2) + !ERROR: Structure constructor lacks a value for component 'm' + !ERROR: Keyword 'originalname=' does not name a component of derived type 'extended' + print *, extended(originalName=newName(m=1),n=2) + print *, x2%newName%m ! ok + print *, x2%originalName ! ok + print *, extended2(newName=newName(m=1),originalName=2) ! ok + end +end diff --git a/flang/test/Semantics/struct03.f90 b/flang/test/Semantics/struct03.f90 new file mode 100644 index 0000000..a334cca --- /dev/null +++ b/flang/test/Semantics/struct03.f90 @@ -0,0 +1,7 @@ +! RUN: %python %S/test_errors.py %s %flang_fc1 + structure /s/ + !ERROR: entity declarations are required on a nested structure + structure /nested/ + end structure + end structure +end diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index 6ba5447..6e07607 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -73,6 +73,8 @@ if(LIBC_BUILD_GPU_LOADER OR (LLVM_LIBC_GPU_BUILD AND NOT LLVM_RUNTIMES_BUILD)) add_subdirectory(utils/gpu) endif() +option(LIBC_USE_NEW_HEADER_GEN "Generate header files using new headergen instead of the old one" OFF) + set(NEED_LIBC_HDRGEN FALSE) if(NOT LLVM_RUNTIMES_BUILD) if("libc" IN_LIST LLVM_ENABLE_RUNTIMES) diff --git a/libc/cmake/modules/LLVMLibCHeaderRules.cmake b/libc/cmake/modules/LLVMLibCHeaderRules.cmake index 7fc6860..3049f4d 100644 --- a/libc/cmake/modules/LLVMLibCHeaderRules.cmake +++ b/libc/cmake/modules/LLVMLibCHeaderRules.cmake @@ -66,7 +66,107 @@ function(add_header target_name) ) endfunction(add_header) -# A rule for generated header file targets. +function(add_gen_header2 target_name) + cmake_parse_arguments( + "ADD_GEN_HDR2" + "PUBLIC" # No optional arguments + "YAML_FILE;DEF_FILE;GEN_HDR" # Single value arguments + "DEPENDS" # Multi value arguments + ${ARGN} + ) + get_fq_target_name(${target_name} fq_target_name) + if(NOT LLVM_LIBC_FULL_BUILD) + add_library(${fq_target_name} INTERFACE) + return() + endif() + if(NOT ADD_GEN_HDR2_DEF_FILE) + message(FATAL_ERROR "`add_gen_hdr2` rule requires DEF_FILE to be specified.") + endif() + if(NOT ADD_GEN_HDR2_GEN_HDR) + message(FATAL_ERROR "`add_gen_hdr2` rule requires GEN_HDR to be specified.") + endif() + if(NOT ADD_GEN_HDR2_YAML_FILE) + message(FATAL_ERROR "`add_gen_hdr2` rule requires YAML_FILE to be specified.") + endif() + + set(absolute_path ${CMAKE_CURRENT_SOURCE_DIR}/${ADD_GEN_HDR2_GEN_HDR}) + file(RELATIVE_PATH relative_path ${LIBC_INCLUDE_SOURCE_DIR} ${absolute_path}) + set(out_file ${LIBC_INCLUDE_DIR}/${relative_path}) + set(yaml_file ${CMAKE_SOURCE_DIR}/${ADD_GEN_HDR2_YAML_FILE}) + set(def_file ${CMAKE_CURRENT_SOURCE_DIR}/${ADD_GEN_HDR2_DEF_FILE}) + + set(fq_data_files "") + if(ADD_GEN_HDR2_DATA_FILES) + foreach(data_file IN LISTS ADD_GEN_HDR2_DATA_FILES) + list(APPEND fq_data_files "${CMAKE_CURRENT_SOURCE_DIR}/${data_file}") + endforeach(data_file) + endif() + + set(entry_points "${TARGET_ENTRYPOINT_NAME_LIST}") + list(TRANSFORM entry_points PREPEND "--e=") + + add_custom_command( + OUTPUT ${out_file} + COMMAND ${Python3_EXECUTABLE} ${LIBC_SOURCE_DIR}/newhdrgen/yaml_to_classes.py + ${yaml_file} + --h_def_file ${def_file} + ${entry_points} + --output_dir ${out_file} + DEPENDS ${yaml_file} ${def_file} ${fq_data_files} + COMMENT "Generating header ${ADD_GEN_HDR2_GE2N_HDR} from ${yaml_file} and ${def_file}" + ) + if(LIBC_TARGET_OS_IS_GPU) + file(MAKE_DIRECTORY ${LIBC_INCLUDE_DIR}/llvm-libc-decls) + file(MAKE_DIRECTORY ${LIBC_INCLUDE_DIR}/llvm-libc-decls/gpu) + set(decl_out_file ${LIBC_INCLUDE_DIR}/llvm-libc-decls/${relative_path}) + add_custom_command( + OUTPUT ${decl_out_file} + COMMAND ${Python3_EXECUTABLE} ${LIBC_SOURCE_DIR}/newhdrgen/yaml_to_classes.py + ${yaml_file} + --export-decls + ${entry_points} + --output_dir ${decl_out_file} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${yaml_file} ${fq_data_files} + ) + endif() + + if(ADD_GEN_HDR2_DEPENDS) + get_fq_deps_list(fq_deps_list ${ADD_GEN_HDR2_DEPENDS}) + # Dependencies of a add_header target can only be another add_gen_header target + # or an add_header target. + foreach(dep IN LISTS fq_deps_list) + get_target_property(header_file ${dep} HEADER_FILE_PATH) + if(NOT header_file) + message(FATAL_ERROR "Invalid dependency '${dep}' for '${fq_target_name}'.") + endif() + endforeach() + endif() + set(generated_hdr_target ${fq_target_name}.__generated_hdr__) + add_custom_target( + ${generated_hdr_target} + DEPENDS ${out_file} ${fq_deps_list} ${decl_out_file} + ) + + add_header_library( + ${target_name} + HDRS + ${out_file} + ) + + add_dependencies(${fq_target_name} ${generated_hdr_target}) + + set_target_properties( + ${fq_target_name} + PROPERTIES + HEADER_FILE_PATH ${out_file} + DECLS_FILE_PATH "${decl_out_file}" + DEPS "${fq_deps_list}" + ) + + +endfunction(add_gen_header2) + # Usage: # add_gen_header( # <target name> diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td index a10dec0..320f3e9 100644 --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -267,5 +267,5 @@ def SearchAPI : PublicAPI<"search.h"> { } def SysStatvfsAPI : PublicAPI<"sys/statvfs.h"> { - let Types = ["fsblkcnt_t", "fsfilcnt_t", "struct statvfs"]; + let Types = ["struct statvfs"]; } diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt index 8a52d80e..0294f62 100644 --- a/libc/config/linux/x86_64/headers.txt +++ b/libc/config/linux/x86_64/headers.txt @@ -45,8 +45,7 @@ set(TARGET_PUBLIC_HEADERS libc.include.sys_select libc.include.sys_socket libc.include.sys_stat - # statvfs is broken, will uncomment once it's fixed. - # libc.include.sys_statvfs + libc.include.sys_statvfs libc.include.sys_syscall libc.include.sys_time libc.include.sys_types diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt index 2cf7206..37cae19 100644 --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -17,18 +17,41 @@ add_header( __llvm-libc-common.h ) -add_gen_header( +macro(add_header_macro TARGET_NAME YAML_FILE DEF_FILE GEN_HDR DEPENDS) + if (LIBC_USE_NEW_HEADER_GEN) + add_gen_header2( + ${TARGET_NAME} + YAML_FILE ${YAML_FILE} + DEF_FILE ${DEF_FILE} + GEN_HDR ${GEN_HDR} + ${DEPENDS} + ${ARGN} + ) + else() + add_gen_header( + ${TARGET_NAME} + DEF_FILE ${DEF_FILE} + GEN_HDR ${GEN_HDR} + ${DEPENDS} + ${ARGN} + ) + endif() +endmacro() + +add_header_macro( ctype - DEF_FILE ctype.h.def - GEN_HDR ctype.h + ../libc/newhdrgen/yaml/ctype.yaml + ctype.h.def + ctype.h DEPENDS .llvm_libc_common_h ) -add_gen_header( +add_header_macro( dirent - DEF_FILE dirent.h.def - GEN_HDR dirent.h + ../libc/newhdrgen/yaml/dirent.yaml + dirent.h.def + dirent.h DEPENDS .llvm_libc_common_h .llvm-libc-types.ino_t @@ -36,10 +59,11 @@ add_gen_header( .llvm-libc-types.struct_dirent ) -add_gen_header( +add_header_macro( fcntl - DEF_FILE fcntl.h.def - GEN_HDR fcntl.h + ../libc/newhdrgen/yaml/fcntl.yaml + fcntl.h.def + fcntl.h DEPENDS .llvm-libc-macros.fcntl_macros .llvm-libc-types.mode_t @@ -51,28 +75,31 @@ add_gen_header( .llvm_libc_common_h ) -add_gen_header( +add_header_macro( dlfcn - DEF_FILE dlfcn.h.def - GEN_HDR dlfcn.h + ../libc/newhdrgen/yaml/dlfcn.yaml + dlfcn.h.def + dlfcn.h DEPENDS .llvm-libc-macros.dlfcn_macros .llvm_libc_common_h ) -add_gen_header( +add_header_macro( features - DEF_FILE features.h.def - GEN_HDR features.h + ../libc/newhdrgen/yaml/features.yaml + features.h.def + features.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.features_macros ) -add_gen_header( +add_header_macro( fenv - DEF_FILE fenv.h.def - GEN_HDR fenv.h + ../libc/newhdrgen/yaml/fenv.yaml + fenv.h.def + fenv.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.fenv_macros @@ -80,44 +107,49 @@ add_gen_header( .llvm-libc-types.fexcept_t ) -add_gen_header( +add_header_macro( inttypes - DEF_FILE inttypes.h.def - GEN_HDR inttypes.h + ../libc/newhdrgen/yaml/inttypes.yaml + inttypes.h.def + inttypes.h DEPENDS .llvm_libc_common_h .llvm-libc-types.imaxdiv_t .llvm-libc-macros.inttypes_macros ) -add_gen_header( +add_header_macro( float - DEF_FILE float.h.def - GEN_HDR float.h + ../libc/newhdrgen/yaml/float.yaml + float.h.def + float.h DEPENDS .llvm-libc-macros.float_macros ) -add_gen_header( +add_header_macro( stdint - DEF_FILE stdint.h.def - GEN_HDR stdint.h + ../libc/newhdrgen/yaml/stdint.yaml + stdint.h.def + stdint.h DEPENDS .llvm-libc-macros.stdint_macros ) -add_gen_header( +add_header_macro( limits - DEF_FILE limits.h.def - GEN_HDR limits.h + ../libc/newhdrgen/yaml/limits.yaml + limits.h.def + limits.h DEPENDS .llvm-libc-macros.limits_macros ) -add_gen_header( +add_header_macro( math - DEF_FILE math.h.def - GEN_HDR math.h + ../libc/newhdrgen/yaml/math.yaml + math.h.def + math.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.float16_macros @@ -128,10 +160,11 @@ add_gen_header( .llvm-libc-types.float128 ) -add_gen_header( +add_header_macro( stdfix - DEF_FILE stdfix.h.def - GEN_HDR stdfix.h + ../libc/newhdrgen/yaml/stdfix.yaml + stdfix.h.def + stdfix.h DEPENDS .llvm-libc-macros.stdfix_macros ) @@ -139,55 +172,61 @@ add_gen_header( # TODO: This should be conditional on POSIX networking being included. file(MAKE_DIRECTORY ${LIBC_INCLUDE_DIR}/arpa) -add_gen_header( +add_header_macro( arpa_inet - DEF_FILE arpa/inet.h.def - GEN_HDR arpa/inet.h + ../libc/newhdrgen/yaml/arpa/inet.yaml + arpa/inet.h.def + arpa/inet.h DEPENDS .llvm_libc_common_h ) -add_gen_header( +add_header_macro( assert - DEF_FILE assert.h.def - GEN_HDR assert.h + ../libc/newhdrgen/yaml/assert.yaml + assert.h.def + assert.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.assert_macros ) -add_gen_header( +add_header_macro( setjmp - DEF_FILE setjmp.h.def - GEN_HDR setjmp.h + ../libc/newhdrgen/yaml/setjmp.yaml + setjmp.h.def + setjmp.h DEPENDS .llvm_libc_common_h .llvm-libc-types.jmp_buf ) -add_gen_header( +add_header_macro( string - DEF_FILE string.h.def - GEN_HDR string.h + ../libc/newhdrgen/yaml/string.yaml + string.h.def + string.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.null_macro .llvm-libc-types.size_t ) -add_gen_header( +add_header_macro( strings - DEF_FILE strings.h.def - GEN_HDR strings.h + ../libc/newhdrgen/yaml/strings.yaml + strings.h.def + strings.h DEPENDS .llvm_libc_common_h .llvm-libc-types.size_t ) -add_gen_header( +add_header_macro( search - DEF_FILE search.h.def - GEN_HDR search.h + ../libc/newhdrgen/yaml/search.yaml + search.h.def + search.h DEPENDS .llvm_libc_common_h .llvm-libc-types.ACTION @@ -196,10 +235,11 @@ add_gen_header( .llvm-libc-types.size_t ) -add_gen_header( +add_header_macro( time - DEF_FILE time.h.def - GEN_HDR time.h + ../libc/newhdrgen/yaml/time.yaml + time.h.def + time.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.time_macros @@ -211,10 +251,11 @@ add_gen_header( .llvm-libc-types.clockid_t ) -add_gen_header( +add_header_macro( threads - DEF_FILE threads.h.def - GEN_HDR threads.h + ../libc/newhdrgen/yaml/threads.yaml + threads.h.def + threads.h DEPENDS .llvm_libc_common_h .llvm-libc-types.__call_once_func_t @@ -227,19 +268,21 @@ add_gen_header( .llvm-libc-types.tss_dtor_t ) -add_gen_header( +add_header_macro( errno - DEF_FILE errno.h.def - GEN_HDR errno.h + ../libc/newhdrgen/yaml/errno.yaml + errno.h.def + errno.h DEPENDS .llvm-libc-macros.generic_error_number_macros .llvm-libc-macros.error_number_macros ) -add_gen_header( +add_header_macro( signal - DEF_FILE signal.h.def - GEN_HDR signal.h + ../libc/newhdrgen/yaml/signal.yaml + signal.h.def + signal.h DEPENDS .llvm-libc-macros.signal_macros .llvm-libc-types.sig_atomic_t @@ -251,28 +294,31 @@ add_gen_header( .llvm-libc-types.pid_t ) -add_gen_header( +add_header_macro( stdbit - DEF_FILE stdbit.h.def - GEN_HDR stdbit.h + ../libc/newhdrgen/yaml/stdbit.yaml + stdbit.h.def + stdbit.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.stdbit_macros ) -add_gen_header( +add_header_macro( stdckdint - DEF_FILE stdckdint.h.def - GEN_HDR stdckdint.h + ../libc/newhdrgen/yaml/stdckdint.yaml + stdckdint.h.def + stdckdint.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.stdckdint_macros ) -add_gen_header( +add_header_macro( stdio - DEF_FILE stdio.h.def - GEN_HDR stdio.h + ../libc/newhdrgen/yaml/stdio.yaml + stdio.h.def + stdio.h DEPENDS .llvm-libc-macros.file_seek_macros .llvm-libc-macros.stdio_macros @@ -284,10 +330,11 @@ add_gen_header( .llvm_libc_common_h ) -add_gen_header( +add_header_macro( stdlib - DEF_FILE stdlib.h.def - GEN_HDR stdlib.h + ../libc/newhdrgen/yaml/stdlib.yaml + stdlib.h.def + stdlib.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.stdlib_macros @@ -301,10 +348,11 @@ add_gen_header( .llvm-libc-types.__atexithandler_t ) -add_gen_header( +add_header_macro( unistd - DEF_FILE unistd.h.def - GEN_HDR unistd.h + ../libc/newhdrgen/yaml/unistd.yaml + unistd.h.def + unistd.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.file_seek_macros @@ -319,10 +367,11 @@ add_gen_header( .llvm-libc-types.__getoptargv_t ) -add_gen_header( +add_header_macro( pthread - DEF_FILE pthread.h.def - GEN_HDR pthread.h + ../libc/newhdrgen/yaml/pthread.yaml + pthread.h.def + pthread.h DEPENDS .llvm_libc_common_h .llvm-libc-types.__atfork_callback_t @@ -340,10 +389,11 @@ add_gen_header( .llvm-libc-types.pthread_t ) -add_gen_header( +add_header_macro( sched - DEF_FILE sched.h.def - GEN_HDR sched.h + ../libc/newhdrgen/yaml/sched.yaml + sched.h.def + sched.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.sched_macros @@ -356,10 +406,11 @@ add_gen_header( .llvm-libc-types.struct_timespec ) -add_gen_header( +add_header_macro( spawn - DEF_FILE spawn.h.def - GEN_HDR spawn.h + ../libc/newhdrgen/yaml/spawn.yaml + spawn.h.def + spawn.h DEPENDS .llvm_libc_common_h .llvm-libc-types.mode_t @@ -373,19 +424,21 @@ add_gen_header( # them. file(MAKE_DIRECTORY ${LIBC_INCLUDE_DIR}/sys) -add_gen_header( +add_header_macro( sys_auxv - DEF_FILE sys/auxv.h.def - GEN_HDR sys/auxv.h + ../libc/newhdrgen/yaml/sys/auxv.yaml + sys/auxv.h.def + sys/auxv.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.sys_auxv_macros ) -add_gen_header( +add_header_macro( sys_epoll - DEF_FILE sys/epoll.h.def - GEN_HDR sys/epoll.h + ../libc/newhdrgen/yaml/sys/epoll.yaml + sys/epoll.h.def + sys/epoll.h DEPENDS .llvm_libc_common_h .llvm-libc-types.struct_epoll_event @@ -394,19 +447,21 @@ add_gen_header( .llvm-libc-macros.sys_epoll_macros ) -add_gen_header( +add_header_macro( sys_ioctl - DEF_FILE sys/ioctl.h.def - GEN_HDR sys/ioctl.h + ../libc/newhdrgen/yaml/sys/ioctl.yaml + sys/ioctl.h.def + sys/ioctl.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.sys_ioctl_macros ) -add_gen_header( +add_header_macro( sys_mman - DEF_FILE sys/mman.h.def - GEN_HDR sys/mman.h + ../libc/newhdrgen/yaml/sys/mman.yaml + sys/mman.h.def + sys/mman.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.sys_mman_macros @@ -415,10 +470,11 @@ add_gen_header( .llvm-libc-types.ssize_t ) -add_gen_header( +add_header_macro( sys_prctl - DEF_FILE sys/prctl.h.def - GEN_HDR sys/prctl.h + ../libc/newhdrgen/yaml/sys/prctl.yaml + sys/prctl.h.def + sys/prctl.h DEPENDS .llvm_libc_common_h ) @@ -431,10 +487,11 @@ add_header( .llvm-libc-macros.sys_queue_macros ) -add_gen_header( +add_header_macro( sys_random - DEF_FILE sys/random.h.def - GEN_HDR sys/random.h + ../libc/newhdrgen/yaml/sys/random.yaml + sys/random.h.def + sys/random.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.sys_random_macros @@ -442,10 +499,11 @@ add_gen_header( .llvm-libc-types.ssize_t ) -add_gen_header( +add_header_macro( sys_resource - DEF_FILE sys/resource.h.def - GEN_HDR sys/resource.h + ../libc/newhdrgen/yaml/sys/resource.yaml + sys/resource.h.def + sys/resource.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.sys_resource_macros @@ -453,10 +511,11 @@ add_gen_header( .llvm-libc-types.struct_rlimit ) -add_gen_header( +add_header_macro( sys_stat - DEF_FILE sys/stat.h.def - GEN_HDR sys/stat.h + ../libc/newhdrgen/yaml/sys/stat.yaml + sys/stat.h.def + sys/stat.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.sys_stat_macros @@ -474,10 +533,11 @@ add_gen_header( .llvm-libc-types.struct_stat ) -add_gen_header( +add_header_macro( sys_select - DEF_FILE sys/select.h.def - GEN_HDR sys/select.h + ../libc/newhdrgen/yaml/sys/select.yaml + sys/select.h.def + sys/select.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.sys_select_macros @@ -489,10 +549,11 @@ add_gen_header( .llvm-libc-types.struct_timeval ) -add_gen_header( +add_header_macro( sys_sendfile - DEF_FILE sys/sendfile.h.def - GEN_HDR sys/sendfile.h + ../libc/newhdrgen/yaml/sys/sendfile.yaml + sys/sendfile.h.def + sys/sendfile.h DEPENDS .llvm_libc_common_h .llvm-libc-types.off_t @@ -500,10 +561,11 @@ add_gen_header( .llvm-libc-types.ssize_t ) -add_gen_header( +add_header_macro( sys_socket - DEF_FILE sys/socket.h.def - GEN_HDR sys/socket.h + ../libc/newhdrgen/yaml/sys/socket.yaml + sys/socket.h.def + sys/socket.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.sys_socket_macros @@ -513,35 +575,40 @@ add_gen_header( .llvm-libc-types.struct_sockaddr_un ) -add_gen_header( +add_header_macro( sys_statvfs - DEF_FILE sys/statvfs.h.def - GEN_HDR sys/statvfs.h + ../libc/newhdrgen/yaml/sys/statvfs.yaml + sys/statvfs.h.def + sys/statvfs.h DEPENDS .llvm_libc_common_h .llvm-libc-types.struct_statvfs ) -add_gen_header( +add_header_macro( sys_syscall - DEF_FILE sys/syscall.h.def - GEN_HDR sys/syscall.h + ../libc/newhdrgen/yaml/sys/syscall.yaml + sys/syscall.h.def + sys/syscall.h + DEPENDS ) -add_gen_header( +add_header_macro( sys_time - DEF_FILE sys/time.h.def - GEN_HDR sys/time.h + ../libc/newhdrgen/yaml/sys/time.yaml + sys/time.h.def + sys/time.h DEPENDS .llvm_libc_common_h .llvm-libc-types.struct_timeval .llvm-libc-macros.sys_time_macros ) -add_gen_header( +add_header_macro( sys_types - DEF_FILE sys/types.h.def - GEN_HDR sys/types.h + ../libc/newhdrgen/yaml/sys/types.yaml + sys/types.h.def + sys/types.h DEPENDS .llvm_libc_common_h .llvm-libc-types.blkcnt_t @@ -567,19 +634,21 @@ add_gen_header( .llvm-libc-types.uid_t ) -add_gen_header( +add_header_macro( sys_utsname - DEF_FILE sys/utsname.h.def - GEN_HDR sys/utsname.h + ../libc/newhdrgen/yaml/sys/utsname.yaml + sys/utsname.h.def + sys/utsname.h DEPENDS .llvm_libc_common_h .llvm-libc-types.struct_utsname ) -add_gen_header( +add_header_macro( sys_wait - DEF_FILE sys/wait.h.def - GEN_HDR sys/wait.h + ../libc/newhdrgen/yaml/sys/wait.yaml + sys/wait.h.def + sys/wait.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.sys_wait_macros @@ -588,10 +657,11 @@ add_gen_header( .llvm-libc-types.siginfo_t ) -add_gen_header( +add_header_macro( termios - DEF_FILE termios.h.def - GEN_HDR termios.h + ../libc/newhdrgen/yaml/termios.yaml + termios.h.def + termios.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.termios_macros @@ -602,10 +672,11 @@ add_gen_header( .llvm-libc-types.tcflag_t ) -add_gen_header( +add_header_macro( uchar - DEF_FILE uchar.h.def - GEN_HDR uchar.h + ../libc/newhdrgen/yaml/uchar.yaml + uchar.h.def + uchar.h DEPENDS .llvm_libc_common_h .llvm-libc-types.mbstate_t @@ -614,10 +685,11 @@ add_gen_header( .llvm-libc-types.char32_t ) -add_gen_header( +add_header_macro( wchar - DEF_FILE wchar.h.def - GEN_HDR wchar.h + ../libc/newhdrgen/yaml/wchar.yaml + wchar.h.def + wchar.h DEPENDS .llvm_libc_common_h .llvm-libc-macros.wchar_macros @@ -630,10 +702,11 @@ add_gen_header( if(LIBC_TARGET_OS_IS_GPU) file(MAKE_DIRECTORY ${LIBC_INCLUDE_DIR}/gpu) - add_gen_header( + add_header_macro( gpu_rpc - DEF_FILE gpu/rpc.h.def - GEN_HDR gpu/rpc.h + ../libc/newhdrgen/yaml/gpu/rpc.yaml + gpu/rpc.h.def + gpu/rpc.h DEPENDS .llvm_libc_common_h .llvm-libc-types.rpc_opcodes_t diff --git a/libc/newhdrgen/class_implementation/classes/include.py b/libc/newhdrgen/class_implementation/classes/include.py deleted file mode 100644 index 2657f2e..0000000 --- a/libc/newhdrgen/class_implementation/classes/include.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python -# -# ====-- Include class for libc function headers --------------*- python -*--==# -# -# 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 -# -# ==-------------------------------------------------------------------------==# - - -class Include: - def __init__(self, name): - self.name = name - - def __str__(self): - return f'#include "{self.name}"' diff --git a/libc/newhdrgen/gpu_headers.py b/libc/newhdrgen/gpu_headers.py index cc13096..d123e4a 100644 --- a/libc/newhdrgen/gpu_headers.py +++ b/libc/newhdrgen/gpu_headers.py @@ -17,7 +17,6 @@ class GpuHeaderFile: self.enumerations = [] self.objects = [] self.functions = [] - self.includes = [] def add_macro(self, macro): self.macros.append(macro) diff --git a/libc/newhdrgen/header.py b/libc/newhdrgen/header.py index 141e3c9..7ec2dee 100644 --- a/libc/newhdrgen/header.py +++ b/libc/newhdrgen/header.py @@ -17,7 +17,6 @@ class HeaderFile: self.enumerations = [] self.objects = [] self.functions = [] - self.includes = [] def add_macro(self, macro): self.macros.append(macro) @@ -34,15 +33,9 @@ class HeaderFile: def add_function(self, function): self.functions.append(function) - def add_include(self, include): - self.includes.append(include) - def __str__(self): content = [""] - for include in self.includes: - content.append(str(include)) - for macro in self.macros: content.append(f"{macro}\n") diff --git a/libc/newhdrgen/yaml/arpa/arpa_inet.yaml b/libc/newhdrgen/yaml/arpa/inet.yaml index c01235d..c01235d 100644 --- a/libc/newhdrgen/yaml/arpa/arpa_inet.yaml +++ b/libc/newhdrgen/yaml/arpa/inet.yaml diff --git a/libc/newhdrgen/yaml/gpu/gpu_rpc.yaml b/libc/newhdrgen/yaml/gpu/rpc.yaml index 8a096db..8a096db 100644 --- a/libc/newhdrgen/yaml/gpu/gpu_rpc.yaml +++ b/libc/newhdrgen/yaml/gpu/rpc.yaml diff --git a/libc/newhdrgen/yaml/math.yaml b/libc/newhdrgen/yaml/math.yaml index 8588389b..ce562c6 100644 --- a/libc/newhdrgen/yaml/math.yaml +++ b/libc/newhdrgen/yaml/math.yaml @@ -64,8 +64,6 @@ functions: return_type: double arguments: - type: double - attributes: - - __LIBC_CONST_ATTR - name: fabsf standards: - stdc @@ -364,6 +362,20 @@ functions: arguments: - type: double - type: double + - name: fmull + standards: + - stdc + return_type: float + arguments: + - type: long double + - type: long double + - name: dmull + standards: + - stdc + return_type: double + arguments: + - type: long double + - type: long double - name: frexp standards: - stdc @@ -1323,6 +1335,30 @@ functions: - type: long double - type: long double guard: LIBC_TYPES_HAS_FLOAT16 + - name: f16mul + standards: + - llvm_libc_ext + return_type: _Float16 + arguments: + - type: double + - type: double + guard: LIBC_TYPES_HAS_FLOAT16 + - name: f16mulf + standards: + - llvm_libc_ext + return_type: _Float16 + arguments: + - type: float + - type: float + guard: LIBC_TYPES_HAS_FLOAT16 + - name: f16mull + standards: + - llvm_libc_ext + return_type: _Float16 + arguments: + - type: long double + - type: long double + guard: LIBC_TYPES_HAS_FLOAT16 - name: f16sqrt standards: - llvm_libc_ext @@ -1756,6 +1792,14 @@ functions: - type: float128 - type: float128 guard: LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128 + - name: f16mulf128 + standards: + - stdc + return_type: _Float16 + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128 - name: f16sqrtf128 standards: - llvm_libc_ext @@ -1896,6 +1940,22 @@ functions: - type: float128 - type: float128 guard: LIBC_TYPES_HAS_FLOAT128 + - name: fmulf128 + standards: + - llvm_libc_ext + return_type: float + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: dmulf128 + standards: + - llvm_libc_ext + return_type: double + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 - name: frexpf128 standards: - stdc diff --git a/libc/newhdrgen/yaml/sys/sys_auxv.yaml b/libc/newhdrgen/yaml/sys/auxv.yaml index 072f63b..072f63b 100644 --- a/libc/newhdrgen/yaml/sys/sys_auxv.yaml +++ b/libc/newhdrgen/yaml/sys/auxv.yaml diff --git a/libc/newhdrgen/yaml/sys/sys_epoll.yaml b/libc/newhdrgen/yaml/sys/epoll.yaml index 18d8f59..18d8f59 100644 --- a/libc/newhdrgen/yaml/sys/sys_epoll.yaml +++ b/libc/newhdrgen/yaml/sys/epoll.yaml diff --git a/libc/newhdrgen/yaml/sys/sys_ioctl.yaml b/libc/newhdrgen/yaml/sys/ioctl.yaml index ffe73a8..ffe73a8 100644 --- a/libc/newhdrgen/yaml/sys/sys_ioctl.yaml +++ b/libc/newhdrgen/yaml/sys/ioctl.yaml diff --git a/libc/newhdrgen/yaml/sys/sys_mman.yaml b/libc/newhdrgen/yaml/sys/mman.yaml index c465f6b..c465f6b 100644 --- a/libc/newhdrgen/yaml/sys/sys_mman.yaml +++ b/libc/newhdrgen/yaml/sys/mman.yaml diff --git a/libc/newhdrgen/yaml/sys/sys_prctl.yaml b/libc/newhdrgen/yaml/sys/prctl.yaml index 82374be..82374be 100644 --- a/libc/newhdrgen/yaml/sys/sys_prctl.yaml +++ b/libc/newhdrgen/yaml/sys/prctl.yaml diff --git a/libc/newhdrgen/yaml/sys/sys_random.yaml b/libc/newhdrgen/yaml/sys/random.yaml index 6d84056..6d84056 100644 --- a/libc/newhdrgen/yaml/sys/sys_random.yaml +++ b/libc/newhdrgen/yaml/sys/random.yaml diff --git a/libc/newhdrgen/yaml/sys/sys_resource.yaml b/libc/newhdrgen/yaml/sys/resource.yaml index 2cc801c..2cc801c 100644 --- a/libc/newhdrgen/yaml/sys/sys_resource.yaml +++ b/libc/newhdrgen/yaml/sys/resource.yaml diff --git a/libc/newhdrgen/yaml/sys/sys_select.yaml b/libc/newhdrgen/yaml/sys/select.yaml index eb621f7..eb621f7 100644 --- a/libc/newhdrgen/yaml/sys/sys_select.yaml +++ b/libc/newhdrgen/yaml/sys/select.yaml diff --git a/libc/newhdrgen/yaml/sys/sys_sendfile.yaml b/libc/newhdrgen/yaml/sys/sendfile.yaml index 8743bf0..8743bf0 100644 --- a/libc/newhdrgen/yaml/sys/sys_sendfile.yaml +++ b/libc/newhdrgen/yaml/sys/sendfile.yaml diff --git a/libc/newhdrgen/yaml/sys/sys_socket.yaml b/libc/newhdrgen/yaml/sys/socket.yaml index f9984c6..f9984c6 100644 --- a/libc/newhdrgen/yaml/sys/sys_socket.yaml +++ b/libc/newhdrgen/yaml/sys/socket.yaml diff --git a/libc/newhdrgen/yaml/sys/sys_stat.yaml b/libc/newhdrgen/yaml/sys/stat.yaml index 6ae69b4..6ae69b4 100644 --- a/libc/newhdrgen/yaml/sys/sys_stat.yaml +++ b/libc/newhdrgen/yaml/sys/stat.yaml diff --git a/libc/newhdrgen/yaml/sys/sys_statvfs.yaml b/libc/newhdrgen/yaml/sys/statvfs.yaml index 3651901..5366677 100644 --- a/libc/newhdrgen/yaml/sys/sys_statvfs.yaml +++ b/libc/newhdrgen/yaml/sys/statvfs.yaml @@ -2,6 +2,8 @@ header: sys-statvfs.h macros: [] types: - type_name: struct_statvfs + - type_name: fsblkcnt_t + - type_name: fsfilcnt_t enums: [] objects: [] functions: diff --git a/libc/newhdrgen/yaml/sys/sys_syscall.yaml b/libc/newhdrgen/yaml/sys/syscall.yaml index c0a64338..c0a64338 100644 --- a/libc/newhdrgen/yaml/sys/sys_syscall.yaml +++ b/libc/newhdrgen/yaml/sys/syscall.yaml diff --git a/libc/newhdrgen/yaml/sys/sys_time.yaml b/libc/newhdrgen/yaml/sys/time.yaml index eb3dd54..eb3dd54 100644 --- a/libc/newhdrgen/yaml/sys/sys_time.yaml +++ b/libc/newhdrgen/yaml/sys/time.yaml diff --git a/libc/newhdrgen/yaml/sys/sys_types.yaml b/libc/newhdrgen/yaml/sys/types.yaml index 15eaf10..15eaf10 100644 --- a/libc/newhdrgen/yaml/sys/sys_types.yaml +++ b/libc/newhdrgen/yaml/sys/types.yaml diff --git a/libc/newhdrgen/yaml/sys/sys_utsname.yaml b/libc/newhdrgen/yaml/sys/utsname.yaml index c48f7e3..c48f7e3 100644 --- a/libc/newhdrgen/yaml/sys/sys_utsname.yaml +++ b/libc/newhdrgen/yaml/sys/utsname.yaml diff --git a/libc/newhdrgen/yaml/sys/sys_wait.yaml b/libc/newhdrgen/yaml/sys/wait.yaml index 2f2f70d..2f2f70d 100644 --- a/libc/newhdrgen/yaml/sys/sys_wait.yaml +++ b/libc/newhdrgen/yaml/sys/wait.yaml diff --git a/libc/newhdrgen/yaml_to_classes.py b/libc/newhdrgen/yaml_to_classes.py index 205bb35..7858805 100644 --- a/libc/newhdrgen/yaml_to_classes.py +++ b/libc/newhdrgen/yaml_to_classes.py @@ -16,7 +16,6 @@ from gpu_headers import GpuHeaderFile as GpuHeader from class_implementation.classes.macro import Macro from class_implementation.classes.type import Type from class_implementation.classes.function import Function -from class_implementation.classes.include import Include from class_implementation.classes.enumeration import Enumeration from class_implementation.classes.object import Object @@ -103,9 +102,6 @@ def yaml_to_classes(yaml_data, header_class, entry_points=None): Object(object_data["object_name"], object_data["object_type"]) ) - for include_data in yaml_data.get("includes", []): - header.add_include(Include(include_data)) - return header diff --git a/libc/src/sys/statvfs/linux/CMakeLists.txt b/libc/src/sys/statvfs/linux/CMakeLists.txt index a6660c0..2953717 100644 --- a/libc/src/sys/statvfs/linux/CMakeLists.txt +++ b/libc/src/sys/statvfs/linux/CMakeLists.txt @@ -8,7 +8,7 @@ add_header_library( libc.src.__support.common libc.src.__support.CPP.optional libc.include.sys_syscall - libc.include.llvm-libc-types.struct_statvfs + libc.include.sys_statvfs ) add_entrypoint_object( @@ -19,7 +19,7 @@ add_entrypoint_object( ../statvfs.h DEPENDS libc.src.__support.libc_assert - libc.include.llvm-libc-types.struct_statvfs + libc.include.sys_statvfs .statfs_utils ) @@ -31,7 +31,7 @@ add_entrypoint_object( ../fstatvfs.h DEPENDS libc.src.__support.libc_assert - libc.include.llvm-libc-types.struct_statvfs + libc.include.sys_statvfs .statfs_utils ) diff --git a/libc/utils/MPFRWrapper/CMakeLists.txt b/libc/utils/MPFRWrapper/CMakeLists.txt index e74b022..be0415d 100644 --- a/libc/utils/MPFRWrapper/CMakeLists.txt +++ b/libc/utils/MPFRWrapper/CMakeLists.txt @@ -1,5 +1,5 @@ if(LIBC_TESTS_CAN_USE_MPFR) - add_library(libcMPFRWrapper + add_library(libcMPFRWrapper STATIC MPFRUtils.cpp MPFRUtils.h mpfr_inc.h diff --git a/libcxx/benchmarks/CMakeLists.txt b/libcxx/benchmarks/CMakeLists.txt index 1106726..d96ccc1 100644 --- a/libcxx/benchmarks/CMakeLists.txt +++ b/libcxx/benchmarks/CMakeLists.txt @@ -135,6 +135,7 @@ set(BENCHMARK_TESTS algorithms/ranges_sort.bench.cpp algorithms/ranges_sort_heap.bench.cpp algorithms/ranges_stable_sort.bench.cpp + algorithms/set_intersection.bench.cpp algorithms/sort.bench.cpp algorithms/sort_heap.bench.cpp algorithms/stable_sort.bench.cpp diff --git a/libcxx/benchmarks/algorithms/set_intersection.bench.cpp b/libcxx/benchmarks/algorithms/set_intersection.bench.cpp new file mode 100644 index 0000000..b3fb15f --- /dev/null +++ b/libcxx/benchmarks/algorithms/set_intersection.bench.cpp @@ -0,0 +1,184 @@ +//===----------------------------------------------------------------------===// +// +// 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 <algorithm> +#include <cstdlib> +#include <iterator> +#include <set> +#include <vector> + +#include "common.h" +#include "test_iterators.h" + +namespace { + +// types of containers we'll want to test, covering interesting iterator types +struct VectorContainer { + template <typename... Args> + using type = std::vector<Args...>; + + static constexpr const char* Name = "Vector"; +}; + +struct SetContainer { + template <typename... Args> + using type = std::set<Args...>; + + static constexpr const char* Name = "Set"; +}; + +using AllContainerTypes = std::tuple<VectorContainer, SetContainer>; + +// set_intersection performance may depend on where matching values lie +enum class OverlapPosition { + None, + Front, + // performance-wise, matches at the back are identical to ones at the front + Interlaced, +}; + +struct AllOverlapPositions : EnumValuesAsTuple<AllOverlapPositions, OverlapPosition, 3> { + static constexpr const char* Names[] = {"None", "Front", "Interlaced"}; +}; + +// forward_iterator wrapping which, for each increment, moves the underlying iterator forward Stride elements +template <typename Wrapped> +struct StridedFwdIt { + Wrapped base_; + unsigned stride_; + + using iterator_category = std::forward_iterator_tag; + using difference_type = typename Wrapped::difference_type; + using value_type = typename Wrapped::value_type; + using pointer = typename Wrapped::pointer; + using reference = typename Wrapped::reference; + + StridedFwdIt(Wrapped base, unsigned stride) : base_(base), stride_(stride) { assert(stride_ != 0); } + + StridedFwdIt operator++() { + for (unsigned i = 0; i < stride_; ++i) + ++base_; + return *this; + } + StridedFwdIt operator++(int) { + auto tmp = *this; + ++*this; + return tmp; + } + value_type& operator*() { return *base_; } + const value_type& operator*() const { return *base_; } + value_type& operator->() { return *base_; } + const value_type& operator->() const { return *base_; } + bool operator==(const StridedFwdIt& o) const { return base_ == o.base_; } + bool operator!=(const StridedFwdIt& o) const { return !operator==(o); } +}; +template <typename Wrapped> +StridedFwdIt(Wrapped, unsigned) -> StridedFwdIt<Wrapped>; + +template <typename T> +std::vector<T> getVectorOfRandom(size_t N) { + std::vector<T> v; + fillValues(v, N, Order::Random); + sortValues(v, Order::Random); + return std::vector<T>(v); +} + +// Realistically, data won't all be nicely contiguous in a container, +// we'll go through some effort to ensure that it's shuffled through memory +// this is especially important for containers with non-contiguous element +// storage, but it will affect even a std::vector, because when you copy a +// std::vector<std::string> the underlying data storage position for the char +// arrays of the copy are likely to have high locality +template <class Container> +std::pair<Container, Container> genCacheUnfriendlyData(size_t size1, size_t size2, OverlapPosition pos) { + using ValueType = typename Container::value_type; + auto move_into = [](auto first, auto last) { + Container out; + std::move(first, last, std::inserter(out, out.begin())); + return out; + }; + const auto src_size = pos == OverlapPosition::None ? size1 + size2 : std::max(size1, size2); + std::vector<ValueType> src = getVectorOfRandom<ValueType>(src_size); + + if (pos == OverlapPosition::None) { + std::sort(src.begin(), src.end()); + return std::make_pair(move_into(src.begin(), src.begin() + size1), move_into(src.begin() + size1, src.end())); + } + + // All other overlap types will have to copy some part of the data, but if + // we copy after sorting it will likely have high locality, so we sort + // each copy separately + auto copy = src; + std::sort(src.begin(), src.end()); + std::sort(copy.begin(), copy.end()); + + switch (pos) { + case OverlapPosition::None: + // we like -Wswitch :) + break; + + case OverlapPosition::Front: + return std::make_pair(move_into(src.begin(), src.begin() + size1), move_into(copy.begin(), copy.begin() + size2)); + + case OverlapPosition::Interlaced: + const auto stride1 = size1 < size2 ? size2 / size1 : 1; + const auto stride2 = size2 < size1 ? size1 / size2 : 1; + return std::make_pair(move_into(StridedFwdIt(src.begin(), stride1), StridedFwdIt(src.end(), stride1)), + move_into(StridedFwdIt(copy.begin(), stride2), StridedFwdIt(copy.end(), stride2))); + } + std::abort(); // would be std::unreachable() if it could + return std::pair<Container, Container>(); +} + +template <class ValueType, class Container, class Overlap> +struct SetIntersection { + using ContainerType = typename Container::template type<Value<ValueType>>; + size_t size1_; + size_t size2_; + + SetIntersection(size_t size1, size_t size2) : size1_(size1), size2_(size2) {} + + bool skip() const noexcept { + // let's save some time and skip simmetrical runs + return size1_ < size2_; + } + + void run(benchmark::State& state) const { + auto input = genCacheUnfriendlyData<ContainerType>(size1_, size2_, Overlap()); + std::vector<Value<ValueType>> out(std::min(size1_, size2_)); + + const auto BATCH_SIZE = std::max(size_t{512}, (2 * TestSetElements) / (size1_ + size2_)); + for (const auto& _ : state) { + while (state.KeepRunningBatch(BATCH_SIZE)) { + for (unsigned i = 0; i < BATCH_SIZE; ++i) { + const auto& [c1, c2] = input; + auto res = std::set_intersection(c1.begin(), c1.end(), c2.begin(), c2.end(), out.begin()); + benchmark::DoNotOptimize(res); + } + } + } + } + + std::string name() const { + return std::string("SetIntersection") + Overlap::name() + '_' + Container::Name + ValueType::name() + '_' + + std::to_string(size1_) + '_' + std::to_string(size2_); + } +}; + +} // namespace + +int main(int argc, char** argv) { /**/ + benchmark::Initialize(&argc, argv); + if (benchmark::ReportUnrecognizedArguments(argc, argv)) + return 1; + + makeCartesianProductBenchmark<SetIntersection, AllValueTypes, AllContainerTypes, AllOverlapPositions>( + Quantities, Quantities); + benchmark::RunSpecifiedBenchmarks(); + return 0; +} diff --git a/libcxx/cmake/caches/Apple.cmake b/libcxx/cmake/caches/Apple.cmake index 1038f1a..8768653 100644 --- a/libcxx/cmake/caches/Apple.cmake +++ b/libcxx/cmake/caches/Apple.cmake @@ -15,3 +15,6 @@ set(LIBCXXABI_HERMETIC_STATIC_LIBRARY ON CACHE BOOL "") set(LIBCXXABI_ENABLE_ASSERTIONS OFF CACHE BOOL "") set(LIBCXXABI_ENABLE_FORGIVING_DYNAMIC_CAST ON CACHE BOOL "") set(LIBCXXABI_USE_LLVM_UNWINDER OFF CACHE BOOL "") # libunwind is built separately + +set(LIBCXX_TEST_CONFIG "apple-libc++-shared.cfg.in" CACHE STRING "") +set(LIBCXXABI_TEST_CONFIG "apple-libc++abi-shared.cfg.in" CACHE STRING "") diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 53cfc37..b548322 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -346,7 +346,7 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_optional`` ``202110L`` ---------------------------------------------------------- ----------------- - ``__cpp_lib_out_ptr`` *unimplemented* + ``__cpp_lib_out_ptr`` ``202106L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_print`` ``202207L`` ---------------------------------------------------------- ----------------- @@ -450,7 +450,7 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_optional_range_support`` *unimplemented* ---------------------------------------------------------- ----------------- - ``__cpp_lib_out_ptr`` *unimplemented* + ``__cpp_lib_out_ptr`` ``202311L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_philox_engine`` *unimplemented* ---------------------------------------------------------- ----------------- diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst index 624550f..784934e 100644 --- a/libcxx/docs/ReleaseNotes/19.rst +++ b/libcxx/docs/ReleaseNotes/19.rst @@ -38,6 +38,7 @@ What's New in Libc++ 19.0.0? Implemented Papers ------------------ +- P1132R8 - ``out_ptr`` - a scalable output pointer abstraction - P2637R3 - Member ``visit`` - P2652R2 - Disallow User Specialization of ``allocator_traits`` - P2819R2 - Add ``tuple`` protocol to ``complex`` @@ -71,6 +72,10 @@ Improvements and New Features - The ``std::ranges::minmax`` algorithm has been optimized for integral types, resulting in a performance increase of up to 100x. +- The ``std::set_intersection`` and ``std::ranges::set_intersection`` algorithms have been optimized to fast-forward over + contiguous ranges of non-matching values, reducing the number of comparisons from linear to + logarithmic growth with the number of elements in best-case scenarios. + - The ``_LIBCPP_ENABLE_CXX26_REMOVED_STRSTREAM`` macro has been added to make the declarations in ``<strstream>`` available. - The ``_LIBCPP_ENABLE_CXX26_REMOVED_WSTRING_CONVERT`` macro has been added to make the declarations in ``<locale>`` diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv index cc601b3..547d38c 100644 --- a/libcxx/docs/Status/Cxx23Issues.csv +++ b/libcxx/docs/Status/Cxx23Issues.csv @@ -192,7 +192,7 @@ "`3515 <https://wg21.link/LWG3515>`__","§[stacktrace.basic.nonmem]: ``operator<<`` should be less templatized", "November 2022","","","" "`3545 <https://wg21.link/LWG3545>`__","``std::pointer_traits`` should be SFINAE-friendly", "November 2022","|Complete|","18.0","" "`3569 <https://wg21.link/LWG3569>`__","``join_view`` fails to support ranges of ranges with non-default_initializable iterators", "November 2022","","","|ranges|" -"`3594 <https://wg21.link/LWG3594>`__","``inout_ptr`` — inconsistent ``release()`` in destructor", "November 2022","","","" +"`3594 <https://wg21.link/LWG3594>`__","``inout_ptr`` — inconsistent ``release()`` in destructor", "November 2022","|Complete|","19.0","" "`3597 <https://wg21.link/LWG3597>`__","Unsigned integer types don't model advanceable", "November 2022","","","|ranges|" "`3600 <https://wg21.link/LWG3600>`__","Making ``istream_iterator`` copy constructor trivial is an ABI break", "November 2022","","","" "`3629 <https://wg21.link/LWG3629>`__","``make_error_code`` and ``make_error_condition`` are customization points","November 2022","|Complete|","16.0","" @@ -282,7 +282,7 @@ "`3645 <https://wg21.link/LWG3645>`__","``resize_and_overwrite`` is overspecified to call its callback with lvalues","February 2023","|Complete|","14.0","" "`3655 <https://wg21.link/LWG3655>`__","The ``INVOKE`` operation and union types","February 2023","|Complete|","18.0","" "`3723 <https://wg21.link/LWG3723>`__","``priority_queue::push_range`` needs to ``append_range``","February 2023","","","|ranges|" -"`3734 <https://wg21.link/LWG3734>`__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","February 2023","","","" +"`3734 <https://wg21.link/LWG3734>`__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","February 2023","|Complete|","19.0","" "`3772 <https://wg21.link/LWG3772>`__","``repeat_view``'s ``piecewise`` constructor is missing Postconditions","February 2023","|Complete|","17.0","|ranges|" "`3786 <https://wg21.link/LWG3786>`__","Flat maps' deduction guide needs to default ``Allocator`` to be useful","February 2023","","","" "`3803 <https://wg21.link/LWG3803>`__","``flat_foo`` constructors taking ``KeyContainer`` lack ``KeyCompare`` parameter","February 2023","","","" diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index 4f589cd..6dd6bda 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -13,7 +13,7 @@ "","","","","","","" "`P0401R6 <https://wg21.link/P0401R6>`__","LWG","Providing size feedback in the Allocator interface","June 2021","|Complete|","15.0" "`P0448R4 <https://wg21.link/P0448R4>`__","LWG","A strstream replacement using span<charT> as buffer","June 2021","","" -"`P1132R8 <https://wg21.link/P1132R8>`__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","","" +"`P1132R8 <https://wg21.link/P1132R8>`__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","|Complete|","19.0" "`P1328R1 <https://wg21.link/P1328R1>`__","LWG","Making std::type_info::operator== constexpr","June 2021","|Complete|","17.0" "`P1425R4 <https://wg21.link/P1425R4>`__","LWG","Iterators pair constructors for stack and queue","June 2021","|Complete|","14.0","|ranges|" "`P1518R2 <https://wg21.link/P1518R2>`__","LWG","Stop overconstraining allocators in container deduction guides","June 2021","|Complete|","13.0" diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv index b5732ee..dec9af1 100644 --- a/libcxx/docs/Status/Cxx2cIssues.csv +++ b/libcxx/docs/Status/Cxx2cIssues.csv @@ -24,7 +24,7 @@ "`3749 <https://wg21.link/LWG3749>`__","``common_iterator`` should handle integer-class difference types","Kona November 2023","","","" "`3809 <https://wg21.link/LWG3809>`__","Is ``std::subtract_with_carry_engine<uint16_t>`` supposed to work","Kona November 2023","","","" "`3892 <https://wg21.link/LWG3892>`__","Incorrect formatting of nested ranges and tuples","Kona November 2023","|Complete|","17.0","|format|" -"`3897 <https://wg21.link/LWG3897>`__","``inout_ptr`` will not update raw pointer to 0","Kona November 2023","","","" +"`3897 <https://wg21.link/LWG3897>`__","``inout_ptr`` will not update raw pointer to 0","Kona November 2023","|Complete|","19.0","" "`3946 <https://wg21.link/LWG3946>`__","The definition of ``const_iterator_t`` should be reworked","Kona November 2023","","","" "`3947 <https://wg21.link/LWG3947>`__","Unexpected constraints on ``adjacent_transform_view::base()``","Kona November 2023","","","|ranges|" "`3948 <https://wg21.link/LWG3948>`__","``possibly-const-range and as-const-pointer`` should be ``noexcept``","Kona November 2023","","","|ranges|" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 26bad4f..4b036ec 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -533,6 +533,8 @@ set(files __memory/concepts.h __memory/construct_at.h __memory/destruct_n.h + __memory/inout_ptr.h + __memory/out_ptr.h __memory/pointer_traits.h __memory/ranges_construct_at.h __memory/ranges_uninitialized_algorithms.h diff --git a/libcxx/include/__algorithm/iterator_operations.h b/libcxx/include/__algorithm/iterator_operations.h index 5cf13f0..8ced989 100644 --- a/libcxx/include/__algorithm/iterator_operations.h +++ b/libcxx/include/__algorithm/iterator_operations.h @@ -11,6 +11,7 @@ #include <__algorithm/iter_swap.h> #include <__algorithm/ranges_iterator_concept.h> +#include <__assert> #include <__config> #include <__iterator/advance.h> #include <__iterator/distance.h> @@ -160,6 +161,59 @@ struct _IterOps<_ClassicAlgPolicy> { _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 void __advance_to(_Iter& __first, _Iter __last) { __first = __last; } + + // advance with sentinel, a la std::ranges::advance + template <class _Iter> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_Iter> + __advance_to(_Iter& __iter, __difference_type<_Iter> __count, const _Iter& __sentinel) { + return _IterOps::__advance_to(__iter, __count, __sentinel, typename iterator_traits<_Iter>::iterator_category()); + } + +private: + // advance with sentinel, a la std::ranges::advance -- InputIterator specialization + template <class _InputIter> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_InputIter> __advance_to( + _InputIter& __iter, __difference_type<_InputIter> __count, const _InputIter& __sentinel, input_iterator_tag) { + __difference_type<_InputIter> __dist = 0; + for (; __dist < __count && __iter != __sentinel; ++__dist) + ++__iter; + return __count - __dist; + } + + // advance with sentinel, a la std::ranges::advance -- BidirectionalIterator specialization + template <class _BiDirIter> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_BiDirIter> + __advance_to(_BiDirIter& __iter, + __difference_type<_BiDirIter> __count, + const _BiDirIter& __sentinel, + bidirectional_iterator_tag) { + __difference_type<_BiDirIter> __dist = 0; + if (__count >= 0) + for (; __dist < __count && __iter != __sentinel; ++__dist) + ++__iter; + else + for (__count = -__count; __dist < __count && __iter != __sentinel; ++__dist) + --__iter; + return __count - __dist; + } + + // advance with sentinel, a la std::ranges::advance -- RandomIterator specialization + template <class _RandIter> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_RandIter> + __advance_to(_RandIter& __iter, + __difference_type<_RandIter> __count, + const _RandIter& __sentinel, + random_access_iterator_tag) { + auto __dist = _IterOps::distance(__iter, __sentinel); + _LIBCPP_ASSERT_VALID_INPUT_RANGE( + __count == 0 || (__dist < 0) == (__count < 0), "__sentinel must precede __iter when __count < 0"); + if (__count < 0) + __dist = __dist > __count ? __dist : __count; + else + __dist = __dist < __count ? __dist : __count; + __iter += __dist; + return __count - __dist; + } }; _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/lower_bound.h b/libcxx/include/__algorithm/lower_bound.h index 8fd355a..c417d84 100644 --- a/libcxx/include/__algorithm/lower_bound.h +++ b/libcxx/include/__algorithm/lower_bound.h @@ -27,11 +27,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template <class _AlgPolicy, class _Iter, class _Sent, class _Type, class _Proj, class _Comp> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter -__lower_bound(_Iter __first, _Sent __last, const _Type& __value, _Comp& __comp, _Proj& __proj) { - auto __len = _IterOps<_AlgPolicy>::distance(__first, __last); - +template <class _AlgPolicy, class _Iter, class _Type, class _Proj, class _Comp> +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter __lower_bound_bisecting( + _Iter __first, + const _Type& __value, + typename iterator_traits<_Iter>::difference_type __len, + _Comp& __comp, + _Proj& __proj) { while (__len != 0) { auto __l2 = std::__half_positive(__len); _Iter __m = __first; @@ -46,6 +48,48 @@ __lower_bound(_Iter __first, _Sent __last, const _Type& __value, _Comp& __comp, return __first; } +// One-sided binary search, aka meta binary search, has been in the public domain for decades, and has the general +// advantage of being \Omega(1) rather than the classic algorithm's \Omega(log(n)), with the downside of executing at +// most 2*log(n) comparisons vs the classic algorithm's exact log(n). There are two scenarios in which it really shines: +// the first one is when operating over non-random-access iterators, because the classic algorithm requires knowing the +// container's size upfront, which adds \Omega(n) iterator increments to the complexity. The second one is when you're +// traversing the container in order, trying to fast-forward to the next value: in that case, the classic algorithm +// would yield \Omega(n*log(n)) comparisons and, for non-random-access iterators, \Omega(n^2) iterator increments, +// whereas the one-sided version will yield O(n) operations on both counts, with a \Omega(log(n)) bound on the number of +// comparisons. +template <class _AlgPolicy, class _ForwardIterator, class _Sent, class _Type, class _Proj, class _Comp> +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +__lower_bound_onesided(_ForwardIterator __first, _Sent __last, const _Type& __value, _Comp& __comp, _Proj& __proj) { + // step = 0, ensuring we can always short-circuit when distance is 1 later on + if (__first == __last || !std::__invoke(__comp, std::__invoke(__proj, *__first), __value)) + return __first; + + using _Distance = typename iterator_traits<_ForwardIterator>::difference_type; + for (_Distance __step = 1; __first != __last; __step <<= 1) { + auto __it = __first; + auto __dist = __step - _IterOps<_AlgPolicy>::__advance_to(__it, __step, __last); + // once we reach the last range where needle can be we must start + // looking inwards, bisecting that range + if (__it == __last || !std::__invoke(__comp, std::__invoke(__proj, *__it), __value)) { + // we've already checked the previous value and it was less, we can save + // one comparison by skipping bisection + if (__dist == 1) + return __it; + return std::__lower_bound_bisecting<_AlgPolicy>(__first, __value, __dist, __comp, __proj); + } + // range not found, move forward! + __first = __it; + } + return __first; +} + +template <class _AlgPolicy, class _ForwardIterator, class _Sent, class _Type, class _Proj, class _Comp> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +__lower_bound(_ForwardIterator __first, _Sent __last, const _Type& __value, _Comp& __comp, _Proj& __proj) { + const auto __dist = _IterOps<_AlgPolicy>::distance(__first, __last); + return std::__lower_bound_bisecting<_AlgPolicy>(__first, __value, __dist, __comp, __proj); +} + template <class _ForwardIterator, class _Tp, class _Compare> _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator lower_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value, _Compare __comp) { diff --git a/libcxx/include/__algorithm/set_intersection.h b/libcxx/include/__algorithm/set_intersection.h index 73d888d..bb0d86c 100644 --- a/libcxx/include/__algorithm/set_intersection.h +++ b/libcxx/include/__algorithm/set_intersection.h @@ -12,10 +12,15 @@ #include <__algorithm/comp.h> #include <__algorithm/comp_ref_type.h> #include <__algorithm/iterator_operations.h> +#include <__algorithm/lower_bound.h> #include <__config> +#include <__functional/identity.h> #include <__iterator/iterator_traits.h> #include <__iterator/next.h> +#include <__type_traits/is_same.h> +#include <__utility/exchange.h> #include <__utility/move.h> +#include <__utility/swap.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -38,10 +43,103 @@ struct __set_intersection_result { : __in1_(std::move(__in_iter1)), __in2_(std::move(__in_iter2)), __out_(std::move(__out_iter)) {} }; -template <class _AlgPolicy, class _Compare, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InIter1, _InIter2, _OutIter> +// Helper for __set_intersection() with one-sided binary search: populate result and advance input iterators if they +// are found to potentially contain the same value in two consecutive calls. This function is very intimately related to +// the way it is used and doesn't attempt to abstract that, it's not appropriate for general usage outside of its +// context. +template <class _InForwardIter1, class _InForwardIter2, class _OutIter> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_intersection_add_output_if_equal( + bool __may_be_equal, + _InForwardIter1& __first1, + _InForwardIter2& __first2, + _OutIter& __result, + bool& __prev_may_be_equal) { + if (__may_be_equal && __prev_may_be_equal) { + *__result = *__first1; + ++__result; + ++__first1; + ++__first2; + __prev_may_be_equal = false; + } else { + __prev_may_be_equal = __may_be_equal; + } +} + +// With forward iterators we can make multiple passes over the data, allowing the use of one-sided binary search to +// reduce best-case complexity to log(N). Understanding how we can use binary search and still respect complexity +// guarantees is _not_ straightforward: the guarantee is "at most 2*(N+M)-1 comparisons", and one-sided binary search +// will necessarily overshoot depending on the position of the needle in the haystack -- for instance, if we're +// searching for 3 in (1, 2, 3, 4), we'll check if 3<1, then 3<2, then 3<4, and, finally, 3<3, for a total of 4 +// comparisons, when linear search would have yielded 3. However, because we won't need to perform the intervening +// reciprocal comparisons (ie 1<3, 2<3, 4<3), that extra comparison doesn't run afoul of the guarantee. Additionally, +// this type of scenario can only happen for match distances of up to 5 elements, because 2*log2(8) is 6, and we'll +// still be worse-off at position 5 of an 8-element set. From then onwards these scenarios can't happen. TL;DR: we'll be +// 1 comparison worse-off compared to the classic linear-searching algorithm if matching position 3 of a set with 4 +// elements, or position 5 if the set has 7 or 8 elements, but we'll never exceed the complexity guarantees from the +// standard. +template <class _AlgPolicy, + class _Compare, + class _InForwardIter1, + class _Sent1, + class _InForwardIter2, + class _Sent2, + class _OutIter> +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InForwardIter1, _InForwardIter2, _OutIter> __set_intersection( - _InIter1 __first1, _Sent1 __last1, _InIter2 __first2, _Sent2 __last2, _OutIter __result, _Compare&& __comp) { + _InForwardIter1 __first1, + _Sent1 __last1, + _InForwardIter2 __first2, + _Sent2 __last2, + _OutIter __result, + _Compare&& __comp, + std::forward_iterator_tag, + std::forward_iterator_tag) { + _LIBCPP_CONSTEXPR std::__identity __proj; + bool __prev_may_be_equal = false; + + while (__first2 != __last2) { + _InForwardIter1 __first1_next = + std::__lower_bound_onesided<_AlgPolicy>(__first1, __last1, *__first2, __comp, __proj); + std::swap(__first1_next, __first1); + // keeping in mind that a==b iff !(a<b) && !(b<a): + // if we can't advance __first1, that means !(*__first1 < *_first2), therefore __may_be_equal==true + std::__set_intersection_add_output_if_equal( + __first1 == __first1_next, __first1, __first2, __result, __prev_may_be_equal); + if (__first1 == __last1) + break; + + _InForwardIter2 __first2_next = + std::__lower_bound_onesided<_AlgPolicy>(__first2, __last2, *__first1, __comp, __proj); + std::swap(__first2_next, __first2); + std::__set_intersection_add_output_if_equal( + __first2 == __first2_next, __first1, __first2, __result, __prev_may_be_equal); + } + return __set_intersection_result<_InForwardIter1, _InForwardIter2, _OutIter>( + _IterOps<_AlgPolicy>::next(std::move(__first1), std::move(__last1)), + _IterOps<_AlgPolicy>::next(std::move(__first2), std::move(__last2)), + std::move(__result)); +} + +// input iterators are not suitable for multipass algorithms, so we stick to the classic single-pass version +template <class _AlgPolicy, + class _Compare, + class _InInputIter1, + class _Sent1, + class _InInputIter2, + class _Sent2, + class _OutIter> +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InInputIter1, _InInputIter2, _OutIter> +__set_intersection( + _InInputIter1 __first1, + _Sent1 __last1, + _InInputIter2 __first2, + _Sent2 __last2, + _OutIter __result, + _Compare&& __comp, + std::input_iterator_tag, + std::input_iterator_tag) { while (__first1 != __last1 && __first2 != __last2) { if (__comp(*__first1, *__first2)) ++__first1; @@ -55,12 +153,28 @@ __set_intersection( } } - return __set_intersection_result<_InIter1, _InIter2, _OutIter>( + return __set_intersection_result<_InInputIter1, _InInputIter2, _OutIter>( _IterOps<_AlgPolicy>::next(std::move(__first1), std::move(__last1)), _IterOps<_AlgPolicy>::next(std::move(__first2), std::move(__last2)), std::move(__result)); } +template <class _AlgPolicy, class _Compare, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter> +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InIter1, _InIter2, _OutIter> +__set_intersection( + _InIter1 __first1, _Sent1 __last1, _InIter2 __first2, _Sent2 __last2, _OutIter __result, _Compare&& __comp) { + return std::__set_intersection<_AlgPolicy>( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + std::forward<_Compare>(__comp), + typename std::_IterOps<_AlgPolicy>::template __iterator_category<_InIter1>(), + typename std::_IterOps<_AlgPolicy>::template __iterator_category<_InIter2>()); +} + template <class _InputIterator1, class _InputIterator2, class _OutputIterator, class _Compare> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_intersection( _InputIterator1 __first1, diff --git a/libcxx/include/__memory/allocator_traits.h b/libcxx/include/__memory/allocator_traits.h index ac564f0..c5fcc89 100644 --- a/libcxx/include/__memory/allocator_traits.h +++ b/libcxx/include/__memory/allocator_traits.h @@ -41,7 +41,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD struct NAME<_Tp, __void_t<typename _Tp::PROPERTY > > : true_type {} // __pointer -_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_pointer, pointer); template <class _Tp, class _Alloc, class _RawAlloc = __libcpp_remove_reference_t<_Alloc>, diff --git a/libcxx/include/__memory/inout_ptr.h b/libcxx/include/__memory/inout_ptr.h new file mode 100644 index 0000000..72e1a21 --- /dev/null +++ b/libcxx/include/__memory/inout_ptr.h @@ -0,0 +1,109 @@ +// -*- 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 _LIBCPP___INOUT_PTR_H +#define _LIBCPP___INOUT_PTR_H + +#include <__config> +#include <__memory/addressof.h> +#include <__memory/pointer_traits.h> +#include <__memory/shared_ptr.h> +#include <__memory/unique_ptr.h> +#include <__type_traits/is_same.h> +#include <__type_traits/is_specialization.h> +#include <__type_traits/is_void.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <tuple> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template <class _Smart, class _Pointer, class... _Args> +class _LIBCPP_TEMPLATE_VIS inout_ptr_t { + static_assert(!__is_specialization_v<_Smart, shared_ptr>, "std::shared_ptr<> is not supported with std::inout_ptr."); + +public: + _LIBCPP_HIDE_FROM_ABI explicit inout_ptr_t(_Smart& __smart, _Args... __args) + : __s_(__smart), __a_(std::forward<_Args>(__args)...), __p_([&__smart] { + if constexpr (is_pointer_v<_Smart>) { + return __smart; + } else { + return __smart.get(); + } + }()) { + if constexpr (requires { __s_.release(); }) { + __s_.release(); + } else { + __s_ = _Smart(); + } + } + + _LIBCPP_HIDE_FROM_ABI inout_ptr_t(const inout_ptr_t&) = delete; + + _LIBCPP_HIDE_FROM_ABI ~inout_ptr_t() { + // LWG-3897 inout_ptr will not update raw pointer to null + if constexpr (!is_pointer_v<_Smart>) { + if (!__p_) { + return; + } + } + + using _SP = __pointer_of_or_t<_Smart, _Pointer>; + if constexpr (is_pointer_v<_Smart>) { + std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); }, + std::move(__a_)); + } else if constexpr (__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...>) { + std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); }, + std::move(__a_)); + } else { + static_assert(is_constructible_v<_Smart, _SP, _Args...>, + "The smart pointer must be constructible from arguments of types _Smart, _Pointer, _Args..."); + std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); }, + std::move(__a_)); + } + } + + _LIBCPP_HIDE_FROM_ABI operator _Pointer*() const noexcept { return std::addressof(const_cast<_Pointer&>(__p_)); } + + _LIBCPP_HIDE_FROM_ABI operator void**() const noexcept + requires(!is_same_v<_Pointer, void*>) + { + static_assert(is_pointer_v<_Pointer>, "The conversion to void** requires _Pointer to be a raw pointer."); + + return reinterpret_cast<void**>(static_cast<_Pointer*>(*this)); + } + +private: + _Smart& __s_; + tuple<_Args...> __a_; + _Pointer __p_; +}; + +template <class _Pointer = void, class _Smart, class... _Args> +_LIBCPP_HIDE_FROM_ABI auto inout_ptr(_Smart& __s, _Args&&... __args) { + using _Ptr = conditional_t<is_void_v<_Pointer>, __pointer_of_t<_Smart>, _Pointer>; + return std::inout_ptr_t<_Smart, _Ptr, _Args&&...>(__s, std::forward<_Args>(__args)...); +} + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___INOUT_PTR_H diff --git a/libcxx/include/__memory/out_ptr.h b/libcxx/include/__memory/out_ptr.h new file mode 100644 index 0000000..95aa202 --- /dev/null +++ b/libcxx/include/__memory/out_ptr.h @@ -0,0 +1,101 @@ +// -*- 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 _LIBCPP___OUT_PTR_H +#define _LIBCPP___OUT_PTR_H + +#include <__config> +#include <__memory/addressof.h> +#include <__memory/pointer_traits.h> +#include <__memory/shared_ptr.h> +#include <__memory/unique_ptr.h> +#include <__type_traits/is_specialization.h> +#include <__type_traits/is_void.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <tuple> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template <class _Smart, class _Pointer, class... _Args> +class _LIBCPP_TEMPLATE_VIS out_ptr_t { + static_assert(!__is_specialization_v<_Smart, shared_ptr> || sizeof...(_Args) > 0, + "Using std::shared_ptr<> without a deleter in std::out_ptr is not supported."); + +public: + _LIBCPP_HIDE_FROM_ABI explicit out_ptr_t(_Smart& __smart, _Args... __args) + : __s_(__smart), __a_(std::forward<_Args>(__args)...), __p_() { + using _Ptr = decltype(__smart); + if constexpr (__resettable_smart_pointer<_Ptr>) { + __s_.reset(); + } else if constexpr (is_constructible_v<_Smart>) { + __s_ = _Smart(); + } else { + static_assert(__resettable_smart_pointer<_Ptr> || is_constructible_v<_Smart>, + "The adapted pointer type must have a reset() member function or be default constructible."); + } + } + + _LIBCPP_HIDE_FROM_ABI out_ptr_t(const out_ptr_t&) = delete; + + _LIBCPP_HIDE_FROM_ABI ~out_ptr_t() { + if (!__p_) { + return; + } + + using _SP = __pointer_of_or_t<_Smart, _Pointer>; + if constexpr (__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...>) { + std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); }, + std::move(__a_)); + } else { + static_assert(is_constructible_v<_Smart, _SP, _Args...>, + "The smart pointer must be constructible from arguments of types _Smart, _Pointer, _Args..."); + std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); }, + std::move(__a_)); + } + } + + _LIBCPP_HIDE_FROM_ABI operator _Pointer*() const noexcept { return std::addressof(const_cast<_Pointer&>(__p_)); } + + _LIBCPP_HIDE_FROM_ABI operator void**() const noexcept + requires(!is_same_v<_Pointer, void*>) + { + static_assert(is_pointer_v<_Pointer>, "The conversion to void** requires _Pointer to be a raw pointer."); + + return reinterpret_cast<void**>(static_cast<_Pointer*>(*this)); + } + +private: + _Smart& __s_; + tuple<_Args...> __a_; + _Pointer __p_ = _Pointer(); +}; + +template <class _Pointer = void, class _Smart, class... _Args> +_LIBCPP_HIDE_FROM_ABI auto out_ptr(_Smart& __s, _Args&&... __args) { + using _Ptr = conditional_t<is_void_v<_Pointer>, __pointer_of_t<_Smart>, _Pointer>; + return std::out_ptr_t<_Smart, _Ptr, _Args&&...>(__s, std::forward<_Args>(__args)...); +} + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___OUT_PTR_H diff --git a/libcxx/include/__memory/pointer_traits.h b/libcxx/include/__memory/pointer_traits.h index fcd2c3e..0914ace 100644 --- a/libcxx/include/__memory/pointer_traits.h +++ b/libcxx/include/__memory/pointer_traits.h @@ -20,19 +20,28 @@ #include <__type_traits/is_void.h> #include <__type_traits/void_t.h> #include <__utility/declval.h> +#include <__utility/forward.h> #include <cstddef> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD -template <class _Tp, class = void> -struct __has_element_type : false_type {}; +// clang-format off +#define _LIBCPP_CLASS_TRAITS_HAS_XXX(NAME, PROPERTY) \ + template <class _Tp, class = void> \ + struct NAME : false_type {}; \ + template <class _Tp> \ + struct NAME<_Tp, __void_t<typename _Tp::PROPERTY> > : true_type {} +// clang-format on -template <class _Tp> -struct __has_element_type<_Tp, __void_t<typename _Tp::element_type> > : true_type {}; +_LIBCPP_CLASS_TRAITS_HAS_XXX(__has_pointer, pointer); +_LIBCPP_CLASS_TRAITS_HAS_XXX(__has_element_type, element_type); template <class _Ptr, bool = __has_element_type<_Ptr>::value> struct __pointer_traits_element_type {}; @@ -240,6 +249,59 @@ to_address(const _Pointer& __p) noexcept -> decltype(std::__to_address(__p)) { } #endif +#if _LIBCPP_STD_VER >= 23 + +template <class _Tp> +struct __pointer_of {}; + +template <class _Tp> + requires(__has_pointer<_Tp>::value) +struct __pointer_of<_Tp> { + using type = typename _Tp::pointer; +}; + +template <class _Tp> + requires(!__has_pointer<_Tp>::value && __has_element_type<_Tp>::value) +struct __pointer_of<_Tp> { + using type = typename _Tp::element_type*; +}; + +template <class _Tp> + requires(!__has_pointer<_Tp>::value && !__has_element_type<_Tp>::value && + __has_element_type<pointer_traits<_Tp>>::value) +struct __pointer_of<_Tp> { + using type = typename pointer_traits<_Tp>::element_type*; +}; + +template <typename _Tp> +using __pointer_of_t = typename __pointer_of<_Tp>::type; + +template <class _Tp, class _Up> +struct __pointer_of_or { + using type _LIBCPP_NODEBUG = _Up; +}; + +template <class _Tp, class _Up> + requires requires { typename __pointer_of_t<_Tp>; } +struct __pointer_of_or<_Tp, _Up> { + using type _LIBCPP_NODEBUG = __pointer_of_t<_Tp>; +}; + +template <typename _Tp, typename _Up> +using __pointer_of_or_t = typename __pointer_of_or<_Tp, _Up>::type; + +template <class _Smart> +concept __resettable_smart_pointer = requires(_Smart __s) { __s.reset(); }; + +template <class _Smart, class _Pointer, class... _Args> +concept __resettable_smart_pointer_with_args = requires(_Smart __s, _Pointer __p, _Args... __args) { + __s.reset(static_cast<__pointer_of_or_t<_Smart, _Pointer>>(__p), std::forward<_Args>(__args)...); +}; + +#endif + _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP___MEMORY_POINTER_TRAITS_H diff --git a/libcxx/include/memory b/libcxx/include/memory index d52ee7b..e1b8462 100644 --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -911,6 +911,22 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space); template<size_t N, class T> [[nodiscard]] constexpr T* assume_aligned(T* ptr); // since C++20 +// [out.ptr.t], class template out_ptr_t +template<class Smart, class Pointer, class... Args> + class out_ptr_t; // since c++23 + +// [out.ptr], function template out_ptr +template<class Pointer = void, class Smart, class... Args> + auto out_ptr(Smart& s, Args&&... args); // since c++23 + +// [inout.ptr.t], class template inout_ptr_t +template<class Smart, class Pointer, class... Args> + class inout_ptr_t; // since c++23 + +// [inout.ptr], function template inout_ptr +template<class Pointer = void, class Smart, class... Args> + auto inout_ptr(Smart& s, Args&&... args); // since c++23 + } // std */ @@ -924,6 +940,8 @@ template<size_t N, class T> #include <__memory/allocator_arg_t.h> #include <__memory/allocator_traits.h> #include <__memory/auto_ptr.h> +#include <__memory/inout_ptr.h> +#include <__memory/out_ptr.h> #include <__memory/pointer_traits.h> #include <__memory/raw_storage_iterator.h> #include <__memory/shared_ptr.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 5ed284d..43ab9c6 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1521,6 +1521,8 @@ module std_private_memory_concepts [system] { module std_private_memory_construct_at [system] { header "__memory/construct_at.h" } module std_private_memory_destruct_n [system] { header "__memory/destruct_n.h" } module std_private_memory_fwd [system] { header "__fwd/memory.h" } +module std_private_memory_inout_ptr [system] { header "__memory/inout_ptr.h" } +module std_private_memory_out_ptr [system] { header "__memory/out_ptr.h" } module std_private_memory_pointer_traits [system] { header "__memory/pointer_traits.h" } module std_private_memory_ranges_construct_at [system] { header "__memory/ranges_construct_at.h" } module std_private_memory_ranges_uninitialized_algorithms [system] { diff --git a/libcxx/include/version b/libcxx/include/version index 7d9fad1..68aa88a 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -477,7 +477,7 @@ __cpp_lib_void_t 201411L <type_traits> // # define __cpp_lib_move_only_function 202110L # undef __cpp_lib_optional # define __cpp_lib_optional 202110L -// # define __cpp_lib_out_ptr 202106L +# define __cpp_lib_out_ptr 202106L # define __cpp_lib_print 202207L // # define __cpp_lib_ranges_as_const 202207L # define __cpp_lib_ranges_as_rvalue 202207L @@ -536,7 +536,7 @@ __cpp_lib_void_t 201411L <type_traits> # define __cpp_lib_mdspan 202406L // # define __cpp_lib_optional_range_support 202406L # undef __cpp_lib_out_ptr -// # define __cpp_lib_out_ptr 202311L +# define __cpp_lib_out_ptr 202311L // # define __cpp_lib_philox_engine 202406L // # define __cpp_lib_ranges_concat 202403L # define __cpp_lib_ratio 202306L diff --git a/libcxx/modules/std/memory.inc b/libcxx/modules/std/memory.inc index 56c621c..c15f37a 100644 --- a/libcxx/modules/std/memory.inc +++ b/libcxx/modules/std/memory.inc @@ -177,17 +177,19 @@ export namespace std { // [util.smartptr.atomic], atomic smart pointers // using std::atomic; +#if _LIBCPP_STD_VER >= 23 // [out.ptr.t], class template out_ptr_t - // using std::out_ptr_t; + using std::out_ptr_t; // [out.ptr], function template out_ptr - // using std::out_ptr; + using std::out_ptr; // [inout.ptr.t], class template inout_ptr_t - // using std::inout_ptr_t; + using std::inout_ptr_t; // [inout.ptr], function template inout_ptr - // using std::inout_ptr; + using std::inout_ptr; +#endif // _LIBCPP_STD_VER >= 23 #ifndef _LIBCPP_HAS_NO_THREADS // [depr.util.smartptr.shared.atomic] diff --git a/libcxx/test/configs/apple-libc++-shared.cfg.in b/libcxx/test/configs/apple-libc++-shared.cfg.in new file mode 100644 index 0000000..5504bfd --- /dev/null +++ b/libcxx/test/configs/apple-libc++-shared.cfg.in @@ -0,0 +1,51 @@ +# Testing configuration for Apple's system libc++. +# +# This configuration differs from a normal LLVM shared library configuration in +# that we must use DYLD_LIBRARY_PATH to run the tests against the just-built library, +# since Apple's libc++ has an absolute install_name. +# +# We also don't use a per-target include directory layout, so we have only one +# include directory for the libc++ headers. +# +# Finally, we also link against an artificial shims library that provides +# the functionality necessary for the upstream libc++ to be usable in place +# of a system-provided libc++. Without that, attempting to replace the system +# libc++ with DYLD_LIBRARY_PATH would result in missing symbols and other similar +# issues since the upstream libc++ does not contain all the symbols provided by +# the system library. + +lit_config.load_config(config, '@CMAKE_CURRENT_BINARY_DIR@/cmake-bridge.cfg') + +import os, site +site.addsitedir(os.path.join('@LIBCXX_SOURCE_DIR@', 'utils')) +import libcxx.test.params, libcxx.test.config, libcxx.test.dsl +ADDITIONAL_PARAMETERS = [ + libcxx.test.dsl.Parameter(name='apple_system_shims', type=str, + actions=lambda path: [libcxx.test.dsl.AddSubstitution('%{apple-system-shims}', path)], + help=""" + Path to a pre-built object file or static archive that contains shims necessary to + allow replacing the system libc++ by the just-built one. + """), +] + +config.substitutions.append(('%{flags}', + '-isysroot {}'.format('@CMAKE_OSX_SYSROOT@') if '@CMAKE_OSX_SYSROOT@' else '' +)) +config.substitutions.append(('%{compile_flags}', + '-nostdinc++ -I %{include-dir} -I %{libcxx-dir}/test/support' +)) +config.substitutions.append(('%{link_flags}', + '-nostdlib++ -L %{lib-dir} -lc++ %{apple-system-shims}' +)) +config.substitutions.append(('%{exec}', + '%{executor} --execdir %T --env DYLD_LIBRARY_PATH=%{lib-dir} -- ' +)) + +config.stdlib = 'apple-libc++' + +libcxx.test.config.configure( + libcxx.test.params.DEFAULT_PARAMETERS + ADDITIONAL_PARAMETERS, + libcxx.test.features.DEFAULT_FEATURES, + config, + lit_config +) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.set.operations/set.intersection/ranges_set_intersection.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.set.operations/set.intersection/ranges_set_intersection.pass.cpp index 5323bb1..f7870485 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.set.operations/set.intersection/ranges_set_intersection.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.set.operations/set.intersection/ranges_set_intersection.pass.cpp @@ -28,6 +28,8 @@ #include <algorithm> #include <array> #include <concepts> +#include <cstddef> +#include <ranges> #include "almost_satisfies_types.h" #include "MoveOnly.h" @@ -463,75 +465,6 @@ constexpr bool test() { } } - // Complexity: At most 2 * ((last1 - first1) + (last2 - first2)) - 1 comparisons and applications of each projection. - { - std::array<Data, 5> r1{{{1}, {3}, {5}, {7}, {9}}}; - std::array<Data, 5> r2{{{2}, {4}, {6}, {8}, {10}}}; - std::array<int, 0> expected{}; - - const std::size_t maxOperation = 2 * (r1.size() + r2.size()) - 1; - - // iterator overload - { - std::array<Data, 0> out{}; - std::size_t numberOfComp = 0; - std::size_t numberOfProj1 = 0; - std::size_t numberOfProj2 = 0; - - const auto comp = [&numberOfComp](int x, int y) { - ++numberOfComp; - return x < y; - }; - - const auto proj1 = [&numberOfProj1](const Data& d) { - ++numberOfProj1; - return d.data; - }; - - const auto proj2 = [&numberOfProj2](const Data& d) { - ++numberOfProj2; - return d.data; - }; - - std::ranges::set_intersection(r1.begin(), r1.end(), r2.begin(), r2.end(), out.data(), comp, proj1, proj2); - - assert(std::ranges::equal(out, expected, {}, &Data::data)); - assert(numberOfComp < maxOperation); - assert(numberOfProj1 < maxOperation); - assert(numberOfProj2 < maxOperation); - } - - // range overload - { - std::array<Data, 0> out{}; - std::size_t numberOfComp = 0; - std::size_t numberOfProj1 = 0; - std::size_t numberOfProj2 = 0; - - const auto comp = [&numberOfComp](int x, int y) { - ++numberOfComp; - return x < y; - }; - - const auto proj1 = [&numberOfProj1](const Data& d) { - ++numberOfProj1; - return d.data; - }; - - const auto proj2 = [&numberOfProj2](const Data& d) { - ++numberOfProj2; - return d.data; - }; - - std::ranges::set_intersection(r1, r2, out.data(), comp, proj1, proj2); - - assert(std::ranges::equal(out, expected, {}, &Data::data)); - assert(numberOfComp < maxOperation); - assert(numberOfProj1 < maxOperation); - assert(numberOfProj2 < maxOperation); - } - } - // Comparator convertible to bool { struct ConvertibleToBool { diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.set.operations/set.intersection/set_intersection_complexity.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.set.operations/set.intersection/set_intersection_complexity.pass.cpp new file mode 100644 index 0000000..ddf4087 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.sorting/alg.set.operations/set.intersection/set_intersection_complexity.pass.cpp @@ -0,0 +1,404 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// <algorithm> + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// Algorithmic complexity tests for both std::set_intersection and std::ranges::set_intersection + +// template<InputIterator InIter1, InputIterator InIter2, typename OutIter> +// requires OutputIterator<OutIter, InIter1::reference> +// && OutputIterator<OutIter, InIter2::reference> +// && HasLess<InIter2::value_type, InIter1::value_type> +// && HasLess<InIter1::value_type, InIter2::value_type> +// constexpr OutIter // constexpr after C++17 +// set_intersection(InIter1 first1, InIter1 last1, InIter2 first2, InIter2 last2, +// OutIter result); +// +// template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2, +// weakly_incrementable O, class Comp = ranges::less, +// class Proj1 = identity, class Proj2 = identity> +// requires mergeable<I1, I2, O, Comp, Proj1, Proj2> +// constexpr set_intersection_result<I1, I2, O> +// set_intersection(I1 first1, S1 last1, I2 first2, S2 last2, O result, +// Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); // since C++20 +// +// template<input_range R1, input_range R2, weakly_incrementable O, +// class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> +// requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2> +// constexpr set_intersection_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O> +// set_intersection(R1&& r1, R2&& r2, O result, +// Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); // since C++20 + +#include <algorithm> +#include <array> +#include <cstddef> +#include <ranges> + +#include "test_iterators.h" + +namespace { + +// __debug_less will perform an additional comparison in an assertion +static constexpr unsigned std_less_comparison_count_multiplier() noexcept { +#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG + return 2; +#else + return 1; +#endif +} + +struct [[nodiscard]] OperationCounts { + std::size_t comparisons{}; + struct PerInput { + std::size_t proj{}; + IteratorOpCounts iterops; + + [[nodiscard]] constexpr bool isNotBetterThan(const PerInput& other) { + return proj >= other.proj && iterops.increments + iterops.decrements + iterops.zero_moves >= + other.iterops.increments + other.iterops.decrements + other.iterops.zero_moves; + } + }; + std::array<PerInput, 2> in; + + [[nodiscard]] constexpr bool isNotBetterThan(const OperationCounts& expect) { + return std_less_comparison_count_multiplier() * comparisons >= expect.comparisons && + in[0].isNotBetterThan(expect.in[0]) && in[1].isNotBetterThan(expect.in[1]); + } +}; + +template <std::size_t ResultSize> +struct counted_set_intersection_result { + std::array<int, ResultSize> result; + OperationCounts opcounts; + + constexpr counted_set_intersection_result() = default; + + constexpr explicit counted_set_intersection_result(std::array<int, ResultSize>&& contents) : result{contents} {} + + constexpr void assertNotBetterThan(const counted_set_intersection_result& other) { + assert(result == other.result); + assert(opcounts.isNotBetterThan(other.opcounts)); + } +}; + +template <std::size_t ResultSize> +counted_set_intersection_result(std::array<int, ResultSize>) -> counted_set_intersection_result<ResultSize>; + +template <template <class...> class InIterType1, + template <class...> + class InIterType2, + class OutIterType, + std::size_t ResultSize, + std::ranges::input_range R1, + std::ranges::input_range R2> +constexpr counted_set_intersection_result<ResultSize> counted_set_intersection(const R1& in1, const R2& in2) { + counted_set_intersection_result<ResultSize> out; + + const auto comp = [&out](int x, int y) { + ++out.opcounts.comparisons; + return x < y; + }; + + operation_counting_iterator b1(InIterType1<decltype(in1.begin())>(in1.begin()), &out.opcounts.in[0].iterops); + operation_counting_iterator e1(InIterType1<decltype(in1.end()) >(in1.end()), &out.opcounts.in[0].iterops); + + operation_counting_iterator b2(InIterType2<decltype(in2.begin())>(in2.begin()), &out.opcounts.in[1].iterops); + operation_counting_iterator e2(InIterType2<decltype(in2.end()) >(in2.end()), &out.opcounts.in[1].iterops); + + std::set_intersection(b1, e1, b2, e2, OutIterType(out.result.data()), comp); + + return out; +} + +template <template <class...> class InIterType1, + template <class...> + class InIterType2, + class OutIterType, + std::size_t ResultSize, + std::ranges::input_range R1, + std::ranges::input_range R2> +constexpr counted_set_intersection_result<ResultSize> counted_ranges_set_intersection(const R1& in1, const R2& in2) { + counted_set_intersection_result<ResultSize> out; + + const auto comp = [&out](int x, int y) { + ++out.opcounts.comparisons; + return x < y; + }; + + const auto proj1 = [&out](const int& i) { + ++out.opcounts.in[0].proj; + return i; + }; + + const auto proj2 = [&out](const int& i) { + ++out.opcounts.in[1].proj; + return i; + }; + + operation_counting_iterator b1(InIterType1<decltype(in1.begin())>(in1.begin()), &out.opcounts.in[0].iterops); + operation_counting_iterator e1(InIterType1<decltype(in1.end()) >(in1.end()), &out.opcounts.in[0].iterops); + + operation_counting_iterator b2(InIterType2<decltype(in2.begin())>(in2.begin()), &out.opcounts.in[1].iterops); + operation_counting_iterator e2(InIterType2<decltype(in2.end()) >(in2.end()), &out.opcounts.in[1].iterops); + + std::ranges::subrange r1{b1, sentinel_wrapper<decltype(e1)>{e1}}; + std::ranges::subrange r2{b2, sentinel_wrapper<decltype(e2)>{e2}}; + std::same_as<std::ranges::set_intersection_result<decltype(e1), decltype(e2), OutIterType>> decltype(auto) result = + std::ranges::set_intersection(r1, r2, OutIterType{out.result.data()}, comp, proj1, proj2); + assert(base(result.in1) == base(e1)); + assert(base(result.in2) == base(e2)); + assert(base(result.out) == out.result.data() + out.result.size()); + + return out; +} + +template <template <typename...> class In1, template <typename...> class In2, class Out> +constexpr void testComplexityParameterizedIter() { + // Worst-case complexity: + // Let N=(last1 - first1) and M=(last2 - first2) + // At most 2*(N+M) - 1 comparisons and applications of each projection. + // At most 2*(N+M) iterator mutations. + { + std::array r1{1, 3, 5, 7, 9, 11, 13, 15, 17, 19}; + std::array r2{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}; + + counted_set_intersection_result<0> expected; + expected.opcounts.comparisons = 37; + expected.opcounts.in[0].proj = 37; + expected.opcounts.in[0].iterops.increments = 30; + expected.opcounts.in[0].iterops.decrements = 0; + expected.opcounts.in[1] = expected.opcounts.in[0]; + + expected.assertNotBetterThan(counted_set_intersection<In1, In2, Out, expected.result.size()>(r1, r2)); + expected.assertNotBetterThan(counted_ranges_set_intersection<In1, In2, Out, expected.result.size()>(r1, r2)); + } + + { + std::array r1{1, 3, 5, 7, 9, 11, 13, 15, 17, 19}; + std::array r2{1, 3, 5, 7, 9, 11, 13, 15, 17, 19}; + + counted_set_intersection_result expected(std::array{1, 3, 5, 7, 9, 11, 13, 15, 17, 19}); + expected.opcounts.comparisons = 38; + expected.opcounts.in[0].proj = 38; + expected.opcounts.in[0].iterops.increments = 30; + expected.opcounts.in[0].iterops.decrements = 0; + expected.opcounts.in[1] = expected.opcounts.in[0]; + + expected.assertNotBetterThan(counted_set_intersection<In1, In2, Out, expected.result.size()>(r1, r2)); + expected.assertNotBetterThan(counted_ranges_set_intersection<In1, In2, Out, expected.result.size()>(r1, r2)); + } + + // Lower complexity when there is low overlap between ranges: we can make 2*log(X) comparisons when one range + // has X elements that can be skipped over (and then 1 more to confirm that the value we found is equal). + { + std::array r1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + std::array r2{15}; + + counted_set_intersection_result expected(std::array{15}); + expected.opcounts.comparisons = 9; + expected.opcounts.in[0].proj = 9; + expected.opcounts.in[0].iterops.increments = 23; + expected.opcounts.in[0].iterops.decrements = 0; + expected.opcounts.in[1].proj = 9; + expected.opcounts.in[1].iterops.increments = 1; + expected.opcounts.in[1].iterops.decrements = 0; + + expected.assertNotBetterThan(counted_set_intersection<In1, In2, Out, expected.result.size()>(r1, r2)); + expected.assertNotBetterThan(counted_ranges_set_intersection<In1, In2, Out, expected.result.size()>(r1, r2)); + } + + { + std::array r1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + std::array r2{0, 16}; + counted_set_intersection_result<0> expected; + + expected.opcounts.comparisons = 10; + expected.opcounts.in[0].proj = 10; + expected.opcounts.in[0].iterops.increments = 24; + expected.opcounts.in[0].iterops.decrements = 0; + expected.opcounts.in[1].proj = 10; + expected.opcounts.in[1].iterops.increments = 4; + expected.opcounts.in[1].iterops.decrements = 0; + + expected.assertNotBetterThan(counted_set_intersection<In1, In2, Out, expected.result.size()>(r1, r2)); + expected.assertNotBetterThan(counted_ranges_set_intersection<In1, In2, Out, expected.result.size()>(r1, r2)); + } +} + +template <template <typename...> class In2, class Out> +constexpr void testComplexityParameterizedIterPermutateIn1() { + //common_input_iterator + testComplexityParameterizedIter<forward_iterator, In2, Out>(); + testComplexityParameterizedIter<bidirectional_iterator, In2, Out>(); + testComplexityParameterizedIter<random_access_iterator, In2, Out>(); +} + +template <class Out> +constexpr void testComplexityParameterizedIterPermutateIn1In2() { + testComplexityParameterizedIterPermutateIn1<forward_iterator, Out>(); + testComplexityParameterizedIterPermutateIn1<bidirectional_iterator, Out>(); + testComplexityParameterizedIterPermutateIn1<random_access_iterator, Out>(); +} + +constexpr bool testComplexity() { + testComplexityParameterizedIterPermutateIn1In2<forward_iterator<int*>>(); + testComplexityParameterizedIterPermutateIn1In2<bidirectional_iterator<int*>>(); + testComplexityParameterizedIterPermutateIn1In2<random_access_iterator<int*>>(); + return true; +} + +template <template <typename...> class In1, template <typename...> class In2, class Out> +constexpr void testComplexityGuaranteesParameterizedIter() { + // now a more generic validation of the complexity guarantees when searching for a single value + for (unsigned range_size = 1; range_size < 20; ++range_size) { + std::ranges::iota_view<int, int> r1(0, range_size); + for (int i : r1) { + // At most 2 * ((last1 - first1) + (last2 - first2)) - 1 comparisons + counted_set_intersection_result<1> expected(std::array{i}); + expected.opcounts.comparisons = 2 * (r1.size() + 1) - 1; + expected.opcounts.in[0].proj = expected.opcounts.comparisons; + expected.opcounts.in[1].proj = expected.opcounts.comparisons; + expected.opcounts.in[0].iterops.increments = 2 * r1.size(); + expected.opcounts.in[1].iterops.increments = 2; + expected.opcounts.in[0].iterops.decrements = expected.opcounts.in[0].iterops.increments; + expected.opcounts.in[1].iterops.decrements = expected.opcounts.in[1].iterops.increments; + + expected.assertNotBetterThan( + counted_set_intersection<In1, In2, Out, expected.result.size()>(r1, expected.result)); + expected.assertNotBetterThan( + counted_ranges_set_intersection<In1, In2, Out, expected.result.size()>(r1, expected.result)); + } + } +} + +template <template <typename...> class In2, class Out> +constexpr void testComplexityGuaranteesParameterizedIterPermutateIn1() { + //common_input_iterator + testComplexityGuaranteesParameterizedIter<forward_iterator, In2, Out>(); + testComplexityGuaranteesParameterizedIter<bidirectional_iterator, In2, Out>(); + testComplexityGuaranteesParameterizedIter<random_access_iterator, In2, Out>(); +} + +template <class Out> +constexpr void testComplexityGuaranteesParameterizedIterPermutateIn1In2() { + testComplexityGuaranteesParameterizedIterPermutateIn1<forward_iterator, Out>(); + testComplexityGuaranteesParameterizedIterPermutateIn1<bidirectional_iterator, Out>(); + testComplexityGuaranteesParameterizedIterPermutateIn1<random_access_iterator, Out>(); +} + +constexpr bool testComplexityGuarantees() { + testComplexityGuaranteesParameterizedIterPermutateIn1In2<forward_iterator<int*>>(); + testComplexityGuaranteesParameterizedIterPermutateIn1In2<bidirectional_iterator<int*>>(); + testComplexityGuaranteesParameterizedIterPermutateIn1In2<random_access_iterator<int*>>(); + return true; +} + +constexpr bool testComplexityBasic() { + // Complexity: At most 2 * ((last1 - first1) + (last2 - first2)) - 1 comparisons and applications of each projection. + std::array<int, 5> r1{1, 3, 5, 7, 9}; + std::array<int, 5> r2{2, 4, 6, 8, 10}; + std::array<int, 0> expected{}; + + const std::size_t maxOperation = std_less_comparison_count_multiplier() * (2 * (r1.size() + r2.size()) - 1); + + // std::set_intersection + { + std::array<int, 0> out{}; + std::size_t numberOfComp = 0; + + const auto comp = [&numberOfComp](int x, int y) { + ++numberOfComp; + return x < y; + }; + + std::set_intersection(r1.begin(), r1.end(), r2.begin(), r2.end(), out.data(), comp); + + assert(std::ranges::equal(out, expected)); + assert(numberOfComp <= maxOperation); + } + + // ranges::set_intersection iterator overload + { + std::array<int, 0> out{}; + std::size_t numberOfComp = 0; + std::size_t numberOfProj1 = 0; + std::size_t numberOfProj2 = 0; + + const auto comp = [&numberOfComp](int x, int y) { + ++numberOfComp; + return x < y; + }; + + const auto proj1 = [&numberOfProj1](int d) { + ++numberOfProj1; + return d; + }; + + const auto proj2 = [&numberOfProj2](int d) { + ++numberOfProj2; + return d; + }; + + std::ranges::set_intersection(r1.begin(), r1.end(), r2.begin(), r2.end(), out.data(), comp, proj1, proj2); + + assert(std::ranges::equal(out, expected)); + assert(numberOfComp <= maxOperation); + assert(numberOfProj1 <= maxOperation); + assert(numberOfProj2 <= maxOperation); + } + + // ranges::set_intersection range overload + { + std::array<int, 0> out{}; + std::size_t numberOfComp = 0; + std::size_t numberOfProj1 = 0; + std::size_t numberOfProj2 = 0; + + const auto comp = [&numberOfComp](int x, int y) { + ++numberOfComp; + return x < y; + }; + + const auto proj1 = [&numberOfProj1](int d) { + ++numberOfProj1; + return d; + }; + + const auto proj2 = [&numberOfProj2](int d) { + ++numberOfProj2; + return d; + }; + + std::ranges::set_intersection(r1, r2, out.data(), comp, proj1, proj2); + + assert(std::ranges::equal(out, expected)); + assert(numberOfComp < maxOperation); + assert(numberOfProj1 < maxOperation); + assert(numberOfProj2 < maxOperation); + } + return true; +} + +} // unnamed namespace + +int main(int, char**) { + testComplexityBasic(); + testComplexity(); + testComplexityGuarantees(); + + static_assert(testComplexityBasic()); + static_assert(testComplexity()); + + // we hit maximum constexpr evaluation step limit even if we split this into + // the 3 types of the first type layer, so let's skip the constexpr validation + // static_assert(testComplexityGuarantees()); + + return 0; +} diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count.pass.cpp index cda49ac..18f8d15 100644 --- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count.pass.cpp +++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count.pass.cpp @@ -12,6 +12,7 @@ #include <iterator> +#include <algorithm> #include <cassert> #include "test_iterators.h" @@ -32,12 +33,16 @@ constexpr void check(int* first, std::iter_difference_t<It> n, int* expected) { // Count operations if constexpr (Count) { - auto it = stride_counting_iterator(It(first)); + IteratorOpCounts ops; + auto it = operation_counting_iterator(It(first), &ops); std::ranges::advance(it, n); if constexpr (std::random_access_iterator<It>) { - assert(it.stride_count() <= 1); + assert(ops.increments + ops.decrements <= 1); } else { - assert(it.stride_count() == abs(M)); + const auto big = std::max(ops.increments, ops.decrements); + const auto small = std::min(ops.increments, ops.decrements); + assert(big == std::size_t(abs(M))); + assert(small == 0); } } } diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count_sentinel.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count_sentinel.pass.cpp index 76439ef..d613105 100644 --- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count_sentinel.pass.cpp +++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count_sentinel.pass.cpp @@ -38,14 +38,16 @@ check_forward(int* first, int* last, std::iter_difference_t<It> n, int* expected // Count operations if constexpr (Count) { - auto it = stride_counting_iterator(It(first)); - auto sent = sentinel_wrapper(stride_counting_iterator(It(last))); + IteratorOpCounts ops; + auto it = operation_counting_iterator(It(first), &ops); + auto sent = sentinel_wrapper(operation_counting_iterator(It(last), &ops)); (void)std::ranges::advance(it, n, sent); // We don't have a sized sentinel, so we have to increment one-by-one // regardless of the iterator category. - assert(it.stride_count() == M); - assert(it.stride_displacement() == M); - assert(it.equals_count() == expected_equals_count); + assert(static_cast<Difference>(ops.increments) == M); + assert(static_cast<Difference>(ops.decrements) == 0); + assert(ops.zero_moves == 0); + assert(ops.equal_cmps == static_cast<std::size_t>(expected_equals_count)); } } @@ -65,28 +67,24 @@ constexpr void check_forward_sized_sentinel(int* first, int* last, std::iter_dif // Count operations { - auto it = stride_counting_iterator(It(first)); + IteratorOpCounts ops; + auto it = operation_counting_iterator(It(first), &ops); auto sent = distance_apriori_sentinel(size); (void)std::ranges::advance(it, n, sent); if constexpr (std::random_access_iterator<It>) { - assert(it.stride_count() <= 1); - assert(it.stride_displacement() <= 1); + assert(ops.increments + ops.zero_moves == 1); + assert(ops.decrements == 0); } else { - assert(it.stride_count() == M); - assert(it.stride_displacement() == M); + assert(static_cast<Difference>(ops.increments) == M); + assert(ops.decrements == 0); + assert(ops.zero_moves == 0); } } } -struct Expected { - int stride_count; - int stride_displacement; - int equals_count; -}; - template <bool Count, typename It> constexpr void -check_backward(int* first, int* last, std::iter_difference_t<It> n, int* expected, Expected expected_counts) { +check_backward(int* first, int* last, std::iter_difference_t<It> n, int* expected, IteratorOpCounts expected_counts) { // Check preconditions for `advance` when called with negative `n` // (see [range.iter.op.advance]). In addition, allow `n == 0`. assert(n <= 0); @@ -105,16 +103,18 @@ check_backward(int* first, int* last, std::iter_difference_t<It> n, int* expecte // Count operations { - auto it = stride_counting_iterator(It(last)); - auto sent = stride_counting_iterator(It(first)); - static_assert(std::bidirectional_iterator<stride_counting_iterator<It>>); + IteratorOpCounts ops; + auto it = operation_counting_iterator(It(last), &ops); + auto sent = operation_counting_iterator(It(first), &ops); + static_assert(std::bidirectional_iterator<operation_counting_iterator<It>>); static_assert(Count == !std::sized_sentinel_for<It, It>); (void)std::ranges::advance(it, n, sent); - assert(it.stride_count() == expected_counts.stride_count); - assert(it.stride_displacement() == expected_counts.stride_displacement); - assert(it.equals_count() == expected_counts.equals_count); + assert(ops.increments == expected_counts.increments); + assert(ops.decrements == expected_counts.decrements); + assert(ops.zero_moves == expected_counts.zero_moves); + assert(ops.equal_cmps == expected_counts.equal_cmps); } } @@ -217,21 +217,22 @@ constexpr bool test() { { int* expected = n > size ? range : range + size - n; { - Expected expected_counts = { - .stride_count = static_cast<int>(range + size - expected), - .stride_displacement = -expected_counts.stride_count, - .equals_count = n > size ? size + 1 : n, + IteratorOpCounts expected_counts = { + .increments = 0, + .decrements = static_cast<std::size_t>(range + size - expected), + .equal_cmps = static_cast<std::size_t>(n > size ? size + 1 : n), }; check_backward<true, bidirectional_iterator<int*>>(range, range + size, -n, expected, expected_counts); } { - Expected expected_counts = { + IteratorOpCounts expected_counts = { // If `n >= size`, the algorithm can just do `it = std::move(sent);` // instead of doing iterator arithmetic. - .stride_count = (n >= size) ? 0 : 1, - .stride_displacement = (n >= size) ? 0 : 1, - .equals_count = 0, + .increments = 0, + .decrements = static_cast<std::size_t>((n == 0 || n >= size) ? 0 : 1), + .zero_moves = static_cast<std::size_t>(n == 0 && size != 0 ? 1 : 0), + .equal_cmps = 0, }; check_backward<false, random_access_iterator<int*>>(range, range + size, -n, expected, expected_counts); diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_sentinel.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_sentinel.pass.cpp index 2e9a28e..147c26e 100644 --- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_sentinel.pass.cpp +++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_sentinel.pass.cpp @@ -12,6 +12,7 @@ #include <iterator> +#include <algorithm> #include <cassert> #include <cstddef> @@ -31,11 +32,12 @@ constexpr void check_assignable(int* first, int* last, int* expected) { // Count operations if constexpr (Count) { - auto it = stride_counting_iterator(It(first)); - auto sent = assignable_sentinel(stride_counting_iterator(It(last))); + IteratorOpCounts ops; + auto it = operation_counting_iterator(It(first), &ops); + auto sent = assignable_sentinel(operation_counting_iterator(It(last), &ops)); std::ranges::advance(it, sent); assert(base(base(it)) == expected); - assert(it.stride_count() == 0); // because we got here by assigning from last, not by incrementing + assert(ops.increments + ops.decrements == 0); // because we got here by assigning from last, not by incrementing } } @@ -53,13 +55,17 @@ constexpr void check_sized_sentinel(int* first, int* last, int* expected) { // Count operations if constexpr (Count) { - auto it = stride_counting_iterator(It(first)); + IteratorOpCounts ops; + auto it = operation_counting_iterator(It(first), &ops); auto sent = distance_apriori_sentinel(size); std::ranges::advance(it, sent); if constexpr (std::random_access_iterator<It>) { - assert(it.stride_count() == 1); + assert(ops.increments + ops.decrements + ops.zero_moves == 1); } else { - assert(it.stride_count() == size); + const auto big = std::max(ops.increments, ops.decrements); + const auto small = std::min(ops.increments, ops.decrements); + assert(big == static_cast<size_t>(size > 0 ? size : -size)); + assert(small == 0); } } } @@ -78,10 +84,14 @@ constexpr void check_sentinel(int* first, int* last, int* expected) { // Count operations if constexpr (Count) { - auto it = stride_counting_iterator(It(first)); - auto sent = sentinel_wrapper(stride_counting_iterator(It(last))); + IteratorOpCounts ops; + auto it = operation_counting_iterator(It(first), &ops); + auto sent = sentinel_wrapper(operation_counting_iterator(It(last), &ops)); std::ranges::advance(it, sent); - assert(it.stride_count() == size); + const auto big = std::max(ops.increments, ops.decrements); + const auto small = std::min(ops.increments, ops.decrements); + assert(big == static_cast<size_t>(size > 0 ? size : -size)); + assert(small == 0); } } diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp index 45d9271..aa11706 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp @@ -485,17 +485,11 @@ # error "__cpp_lib_make_unique should have the value 201304L in c++23" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should be defined in c++23" -# endif -# if __cpp_lib_out_ptr != 202106L -# error "__cpp_lib_out_ptr should have the value 202106L in c++23" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_out_ptr +# error "__cpp_lib_out_ptr should be defined in c++23" +# endif +# if __cpp_lib_out_ptr != 202106L +# error "__cpp_lib_out_ptr should have the value 202106L in c++23" # endif # ifndef __cpp_lib_ranges @@ -622,17 +616,11 @@ # error "__cpp_lib_make_unique should have the value 201304L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should be defined in c++26" -# endif -# if __cpp_lib_out_ptr != 202311L -# error "__cpp_lib_out_ptr should have the value 202311L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_out_ptr +# error "__cpp_lib_out_ptr should be defined in c++26" +# endif +# if __cpp_lib_out_ptr != 202311L +# error "__cpp_lib_out_ptr should have the value 202311L in c++26" # endif # ifndef __cpp_lib_ranges diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index e1af306..945de95 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -5542,17 +5542,11 @@ # error "__cpp_lib_optional_range_support should not be defined before c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should be defined in c++23" -# endif -# if __cpp_lib_out_ptr != 202106L -# error "__cpp_lib_out_ptr should have the value 202106L in c++23" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_out_ptr +# error "__cpp_lib_out_ptr should be defined in c++23" +# endif +# if __cpp_lib_out_ptr != 202106L +# error "__cpp_lib_out_ptr should have the value 202106L in c++23" # endif # if !defined(_LIBCPP_VERSION) @@ -7383,17 +7377,11 @@ # endif # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should be defined in c++26" -# endif -# if __cpp_lib_out_ptr != 202311L -# error "__cpp_lib_out_ptr should have the value 202311L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_out_ptr +# error "__cpp_lib_out_ptr should be defined in c++26" +# endif +# if __cpp_lib_out_ptr != 202311L +# error "__cpp_lib_out_ptr should have the value 202311L in c++26" # endif # if !defined(_LIBCPP_VERSION) diff --git a/libcxx/test/std/ranges/range.adaptors/range.drop/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.drop/begin.pass.cpp index 28ac53c..7e01b58 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.drop/begin.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.drop/begin.pass.cpp @@ -73,12 +73,12 @@ constexpr bool test() { std::ranges::drop_view dropView7(MoveOnlyView(), 10); assert(dropView7.begin() == globalBuff + 8); - CountedView view8; + IteratorOpCounts opcounts; + CountedView view8(&opcounts); + ; std::ranges::drop_view dropView8(view8, 5); assert(base(base(dropView8.begin())) == globalBuff + 5); - assert(dropView8.begin().stride_count() == 5); - assert(base(base(dropView8.begin())) == globalBuff + 5); - assert(dropView8.begin().stride_count() == 5); + assert(opcounts.increments == 5); static_assert(!BeginInvocable<const ForwardView>); diff --git a/libcxx/test/std/ranges/range.adaptors/range.drop/types.h b/libcxx/test/std/ranges/range.adaptors/range.drop/types.h index ae861bc..73d1e50 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.drop/types.h +++ b/libcxx/test/std/ranges/range.adaptors/range.drop/types.h @@ -120,10 +120,14 @@ struct Range { int *end() const; }; -using CountedIter = stride_counting_iterator<forward_iterator<int*>>; +using CountedIter = operation_counting_iterator<forward_iterator<int*>>; struct CountedView : std::ranges::view_base { - constexpr CountedIter begin() const { return CountedIter(ForwardIter(globalBuff)); } - constexpr CountedIter end() const { return CountedIter(ForwardIter(globalBuff + 8)); } + explicit constexpr CountedView(IteratorOpCounts* opcounts) noexcept : opcounts_(opcounts) {} + constexpr CountedIter begin() const { return CountedIter(ForwardIter(globalBuff), opcounts_); } + constexpr CountedIter end() const { return CountedIter(ForwardIter(globalBuff + 8), opcounts_); } + +private: + IteratorOpCounts* opcounts_; }; struct View : std::ranges::view_base { diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/types.h b/libcxx/test/std/ranges/range.adaptors/range.transform/types.h index 14f8572..cc5679f 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.transform/types.h +++ b/libcxx/test/std/ranges/range.adaptors/range.transform/types.h @@ -119,12 +119,6 @@ struct Range { int *end() const; }; -using CountedIter = stride_counting_iterator<forward_iterator<int*>>; -struct CountedView : std::ranges::view_base { - constexpr CountedIter begin() const { return CountedIter(ForwardIter(globalBuff)); } - constexpr CountedIter end() const { return CountedIter(ForwardIter(globalBuff + 8)); } -}; - struct TimesTwo { constexpr int operator()(int x) const { return x * 2; } }; diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr.general.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr.general.pass.cpp new file mode 100644 index 0000000..d55a0c2 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr.general.pass.cpp @@ -0,0 +1,206 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <memory> + +// [inout.ptr], function template inout_ptr +// template<class Pointer = void, class Smart, class... Args> +// auto inout_ptr(Smart& s, Args&&... args); // since c++23 + +#include <cassert> +#include <memory> +#include <utility> + +#include "../types.h" + +// Test updating the ownership of an `inout_ptr_t`-managed pointer for an API with a non-void pointer type. +// The API returns a new valid object. +void test_replace_int_p() { + auto replace_int_p = [](int** pp) { + assert(**pp == 90); + + delete *pp; + *pp = new int{84}; + }; + + // raw pointer + { + auto rPtr = new int{90}; + + replace_int_p(std::inout_ptr<int*>(rPtr)); + assert(*rPtr == 84); + + delete rPtr; + } + + // std::unique_ptr + { + auto uPtr = std::make_unique<int>(90); + + replace_int_p(std::inout_ptr(uPtr)); + assert(*uPtr == 84); + } + + { + MoveOnlyDeleter<int> del; + std::unique_ptr<int, MoveOnlyDeleter<int>> uPtr{new int{90}}; + + replace_int_p(std::inout_ptr(uPtr, std::move(del))); + assert(*uPtr == 84); + assert(uPtr.get_deleter().wasMoveInitilized == true); + } + + // pointer-like ConstructiblePtr + { + ConstructiblePtr<int> cPtr(new int{90}); + + replace_int_p(std::inout_ptr(cPtr)); + assert(cPtr == 84); + } + + // pointer-like ResettablePtr + { + ResettablePtr<int> rPtr(new int{90}); + + replace_int_p(std::inout_ptr(rPtr)); + assert(rPtr == 84); + } + + // pointer-like NonConstructiblePtr + { + NonConstructiblePtr<int> nPtr; + nPtr.reset(new int{90}); + + replace_int_p(std::inout_ptr(nPtr)); + assert(nPtr == 84); + } +} + +// Test updating the ownership of an `inout_ptr_t`-managed pointer for an API with a non-void pointer type. +// The API returns `nullptr`. +void test_replace_int_p_with_nullptr() { + auto replace_int_p_with_nullptr = [](int** pp) -> void { + assert(**pp == 90); + + delete *pp; + *pp = nullptr; + }; + + // raw pointer + { + // LWG-3897 inout_ptr will not update raw pointer to null + auto rPtr = new int{90}; + + replace_int_p_with_nullptr(std::inout_ptr<int*>(rPtr)); + assert(rPtr == nullptr); + } + + // std::unique_ptr + { + auto uPtr = std::make_unique<int>(90); + + replace_int_p_with_nullptr(std::inout_ptr(uPtr)); + assert(uPtr == nullptr); + } +} + +// Test updating the ownership of an `inout_ptr_t`-managed pointer for an API with a void pointer type. +// The API returns a new valid object. +void test_replace_int_void_p() { + auto replace_int_void_p = [](void** pp) { + assert(*(static_cast<int*>(*pp)) == 90); + + delete static_cast<int*>(*pp); + *pp = new int{84}; + }; + + // raw pointer + { + auto rPtr = new int{90}; + + replace_int_void_p(std::inout_ptr<int*>(rPtr)); + assert(*rPtr == 84); + + delete rPtr; + } + + // std::unique_ptr + { + auto uPtr = std::make_unique<int>(90); + + replace_int_void_p(std::inout_ptr(uPtr)); + assert(*uPtr == 84); + } +} + +// Test updating the ownership of an `inout_ptr_t`-managed pointer for an API with a non-void pointer type. +// The API returns `nullptr`. +void test_replace_int_void_p_with_nullptr() { + auto replace_int_void_p_with_nullptr = [](void** pp) { + assert(*(static_cast<int*>(*pp)) == 90); + + delete static_cast<int*>(*pp); + *pp = nullptr; + }; + + // raw pointer + { + auto rPtr = new int{90}; + + replace_int_void_p_with_nullptr(std::inout_ptr<int*>(rPtr)); + assert(rPtr == nullptr); + } + + // std::unique_ptr + { + auto uPtr = std::make_unique<int>(90); + + replace_int_void_p_with_nullptr(std::inout_ptr(uPtr)); + assert(uPtr == nullptr); + } +} + +// Test updating the ownership of an `inout_ptr_t`-managed pointer for an API with a void pointer type. +// The API returns a new valid object. +void test_replace_nullptr_with_int_p() { + auto replace_nullptr_with_int_p = [](int** pp) { + assert(*pp == nullptr); + + *pp = new int{84}; + }; + + // raw pointer + { + int* rPtr = nullptr; + + replace_nullptr_with_int_p(std::inout_ptr<int*>(rPtr)); + assert(*rPtr == 84); + + delete rPtr; + } + + // std::unique_ptr + { + std::unique_ptr<int> uPtr; + + replace_nullptr_with_int_p(std::inout_ptr(uPtr)); + assert(*uPtr == 84); + } +} + +int main(int, char**) { + test_replace_int_p(); + test_replace_int_p_with_nullptr(); + test_replace_int_void_p(); + test_replace_int_void_p_with_nullptr(); + test_replace_nullptr_with_int_p(); + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr.verify.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr.verify.cpp new file mode 100644 index 0000000..d6d7078 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr.verify.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <memory> + +// [inout.ptr], function template inout_ptr +// template<class Pointer = void, class Smart, class... Args> +// auto inout_ptr(Smart& s, Args&&... args); // since c++23 + +#include <memory> +#include <tuple> + +#include "../types.h" + +int main(int, char**) { + // `std::inout_ptr<>` does not support `std::shared_ptr<>`. + { + std::shared_ptr<int> sPtr; + + // expected-error-re@*:* {{static assertion failed due to requirement {{.*}}std::shared_ptr<> is not supported}} + std::ignore = std::inout_ptr(sPtr); + // expected-error@*:* {{no matching conversion for functional-style cast from 'std::shared_ptr<int>' to 'std::inout_ptr_t<shared_ptr<int>, _Ptr>' (aka 'inout_ptr_t<std::shared_ptr<int>, int *>'}} + std::ignore = std::inout_ptr<int*>(sPtr); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr_t.convert.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr_t.convert.pass.cpp new file mode 100644 index 0000000..230402a --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr_t.convert.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, c++17, c++20 + +// <memory> + +// [inout.ptr.t], class template inout_ptr_t +// template<class Smart, class Pointer, class... Args> +// class inout_ptr_t; // since c++23 + +// operator Pointer*() const noexcept; +// operator void**() const noexcept; + +#include <cassert> +#include <concepts> +#include <memory> + +int main(int, char**) { + // operator Pointer*() + { + std::unique_ptr<int> uPtr = std::make_unique<int>(84); + + const std::inout_ptr_t<std::unique_ptr<int>, int*> ioPtr{uPtr}; + + static_assert(noexcept(ioPtr.operator int**())); + std::same_as<int**> decltype(auto) pPtr = ioPtr.operator int**(); + + assert(**pPtr == 84); + } + + { + std::unique_ptr<int, std::default_delete<int>> uPtr = std::make_unique<int>(84); + + const std::inout_ptr_t<decltype(uPtr), int*, std::default_delete<int>> ioPtr{uPtr, std::default_delete<int>{}}; + + static_assert(noexcept(ioPtr.operator int**())); + std::same_as<int**> decltype(auto) pPtr = ioPtr.operator int**(); + + assert(**pPtr == 84); + } + + // operator void**() + { + std::unique_ptr<int> uPtr = std::make_unique<int>(84); + + const std::inout_ptr_t<std::unique_ptr<int>, void*> ioPtr{uPtr}; + + static_assert(noexcept(ioPtr.operator void**())); + std::same_as<void**> decltype(auto) pPtr = ioPtr.operator void**(); + + assert(**reinterpret_cast<int**>(pPtr) == 84); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr_t.ctor.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr_t.ctor.pass.cpp new file mode 100644 index 0000000..c7e173a --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr_t.ctor.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, c++17, c++20 + +// <memory> + +// [inout.ptr.t], class template inout_ptr_t +// template<class Smart, class Pointer, class... Args> +// class inout_ptr_t; // since c++23 + +// explicit inout_ptr_t(Smart&, Args...); + +#include <cassert> +#include <memory> + +#include "test_convertible.h" +#include "../types.h" + +int main(int, char**) { + { + std::unique_ptr<int> uPtr; + + std::inout_ptr_t<std::unique_ptr<int>, int*>{uPtr}; + + static_assert( + !test_convertible<std::inout_ptr_t<std::unique_ptr<int>, int*>>(), "This constructor must be explicit"); + + // Test the state of the pointer after construction. Complete tests are available in inout_ptr.general.pass.cpp. + assert(uPtr == nullptr); + } + + { + auto deleter = [](auto* p) { delete p; }; + std::unique_ptr<int, decltype(deleter)> uPtr; + + std::inout_ptr_t<std::unique_ptr<int, decltype(deleter)>, int*>{uPtr}; + + static_assert(!test_convertible<std::inout_ptr_t<std::unique_ptr<int, decltype(deleter)>, int*>>(), + "This constructor must be explicit"); + + // Test the state of the pointer after construction. Complete tests are available in inout_ptr.general.pass.cpp. + assert(uPtr == nullptr); + } + + { + std::unique_ptr<int, MoveOnlyDeleter<int>> uPtr; + + std::inout_ptr_t<decltype(uPtr), int*, MoveOnlyDeleter<int>>{uPtr, MoveOnlyDeleter<int>{}}; + + // Test the state of the pointer after construction. Complete tests are available in inout_ptr.general.pass.cpp. + assert(uPtr == nullptr); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr_t.verify.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr_t.verify.cpp new file mode 100644 index 0000000..2270c4c --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr_t.verify.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <memory> + +// [inout.ptr.t], class template inout_ptr_t +// template<class Smart, class Pointer, class... Args> +// class inout_ptr_t; // since c++23 + +#include <memory> + +int main(int, char**) { + // `std::inout_ptr<>` does not support `std::shared_ptr<>`. + { + std::shared_ptr<int> sPtr; + + // expected-error-re@*:* {{static assertion failed due to requirement {{.*}}std::shared_ptr<> is not supported with std::inout_ptr.}} + std::inout_ptr_t<std::shared_ptr<int>, int*>{sPtr}; + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr.general.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr.general.pass.cpp new file mode 100644 index 0000000..a78e22f --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr.general.pass.cpp @@ -0,0 +1,230 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <memory> + +// [out.ptr], function template out_ptr +// template<class Pointer = void, class Smart, class... Args> +// auto out_ptr(Smart& s, Args&&... args); // since c++23 + +#include <cassert> +#include <memory> +#include <utility> + +#include "../types.h" + +// Test updating an `out_ptr_t`-managed pointer for an API with a non-void pointer type. +// The API returns a new valid object. +void test_get_int_p() { + auto get_int_p = [](int** pp) { *pp = new int{84}; }; + + // raw pointer + { + int* rPtr; + + get_int_p(std::out_ptr<int*>(rPtr)); + assert(*rPtr == 84); + + delete rPtr; + } + + // std::unique_ptr + { + std::unique_ptr<int> uPtr; + + get_int_p(std::out_ptr(uPtr)); + assert(*uPtr == 84); + } + + { + MoveOnlyDeleter<int> del; + std::unique_ptr<int, MoveOnlyDeleter<int>> uPtr; + + get_int_p(std::out_ptr(uPtr, std::move(del))); + assert(*uPtr == 84); + assert(uPtr.get_deleter().wasMoveInitilized == true); + } + + // std::shared_ptr + { + std::shared_ptr<int> sPtr; + + get_int_p(std::out_ptr(sPtr, [](auto* p) { + assert(*p == 84); + + delete p; + })); + assert(*sPtr == 84); + } + + // pointer-like ConstructiblePtr + { + ConstructiblePtr<int> cPtr; + + get_int_p(std::out_ptr(cPtr)); + assert(cPtr == 84); + } + + // pointer-like ResettablePtr + { + ResettablePtr<int> rPtr{nullptr}; + + get_int_p(std::out_ptr(rPtr)); + assert(rPtr == 84); + } + + // NonConstructiblePtr + { + NonConstructiblePtr<int> nPtr; + + get_int_p(std::out_ptr(nPtr)); + assert(nPtr == 84); + } +} + +// Test updating an `out_ptr_t`-managed pointer for an API with a non-void pointer type. +// The API returns `nullptr`. +void test_get_int_p_nullptr() { + auto get_int_p_nullptr = [](int** pp) { *pp = nullptr; }; + // raw pointer + { + int* rPtr; + + get_int_p_nullptr(std::out_ptr<int*>(rPtr)); + assert(rPtr == nullptr); + + delete rPtr; + } + + // std::unique_ptr + { + std::unique_ptr<int> uPtr; + + get_int_p_nullptr(std::out_ptr(uPtr)); + assert(uPtr == nullptr); + } + + // std::shared_ptr + { + std::shared_ptr<int> sPtr; + + get_int_p_nullptr(std::out_ptr(sPtr, [](auto* p) { + assert(p == nullptr); + + delete p; + })); + assert(sPtr == nullptr); + } +} + +// Test updating an `out_ptr_t`-managed pointer for an API with a void pointer type. +// The API returns a new valid object. +void test_get_int_void_p() { + auto get_int_void_p = [](void** pp) { *(reinterpret_cast<int**>(pp)) = new int{84}; }; + + // raw pointer + { + int* rPtr; + + get_int_void_p(std::out_ptr(rPtr)); + assert(*rPtr == 84); + + delete rPtr; + } + + // std::unique_ptr + { + std::unique_ptr<int> uPtr; + + get_int_void_p(std::out_ptr(uPtr)); + assert(*uPtr == 84); + } + + // std::shared_ptr + { + std::shared_ptr<int> sPtr; + + get_int_void_p(std::out_ptr(sPtr, [](auto* p) { + assert(*p == 84); + + delete p; + })); + assert(*sPtr == 84); + } + + // pointer-like ConstructiblePtr + { + ConstructiblePtr<int> cPtr; + + get_int_void_p(std::out_ptr(cPtr)); + assert(cPtr == 84); + } + + // pointer-like ResettablePtr + { + ResettablePtr<int> rPtr{nullptr}; + + get_int_void_p(std::out_ptr(rPtr)); + assert(rPtr == 84); + } + + // NonConstructiblePtr + { + NonConstructiblePtr<int> nPtr; + + get_int_void_p(std::out_ptr(nPtr)); + assert(nPtr == 84); + } +} + +// Test updating an `out_ptr_t`-managed pointer for an API with a void pointer type. +// The API returns `nullptr`. +void test_get_int_void_p_nullptr() { + auto get_int_void_p_nullptr = [](void** pp) { *pp = nullptr; }; + + // raw pointer + { + int* rPtr; + + get_int_void_p_nullptr(std::out_ptr<int*>(rPtr)); + assert(rPtr == nullptr); + + delete rPtr; + } + + // std::unique_ptr + { + std::unique_ptr<int> uPtr; + + get_int_void_p_nullptr(std::out_ptr(uPtr)); + assert(uPtr == nullptr); + } + + // std::shared_ptr + { + std::shared_ptr<int> sPtr; + + get_int_void_p_nullptr(std::out_ptr(sPtr, [](auto* p) { + assert(p == nullptr); + + delete p; + })); + assert(sPtr == nullptr); + } +} + +int main(int, char**) { + test_get_int_p(); + test_get_int_p_nullptr(); + test_get_int_void_p(); + test_get_int_void_p_nullptr(); + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr.verify.cpp b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr.verify.cpp new file mode 100644 index 0000000..1fe78ec --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr.verify.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <memory> + +// [out.ptr], function template out_ptr +// template<class Pointer = void, class Smart, class... Args> +// auto out_ptr(Smart& s, Args&&... args); // since c++23 + +#include <memory> +#include <tuple> + +#include "../types.h" + +int main(int, char**) { + // `std::out_ptr<>` requires `std::shared_ptr<>` with a deleter. + { + std::shared_ptr<int> sPtr; + + // expected-error-re@*:* {{static assertion failed due to requirement {{.*}}Using std::shared_ptr<> without a deleter in std::out_ptr is not supported.}} + std::ignore = std::out_ptr(sPtr); + // expected-error@*:* {{no matching conversion for functional-style cast from 'std::shared_ptr<int>' to 'std::out_ptr_t<shared_ptr<int>, _Ptr>' (aka 'out_ptr_t<std::shared_ptr<int>, int *>')}} + std::ignore = std::out_ptr<int*>(sPtr); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr_t.convert.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr_t.convert.pass.cpp new file mode 100644 index 0000000..828a5d0 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr_t.convert.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, c++17, c++20 + +// <memory> + +// [out.ptr.t], class template out_ptr_t +// template<class Smart, class Pointer, class... Args> +// class out_ptr_t; // since c++23 + +// operator Pointer*() const noexcept; +// operator void**() const noexcept; + +#include <cassert> +#include <concepts> +#include <memory> + +int main(int, char**) { + // operator Pointer*() + { + std::unique_ptr<int> uPtr; + + const std::out_ptr_t<std::unique_ptr<int>, int*> oPtr{uPtr}; + + static_assert(noexcept(oPtr.operator int**())); + std::same_as<int**> decltype(auto) pPtr = oPtr.operator int**(); + + assert(*pPtr == nullptr); + } + + { + std::unique_ptr<int, std::default_delete<int>> uPtr; + + const std::out_ptr_t<decltype(uPtr), int*, std::default_delete<int>> oPtr{uPtr, std::default_delete<int>{}}; + + static_assert(noexcept(oPtr.operator int**())); + std::same_as<int**> decltype(auto) pPtr = oPtr.operator int**(); + + assert(*pPtr == nullptr); + } + + // operator void**() + { + std::unique_ptr<int> uPtr; + + const std::out_ptr_t<std::unique_ptr<int>, void*> oPtr{uPtr}; + + static_assert(noexcept(oPtr.operator void**())); + std::same_as<void**> decltype(auto) pPtr = oPtr.operator void**(); + + assert(*pPtr == nullptr); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr_t.ctor.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr_t.ctor.pass.cpp new file mode 100644 index 0000000..29e1258 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr_t.ctor.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <memory> + +// [out.ptr.t], class template out_ptr_t +// template<class Smart, class Pointer, class... Args> +// class out_ptr_t; // since c++23 + +// explicit out_ptr_t(Smart&, Args...); + +#include <cassert> +#include <memory> + +#include "test_convertible.h" +#include "../types.h" + +int main(int, char**) { + { + std::unique_ptr<int> uPtr; + + std::out_ptr_t<std::unique_ptr<int>, int*>{uPtr}; + + static_assert(!test_convertible<std::out_ptr_t<std::unique_ptr<int>, int*>>(), "This constructor must be explicit"); + + // Test the state of the pointer after construction. Complete tests are available in out_ptr.general.pass.cpp + assert(uPtr == nullptr); + } + + { + std::unique_ptr<int, std::default_delete<int>> uPtr; + + std::out_ptr_t<decltype(uPtr), int*, std::default_delete<int>>{uPtr, std::default_delete<int>{}}; + + static_assert(!test_convertible<std::out_ptr_t<decltype(uPtr), int*, std::default_delete<int>>>(), + "This constructor must be explicit"); + + // Test the state of the pointer after construction. Complete tests are available in out_ptr.general.pass.cpp + assert(uPtr == nullptr); + } + + { + std::unique_ptr<int, MoveOnlyDeleter<int>> uPtr; + + std::out_ptr_t<decltype(uPtr), int*, MoveOnlyDeleter<int>>{uPtr, MoveOnlyDeleter<int>{}}; + + // Test the state of the pointer after construction. Complete tests are available in out_ptr.general.pass.cpp + assert(uPtr == nullptr); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr_t.verify.cpp b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr_t.verify.cpp new file mode 100644 index 0000000..cbe96e7 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr_t.verify.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <memory> + +// [out.ptr.t], class template out_ptr_t +// template<class Smart, class Pointer, class... Args> +// class out_ptr_t; // since c++23 + +#include <memory> + +int main(int, char**) { + // `std::out_ptr_t<>` requires `std::shared_ptr<>` with a deleter. + { + std::shared_ptr<int> sPtr; + + // expected-error-re@*:* {{static assertion failed due to requirement {{.*}}Using std::shared_ptr<> without a deleter in std::out_ptr is not supported.}} + std::out_ptr_t<std::shared_ptr<int>, int*>{sPtr}; + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/types.h b/libcxx/test/std/utilities/smartptr/adapt/types.h new file mode 100644 index 0000000..0da6007 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/types.h @@ -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 +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_LIBCXX_UTILITIES_SMARTPTR_ADAPT_TYPES_H +#define TEST_LIBCXX_UTILITIES_SMARTPTR_ADAPT_TYPES_H + +#include <type_traits> +#include <memory> + +#include "test_macros.h" + +// Custom deleters. + +template <typename T> +struct MoveOnlyDeleter { + MoveOnlyDeleter() = default; + MoveOnlyDeleter(const MoveOnlyDeleter&) = delete; + MoveOnlyDeleter& operator=(const MoveOnlyDeleter&) = delete; + MoveOnlyDeleter(MoveOnlyDeleter&&) : wasMoveInitilized{true} {} + MoveOnlyDeleter& operator=(MoveOnlyDeleter&&) = default; + + void operator()(T* p) const { delete p; } + + bool wasMoveInitilized = false; +}; + +// Custom pointer types. + +template <typename T> +struct ConstructiblePtr { + using pointer = T*; + std::unique_ptr<T> ptr; + + ConstructiblePtr() = default; + explicit ConstructiblePtr(T* p) : ptr{p} {} + + auto operator==(T val) { return *ptr == val; } + + auto* get() const { return ptr.get(); } + + void release() { ptr.release(); } +}; + +LIBCPP_STATIC_ASSERT(std::is_same_v<std::__pointer_of_t< ConstructiblePtr<int>>, int* >); +static_assert(std::is_constructible_v< ConstructiblePtr<int>, int* >); + +struct ResetArg {}; + +template <typename T> +struct ResettablePtr { + using element_type = T; + std::unique_ptr<T> ptr; + + explicit ResettablePtr(T* p) : ptr{p} {} + + auto operator*() const { return *ptr; } + + auto operator==(T val) { return *ptr == val; } + + void reset() { ptr.reset(); } + void reset(T* p, ResetArg) { ptr.reset(p); } + + auto* get() const { return ptr.get(); } + + void release() { ptr.release(); } +}; + +LIBCPP_STATIC_ASSERT(std::is_same_v<std::__pointer_of_t< ResettablePtr<int>>, int* >); +static_assert(std::is_constructible_v< ResettablePtr<int>, int* >); + +template <typename T> +struct NonConstructiblePtr : public ResettablePtr<T> { + NonConstructiblePtr() : NonConstructiblePtr::ResettablePtr(nullptr) {}; + + void reset(T* p) { ResettablePtr<T>::ptr.reset(p); } +}; + +LIBCPP_STATIC_ASSERT(std::is_same_v<std::__pointer_of_t< NonConstructiblePtr<int>>, int* >); +static_assert(!std::is_constructible_v< NonConstructiblePtr<int>, int* >); + +#endif // TEST_LIBCXX_UTILITIES_SMARTPTR_ADAPT_TYPES_H diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index bb3ba21..31564a3 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -725,17 +725,18 @@ struct common_input_iterator { # endif // TEST_STD_VER >= 20 -// Iterator adaptor that counts the number of times the iterator has had a successor/predecessor -// operation or an equality comparison operation called. Has three recorders: -// * `stride_count`, which records the total number of calls to an op++, op--, op+=, or op-=. -// * `stride_displacement`, which records the displacement of the calls. This means that both -// op++/op+= will increase the displacement counter by 1, and op--/op-= will decrease the -// displacement counter by 1. -// * `equals_count`, which records the total number of calls to an op== or op!=. If compared -// against a sentinel object, that sentinel object must call the `record_equality_comparison` -// function so that the comparison is counted correctly. +struct IteratorOpCounts { + std::size_t increments = 0; ///< Number of times the iterator moved forward (++it, it++, it+=positive, it-=negative). + std::size_t decrements = 0; ///< Number of times the iterator moved backward (--it, it--, it-=positive, it+=negative). + std::size_t zero_moves = 0; ///< Number of times a call was made to move the iterator by 0 positions (it+=0, it-=0). + std::size_t equal_cmps = 0; ///< Total number of calls to op== or op!=. If compared against a sentinel object, that + /// sentinel object must call the `record_equality_comparison` function so that the + /// comparison is counted correctly. +}; + +// Iterator adaptor that records its operation counts in a IteratorOpCounts template <class It> -class stride_counting_iterator { +class operation_counting_iterator { public: using value_type = typename iter_value_or_void<It>::type; using difference_type = std::iter_difference_t<It>; @@ -747,147 +748,160 @@ public: std::conditional_t<std::input_iterator<It>, std::input_iterator_tag, /* else */ std::output_iterator_tag >>>>>; + using iterator_category = iterator_concept; - stride_counting_iterator() requires std::default_initializable<It> = default; - - constexpr explicit stride_counting_iterator(It const& it) : base_(base(it)) { } + operation_counting_iterator() + requires std::default_initializable<It> + = default; - friend constexpr It base(stride_counting_iterator const& it) { return It(it.base_); } + constexpr explicit operation_counting_iterator(It const& it, IteratorOpCounts* counts = nullptr) + : base_(base(it)), counts_(counts) {} - constexpr difference_type stride_count() const { return stride_count_; } + constexpr operation_counting_iterator(const operation_counting_iterator& o) { *this = o; } + constexpr operation_counting_iterator(operation_counting_iterator&& o) { *this = o; } - constexpr difference_type stride_displacement() const { return stride_displacement_; } + constexpr operation_counting_iterator& operator=(const operation_counting_iterator& o) = default; + constexpr operation_counting_iterator& operator=(operation_counting_iterator&& o) { return *this = o; } - constexpr difference_type equals_count() const { return equals_count_; } + friend constexpr It base(operation_counting_iterator const& it) { return It(it.base_); } constexpr decltype(auto) operator*() const { return *It(base_); } constexpr decltype(auto) operator[](difference_type n) const { return It(base_)[n]; } - constexpr stride_counting_iterator& operator++() { - It tmp(base_); - base_ = base(++tmp); - ++stride_count_; - ++stride_displacement_; - return *this; + constexpr operation_counting_iterator& operator++() { + It tmp(base_); + base_ = base(++tmp); + moved_by(1); + return *this; } constexpr void operator++(int) { ++*this; } - constexpr stride_counting_iterator operator++(int) - requires std::forward_iterator<It> + constexpr operation_counting_iterator operator++(int) + requires std::forward_iterator<It> { - auto temp = *this; - ++*this; - return temp; + auto temp = *this; + ++*this; + return temp; } - constexpr stride_counting_iterator& operator--() - requires std::bidirectional_iterator<It> + constexpr operation_counting_iterator& operator--() + requires std::bidirectional_iterator<It> { - It tmp(base_); - base_ = base(--tmp); - ++stride_count_; - --stride_displacement_; - return *this; + It tmp(base_); + base_ = base(--tmp); + moved_by(-1); + return *this; } - constexpr stride_counting_iterator operator--(int) - requires std::bidirectional_iterator<It> + constexpr operation_counting_iterator operator--(int) + requires std::bidirectional_iterator<It> { - auto temp = *this; - --*this; - return temp; + auto temp = *this; + --*this; + return temp; } - constexpr stride_counting_iterator& operator+=(difference_type const n) - requires std::random_access_iterator<It> + constexpr operation_counting_iterator& operator+=(difference_type const n) + requires std::random_access_iterator<It> { - It tmp(base_); - base_ = base(tmp += n); - ++stride_count_; - ++stride_displacement_; - return *this; + It tmp(base_); + base_ = base(tmp += n); + moved_by(n); + return *this; } - constexpr stride_counting_iterator& operator-=(difference_type const n) - requires std::random_access_iterator<It> + constexpr operation_counting_iterator& operator-=(difference_type const n) + requires std::random_access_iterator<It> { - It tmp(base_); - base_ = base(tmp -= n); - ++stride_count_; - --stride_displacement_; - return *this; + It tmp(base_); + base_ = base(tmp -= n); + moved_by(-n); + return *this; } - friend constexpr stride_counting_iterator operator+(stride_counting_iterator it, difference_type n) - requires std::random_access_iterator<It> + friend constexpr operation_counting_iterator operator+(operation_counting_iterator it, difference_type n) + requires std::random_access_iterator<It> { - return it += n; + return it += n; } - friend constexpr stride_counting_iterator operator+(difference_type n, stride_counting_iterator it) - requires std::random_access_iterator<It> + friend constexpr operation_counting_iterator operator+(difference_type n, operation_counting_iterator it) + requires std::random_access_iterator<It> { - return it += n; + return it += n; } - friend constexpr stride_counting_iterator operator-(stride_counting_iterator it, difference_type n) - requires std::random_access_iterator<It> + friend constexpr operation_counting_iterator operator-(operation_counting_iterator it, difference_type n) + requires std::random_access_iterator<It> { - return it -= n; + return it -= n; } - friend constexpr difference_type operator-(stride_counting_iterator const& x, stride_counting_iterator const& y) - requires std::sized_sentinel_for<It, It> + friend constexpr difference_type + operator-(operation_counting_iterator const& x, operation_counting_iterator const& y) + requires std::sized_sentinel_for<It, It> { - return base(x) - base(y); + return base(x) - base(y); } - constexpr void record_equality_comparison() const { ++equals_count_; } + constexpr void record_equality_comparison() const { + if (counts_ != nullptr) + ++counts_->equal_cmps; + } - constexpr bool operator==(stride_counting_iterator const& other) const - requires std::sentinel_for<It, It> + constexpr bool operator==(operation_counting_iterator const& other) const + requires std::sentinel_for<It, It> { record_equality_comparison(); return It(base_) == It(other.base_); } - friend constexpr bool operator<(stride_counting_iterator const& x, stride_counting_iterator const& y) - requires std::random_access_iterator<It> + friend constexpr bool operator<(operation_counting_iterator const& x, operation_counting_iterator const& y) + requires std::random_access_iterator<It> { - return It(x.base_) < It(y.base_); + return It(x.base_) < It(y.base_); } - friend constexpr bool operator>(stride_counting_iterator const& x, stride_counting_iterator const& y) - requires std::random_access_iterator<It> + friend constexpr bool operator>(operation_counting_iterator const& x, operation_counting_iterator const& y) + requires std::random_access_iterator<It> { - return It(x.base_) > It(y.base_); + return It(x.base_) > It(y.base_); } - friend constexpr bool operator<=(stride_counting_iterator const& x, stride_counting_iterator const& y) - requires std::random_access_iterator<It> + friend constexpr bool operator<=(operation_counting_iterator const& x, operation_counting_iterator const& y) + requires std::random_access_iterator<It> { - return It(x.base_) <= It(y.base_); + return It(x.base_) <= It(y.base_); } - friend constexpr bool operator>=(stride_counting_iterator const& x, stride_counting_iterator const& y) - requires std::random_access_iterator<It> + friend constexpr bool operator>=(operation_counting_iterator const& x, operation_counting_iterator const& y) + requires std::random_access_iterator<It> { - return It(x.base_) >= It(y.base_); + return It(x.base_) >= It(y.base_); } template <class T> void operator,(T const &) = delete; private: + constexpr void moved_by(difference_type n) { + if (counts_ == nullptr) + return; + if (n > 0) + ++counts_->increments; + else if (n < 0) + ++counts_->decrements; + else + ++counts_->zero_moves; + } + decltype(base(std::declval<It>())) base_; - difference_type stride_count_ = 0; - difference_type stride_displacement_ = 0; - mutable difference_type equals_count_ = 0; + IteratorOpCounts* counts_ = nullptr; }; template <class It> -stride_counting_iterator(It) -> stride_counting_iterator<It>; +operation_counting_iterator(It) -> operation_counting_iterator<It>; #endif // TEST_STD_VER > 17 diff --git a/libcxx/utils/ci/apple-install-libcxx.sh b/libcxx/utils/ci/apple-install-libcxx.sh index ddefabe..4872253 100755 --- a/libcxx/utils/ci/apple-install-libcxx.sh +++ b/libcxx/utils/ci/apple-install-libcxx.sh @@ -114,8 +114,14 @@ for arch in ${architectures}; do # Then LLVM would guess the LLVM_DEFAULT_TARGET_TRIPLE properly and we wouldn't have to specify it. target=$(xcrun clang -arch ${arch} -xc - -### 2>&1 | grep --only-matching -E '"-triple" ".+?"' | grep --only-matching -E '"[^ ]+-apple-[^ ]+?"' | tr -d '"') - step "Building libc++.dylib and libc++abi.dylib for architecture ${arch}" mkdir -p "${build_dir}/${arch}" + + step "Building shims to make libc++ compatible with the system libc++ on Apple platforms when running the tests" + shims_library="${build_dir}/${arch}/apple-system-shims.a" + # Note that this doesn't need to match the Standard version used to build the rest of the library. + xcrun clang++ -c -std=c++2b -target ${target} "${llvm_root}/libcxxabi/src/vendor/apple/shims.cpp" -static -o "${shims_library}" + + step "Building libc++.dylib and libc++abi.dylib for architecture ${arch}" xcrun cmake -S "${llvm_root}/runtimes" \ -B "${build_dir}/${arch}" \ -GNinja \ @@ -127,9 +133,9 @@ for arch in ${architectures}; do -DCMAKE_OSX_ARCHITECTURES="${arch}" \ -DLIBCXXABI_LIBRARY_VERSION="${version}" \ -DLIBCXX_LIBRARY_VERSION="${version}" \ - -DLIBCXX_TEST_PARAMS="target_triple=${target};stdlib=apple-libc++" \ - -DLIBCXXABI_TEST_PARAMS="target_triple=${target};stdlib=apple-libc++" \ - -DLIBUNWIND_TEST_PARAMS="target_triple=${target};stdlib=apple-libc++" + -DLIBCXX_TEST_PARAMS="target_triple=${target};apple_system_shims=${shims_library}" \ + -DLIBCXXABI_TEST_PARAMS="target_triple=${target};apple_system_shims=${shims_library}" \ + -DLIBUNWIND_TEST_PARAMS="target_triple=${target};apple_system_shims=${shims_library}" if [ "$headers_only" = true ]; then xcrun cmake --build "${build_dir}/${arch}" --target install-cxx-headers install-cxxabi-headers -- -v diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index 65ba2f8..a09beb2 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -949,7 +949,6 @@ feature_test_macros = [ "c++26": 202311, # P2833R2 Freestanding Library: inout expected span }, "headers": ["memory"], - "unimplemented": True, }, { "name": "__cpp_lib_parallel_algorithm", diff --git a/libcxxabi/src/vendor/apple/shims.cpp b/libcxxabi/src/vendor/apple/shims.cpp new file mode 100644 index 0000000..65152f7 --- /dev/null +++ b/libcxxabi/src/vendor/apple/shims.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// +// These shims implement symbols that are present in the system libc++ on Apple platforms +// but are not implemented in upstream libc++. This allows testing libc++ under a system +// library configuration, which requires the just-built libc++ to be ABI compatible with +// the system library it is replacing. +// + +#include <cstddef> +#include <new> + +namespace std { // purposefully not versioned, like align_val_t +enum class __type_descriptor_t : unsigned long long; +} + +_LIBCPP_OVERRIDABLE_FUNC_VIS void* operator new(std::size_t __sz, std::__type_descriptor_t) { + return ::operator new(__sz); +} + +_LIBCPP_OVERRIDABLE_FUNC_VIS void* operator new(std::size_t __sz, const std::nothrow_t& __nt, + std::__type_descriptor_t) noexcept { + return ::operator new(__sz, __nt); +} + +_LIBCPP_OVERRIDABLE_FUNC_VIS void* operator new[](std::size_t __sz, std::__type_descriptor_t) { + return ::operator new[](__sz); +} + +_LIBCPP_OVERRIDABLE_FUNC_VIS void* operator new[](std::size_t __sz, const std::nothrow_t& __nt, + std::__type_descriptor_t) noexcept { + return ::operator new(__sz, __nt); +} + +_LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete(void* __p, std::__type_descriptor_t) noexcept { + return ::operator delete(__p); +} + +_LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete(void* __p, const std::nothrow_t& __nt, + std::__type_descriptor_t) noexcept { + return ::operator delete(__p, __nt); +} + +_LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete[](void* __p, std::__type_descriptor_t) noexcept { + return ::operator delete[](__p); +} + +_LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete[](void* __p, const std::nothrow_t& __nt, + std::__type_descriptor_t) noexcept { + return ::operator delete[](__p, __nt); +} + +_LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete(void* __p, std::size_t __sz, std::__type_descriptor_t) noexcept { + return ::operator delete(__p, __sz); +} + +_LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete[](void* __p, std::size_t __sz, std::__type_descriptor_t) noexcept { + return ::operator delete[](__p, __sz); +} diff --git a/libcxxabi/test/configs/apple-libc++abi-shared.cfg.in b/libcxxabi/test/configs/apple-libc++abi-shared.cfg.in new file mode 100644 index 0000000..537fe82 --- /dev/null +++ b/libcxxabi/test/configs/apple-libc++abi-shared.cfg.in @@ -0,0 +1,49 @@ +# Testing configuration for Apple's system libc++abi. +# +# This configuration differs from a normal LLVM shared library configuration in +# that we must use DYLD_LIBRARY_PATH to run the tests against the just-built library, +# since Apple's libc++abi has an absolute install_name. +# +# Finally, we also link against an artificial shims library that provides +# the functionality necessary for the upstream libc++abi to be usable in place +# of a system-provided libc++abi. Without that, attempting to replace the system +# libc++abi with DYLD_LIBRARY_PATH would result in missing symbols and other similar +# issues since the upstream libc++abi does not contain all the symbols provided by +# the system library. + +lit_config.load_config(config, '@CMAKE_CURRENT_BINARY_DIR@/cmake-bridge.cfg') + +import os, site +site.addsitedir(os.path.join('@LIBCXXABI_LIBCXX_PATH@', 'utils')) +import libcxx.test.params, libcxx.test.config, libcxx.test.dsl +ADDITIONAL_PARAMETERS = [ + libcxx.test.dsl.Parameter(name='apple_system_shims', type=str, + actions=lambda path: [libcxx.test.dsl.AddSubstitution('%{apple-system-shims}', path)], + help=""" + Path to a pre-built object file or static archive that contains shims necessary to + allow replacing the system libc++abi by the just-built one. + """), +] + +config.substitutions.append(('%{flags}', + '-isysroot {}'.format('@CMAKE_OSX_SYSROOT@') if '@CMAKE_OSX_SYSROOT@' else '' +)) +config.substitutions.append(('%{compile_flags}', + '-nostdinc++ -I %{include} -I %{cxx-include} -I %{cxx-target-include} %{maybe-include-libunwind} -D_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS ' + + '-I %{libcxx}/test/support -I %{libcxx}/src' +)) +config.substitutions.append(('%{link_flags}', + '-nostdlib++ -L %{lib} -lc++ %{apple-system-shims}' +)) +config.substitutions.append(('%{exec}', + '%{executor} --execdir %T --env DYLD_LIBRARY_PATH=%{lib} -- ' +)) + +config.stdlib = 'apple-libc++' + +libcxx.test.config.configure( + libcxx.test.params.DEFAULT_PARAMETERS + ADDITIONAL_PARAMETERS, + libcxx.test.features.DEFAULT_FEATURES, + config, + lit_config +) diff --git a/lldb/bindings/headers.swig b/lldb/bindings/headers.swig index c915046..c0dde90 100644 --- a/lldb/bindings/headers.swig +++ b/lldb/bindings/headers.swig @@ -21,6 +21,7 @@ #include "lldb/API/SBCommandReturnObject.h" #include "lldb/API/SBCommunication.h" #include "lldb/API/SBCompileUnit.h" +#include "lldb/API/SBSaveCoreOptions.h" #include "lldb/API/SBData.h" #include "lldb/API/SBDebugger.h" #include "lldb/API/SBDeclaration.h" diff --git a/lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i b/lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i diff --git a/lldb/bindings/interfaces.swig b/lldb/bindings/interfaces.swig index 0953f4c..8a6fed9 100644 --- a/lldb/bindings/interfaces.swig +++ b/lldb/bindings/interfaces.swig @@ -25,6 +25,7 @@ %include "./interface/SBCommandReturnObjectDocstrings.i" %include "./interface/SBCommunicationDocstrings.i" %include "./interface/SBCompileUnitDocstrings.i" +%include "./interface/SBSaveCoreOptionsDocstrings.i" %include "./interface/SBDataDocstrings.i" %include "./interface/SBDebuggerDocstrings.i" %include "./interface/SBDeclarationDocstrings.i" @@ -101,6 +102,7 @@ %include "lldb/API/SBCommandReturnObject.h" %include "lldb/API/SBCommunication.h" %include "lldb/API/SBCompileUnit.h" +%include "lldb/API/SBSaveCoreOptions.h" %include "lldb/API/SBData.h" %include "lldb/API/SBDebugger.h" %include "lldb/API/SBDeclaration.h" diff --git a/lldb/include/lldb/API/LLDB.h b/lldb/include/lldb/API/LLDB.h index d8cc9f5..40368e0 100644 --- a/lldb/include/lldb/API/LLDB.h +++ b/lldb/include/lldb/API/LLDB.h @@ -57,6 +57,7 @@ #include "lldb/API/SBQueue.h" #include "lldb/API/SBQueueItem.h" #include "lldb/API/SBReproducer.h" +#include "lldb/API/SBSaveCoreOptions.h" #include "lldb/API/SBSection.h" #include "lldb/API/SBSourceManager.h" #include "lldb/API/SBStatisticsOptions.h" diff --git a/lldb/include/lldb/API/SBDefines.h b/lldb/include/lldb/API/SBDefines.h index 87c0a1c..f42e2be 100644 --- a/lldb/include/lldb/API/SBDefines.h +++ b/lldb/include/lldb/API/SBDefines.h @@ -61,6 +61,7 @@ class LLDB_API SBCommandPluginInterface; class LLDB_API SBCommandReturnObject; class LLDB_API SBCommunication; class LLDB_API SBCompileUnit; +class LLDB_API SBSaveCoreOptions; class LLDB_API SBData; class LLDB_API SBDebugger; class LLDB_API SBDeclaration; diff --git a/lldb/include/lldb/API/SBError.h b/lldb/include/lldb/API/SBError.h index 1a720a4..17f2c6c 100644 --- a/lldb/include/lldb/API/SBError.h +++ b/lldb/include/lldb/API/SBError.h @@ -77,6 +77,7 @@ protected: friend class SBBreakpointName; friend class SBCommandReturnObject; friend class SBCommunication; + friend class SBSaveCoreOptions; friend class SBData; friend class SBDebugger; friend class SBFile; diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index beefa19..3664184 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -78,6 +78,7 @@ private: friend class SBTarget; friend class SBThread; friend class SBTrace; + friend class SBSaveCoreOptions; SBFileSpec(const lldb_private::FileSpec &fspec); diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h index a6ab7ae..778be79 100644 --- a/lldb/include/lldb/API/SBProcess.h +++ b/lldb/include/lldb/API/SBProcess.h @@ -378,6 +378,12 @@ public: /// \param[in] file_name - The name of the file to save the core file to. lldb::SBError SaveCore(const char *file_name); + /// Save the state of the process with the desired settings + /// as defined in the options object. + /// + /// \param[in] options - The options to use when saving the core file. + lldb::SBError SaveCore(SBSaveCoreOptions &options); + /// Query the address load_addr and store the details of the memory /// region that contains it in the supplied SBMemoryRegionInfo object. /// To iterate over all memory regions use GetMemoryRegionList. diff --git a/lldb/include/lldb/API/SBSaveCoreOptions.h b/lldb/include/lldb/API/SBSaveCoreOptions.h new file mode 100644 index 0000000..b8659bf1 --- /dev/null +++ b/lldb/include/lldb/API/SBSaveCoreOptions.h @@ -0,0 +1,69 @@ +//===-- SBSaveCoreOptions.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 LLDB_API_SBSAVECOREOPTIONS_H +#define LLDB_API_SBSAVECOREOPTIONS_H + +#include "lldb/API/SBDefines.h" +#include "lldb/Symbol/SaveCoreOptions.h" + +namespace lldb { + +class LLDB_API SBSaveCoreOptions { +public: + SBSaveCoreOptions(); + SBSaveCoreOptions(const lldb::SBSaveCoreOptions &rhs); + ~SBSaveCoreOptions() = default; + + const SBSaveCoreOptions &operator=(const lldb::SBSaveCoreOptions &rhs); + + /// Set the plugin name. Supplying null or empty string will reset + /// the option. + /// + /// \param plugin Name of the object file plugin. + SBError SetPluginName(const char *plugin); + + /// Get the Core dump plugin name, if set. + /// + /// \return The name of the plugin, or null if not set. + const char *GetPluginName() const; + + /// Set the Core dump style. + /// + /// \param style The style of the core dump. + void SetStyle(lldb::SaveCoreStyle style); + + /// Get the Core dump style, if set. + /// + /// \return The core dump style, or undefined if not set. + lldb::SaveCoreStyle GetStyle() const; + + /// Set the output file path + /// + /// \param output_file a + /// \class SBFileSpec object that describes the output file. + void SetOutputFile(SBFileSpec output_file); + + /// Get the output file spec + /// + /// \return The output file spec. + SBFileSpec GetOutputFile() const; + + /// Reset all options. + void Clear(); + +protected: + friend class SBProcess; + lldb_private::SaveCoreOptions &ref() const; + +private: + std::unique_ptr<lldb_private::SaveCoreOptions> m_opaque_up; +}; // SBSaveCoreOptions +} // namespace lldb + +#endif // LLDB_API_SBSAVECOREOPTIONS_H diff --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h index f2296e2..38a291d 100644 --- a/lldb/include/lldb/Core/PluginManager.h +++ b/lldb/include/lldb/Core/PluginManager.h @@ -178,6 +178,8 @@ public: static bool UnregisterPlugin(ObjectFileCreateInstance create_callback); + static bool IsRegisteredObjectFilePluginName(llvm::StringRef name); + static ObjectFileCreateInstance GetObjectFileCreateCallbackAtIndex(uint32_t idx); @@ -191,9 +193,7 @@ public: GetObjectFileCreateMemoryCallbackForPluginName(llvm::StringRef name); static Status SaveCore(const lldb::ProcessSP &process_sp, - const FileSpec &outfile, - lldb::SaveCoreStyle &core_style, - llvm::StringRef plugin_name); + const lldb_private::SaveCoreOptions &core_options); // ObjectContainer static bool RegisterPlugin( diff --git a/lldb/include/lldb/Symbol/SaveCoreOptions.h b/lldb/include/lldb/Symbol/SaveCoreOptions.h new file mode 100644 index 0000000..583bc1f --- /dev/null +++ b/lldb/include/lldb/Symbol/SaveCoreOptions.h @@ -0,0 +1,44 @@ +//===-- SaveCoreOptions.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 LLDB_SOURCE_PLUGINS_OBJECTFILE_SaveCoreOPTIONS_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_SaveCoreOPTIONS_H + +#include "lldb/Utility/FileSpec.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-types.h" + +#include <optional> +#include <string> + +namespace lldb_private { + +class SaveCoreOptions { +public: + SaveCoreOptions(){}; + ~SaveCoreOptions() = default; + + lldb_private::Status SetPluginName(const char *name); + std::optional<std::string> GetPluginName() const; + + void SetStyle(lldb::SaveCoreStyle style); + lldb::SaveCoreStyle GetStyle() const; + + void SetOutputFile(lldb_private::FileSpec file); + const std::optional<lldb_private::FileSpec> GetOutputFile() const; + + void Clear(); + +private: + std::optional<std::string> m_plugin_name; + std::optional<lldb_private::FileSpec> m_file; + std::optional<lldb::SaveCoreStyle> m_style; +}; +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_SaveCoreOPTIONS_H diff --git a/lldb/include/lldb/lldb-private-interfaces.h b/lldb/include/lldb/lldb-private-interfaces.h index cdd9b51..10eaf1e 100644 --- a/lldb/include/lldb/lldb-private-interfaces.h +++ b/lldb/include/lldb/lldb-private-interfaces.h @@ -9,6 +9,7 @@ #ifndef LLDB_LLDB_PRIVATE_INTERFACES_H #define LLDB_LLDB_PRIVATE_INTERFACES_H +#include "lldb/Symbol/SaveCoreOptions.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-private-enumerations.h" @@ -55,8 +56,7 @@ typedef ObjectFile *(*ObjectFileCreateMemoryInstance)( const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, const lldb::ProcessSP &process_sp, lldb::addr_t offset); typedef bool (*ObjectFileSaveCore)(const lldb::ProcessSP &process_sp, - const FileSpec &outfile, - lldb::SaveCoreStyle &core_style, + const lldb_private::SaveCoreOptions &options, Status &error); typedef EmulateInstruction *(*EmulateInstructionCreateInstance)( const ArchSpec &arch, InstructionType inst_type); diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index 6397101..a32bc58 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -56,6 +56,7 @@ add_lldb_library(liblldb SHARED ${option_framework} SBCommandReturnObject.cpp SBCommunication.cpp SBCompileUnit.cpp + SBSaveCoreOptions.cpp SBData.cpp SBDebugger.cpp SBDeclaration.cpp diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp index efb3c8d..b88f897 100644 --- a/lldb/source/API/SBProcess.cpp +++ b/lldb/source/API/SBProcess.cpp @@ -40,6 +40,7 @@ #include "lldb/API/SBFileSpec.h" #include "lldb/API/SBMemoryRegionInfo.h" #include "lldb/API/SBMemoryRegionInfoList.h" +#include "lldb/API/SBSaveCoreOptions.h" #include "lldb/API/SBScriptObject.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBStringList.h" @@ -1216,13 +1217,28 @@ bool SBProcess::IsInstrumentationRuntimePresent( lldb::SBError SBProcess::SaveCore(const char *file_name) { LLDB_INSTRUMENT_VA(this, file_name); - return SaveCore(file_name, "", SaveCoreStyle::eSaveCoreFull); + SBSaveCoreOptions options; + options.SetOutputFile(SBFileSpec(file_name)); + options.SetStyle(SaveCoreStyle::eSaveCoreFull); + return SaveCore(options); } lldb::SBError SBProcess::SaveCore(const char *file_name, const char *flavor, SaveCoreStyle core_style) { LLDB_INSTRUMENT_VA(this, file_name, flavor, core_style); + SBSaveCoreOptions options; + options.SetOutputFile(SBFileSpec(file_name)); + options.SetStyle(core_style); + SBError error = options.SetPluginName(flavor); + if (error.Fail()) + return error; + return SaveCore(options); +} + +lldb::SBError SBProcess::SaveCore(SBSaveCoreOptions &options) { + + LLDB_INSTRUMENT_VA(this, options); lldb::SBError error; ProcessSP process_sp(GetSP()); @@ -1239,10 +1255,7 @@ lldb::SBError SBProcess::SaveCore(const char *file_name, return error; } - FileSpec core_file(file_name); - FileSystem::Instance().Resolve(core_file); - error.ref() = PluginManager::SaveCore(process_sp, core_file, core_style, - flavor); + error.ref() = PluginManager::SaveCore(process_sp, options.ref()); return error; } diff --git a/lldb/source/API/SBSaveCoreOptions.cpp b/lldb/source/API/SBSaveCoreOptions.cpp new file mode 100644 index 0000000..6c3f745 --- /dev/null +++ b/lldb/source/API/SBSaveCoreOptions.cpp @@ -0,0 +1,85 @@ +//===-- SBSaveCoreOptions.cpp -----------------------------------*- 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 "lldb/API/SBSaveCoreOptions.h" +#include "lldb/API/SBError.h" +#include "lldb/API/SBFileSpec.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/SaveCoreOptions.h" +#include "lldb/Utility/Instrumentation.h" + +#include "Utils.h" + +using namespace lldb; + +SBSaveCoreOptions::SBSaveCoreOptions() { + LLDB_INSTRUMENT_VA(this) + + m_opaque_up = std::make_unique<lldb_private::SaveCoreOptions>(); +} + +SBSaveCoreOptions::SBSaveCoreOptions(const SBSaveCoreOptions &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + m_opaque_up = clone(rhs.m_opaque_up); +} + +const SBSaveCoreOptions & +SBSaveCoreOptions::operator=(const SBSaveCoreOptions &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + if (this != &rhs) + m_opaque_up = clone(rhs.m_opaque_up); + return *this; +} + +SBError SBSaveCoreOptions::SetPluginName(const char *name) { + LLDB_INSTRUMENT_VA(this, name); + lldb_private::Status error = m_opaque_up->SetPluginName(name); + return SBError(error); +} + +void SBSaveCoreOptions::SetStyle(lldb::SaveCoreStyle style) { + LLDB_INSTRUMENT_VA(this, style); + m_opaque_up->SetStyle(style); +} + +void SBSaveCoreOptions::SetOutputFile(lldb::SBFileSpec file_spec) { + LLDB_INSTRUMENT_VA(this, file_spec); + m_opaque_up->SetOutputFile(file_spec.ref()); +} + +const char *SBSaveCoreOptions::GetPluginName() const { + LLDB_INSTRUMENT_VA(this); + const auto name = m_opaque_up->GetPluginName(); + if (!name) + return nullptr; + return lldb_private::ConstString(name.value()).GetCString(); +} + +SBFileSpec SBSaveCoreOptions::GetOutputFile() const { + LLDB_INSTRUMENT_VA(this); + const auto file_spec = m_opaque_up->GetOutputFile(); + if (file_spec) + return SBFileSpec(file_spec.value()); + return SBFileSpec(); +} + +lldb::SaveCoreStyle SBSaveCoreOptions::GetStyle() const { + LLDB_INSTRUMENT_VA(this); + return m_opaque_up->GetStyle(); +} + +void SBSaveCoreOptions::Clear() { + LLDB_INSTRUMENT_VA(this); + m_opaque_up->Clear(); +} + +lldb_private::SaveCoreOptions &SBSaveCoreOptions::ref() const { + return *m_opaque_up.get(); +} diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp index 8685d5761..50695af 100644 --- a/lldb/source/Commands/CommandObjectProcess.cpp +++ b/lldb/source/Commands/CommandObjectProcess.cpp @@ -1273,13 +1273,13 @@ public: switch (short_option) { case 'p': - m_requested_plugin_name = option_arg.str(); + error = m_core_dump_options.SetPluginName(option_arg.data()); break; case 's': - m_requested_save_core_style = + m_core_dump_options.SetStyle( (lldb::SaveCoreStyle)OptionArgParser::ToOptionEnum( option_arg, GetDefinitions()[option_idx].enum_values, - eSaveCoreUnspecified, error); + eSaveCoreUnspecified, error)); break; default: llvm_unreachable("Unimplemented option"); @@ -1289,13 +1289,11 @@ public: } void OptionParsingStarting(ExecutionContext *execution_context) override { - m_requested_save_core_style = eSaveCoreUnspecified; - m_requested_plugin_name.clear(); + m_core_dump_options.Clear(); } // Instance variables to hold the values for command options. - SaveCoreStyle m_requested_save_core_style = eSaveCoreUnspecified; - std::string m_requested_plugin_name; + SaveCoreOptions m_core_dump_options; }; protected: @@ -1305,13 +1303,14 @@ protected: if (command.GetArgumentCount() == 1) { FileSpec output_file(command.GetArgumentAtIndex(0)); FileSystem::Instance().Resolve(output_file); - SaveCoreStyle corefile_style = m_options.m_requested_save_core_style; - Status error = - PluginManager::SaveCore(process_sp, output_file, corefile_style, - m_options.m_requested_plugin_name); + auto &core_dump_options = m_options.m_core_dump_options; + core_dump_options.SetOutputFile(output_file); + Status error = PluginManager::SaveCore(process_sp, core_dump_options); if (error.Success()) { - if (corefile_style == SaveCoreStyle::eSaveCoreDirtyOnly || - corefile_style == SaveCoreStyle::eSaveCoreStackOnly) { + if (core_dump_options.GetStyle() == + SaveCoreStyle::eSaveCoreDirtyOnly || + core_dump_options.GetStyle() == + SaveCoreStyle::eSaveCoreStackOnly) { result.AppendMessageWithFormat( "\nModified-memory or stack-memory only corefile " "created. This corefile may \n" diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp index b428370..759ef3a 100644 --- a/lldb/source/Core/PluginManager.cpp +++ b/lldb/source/Core/PluginManager.cpp @@ -12,6 +12,7 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" #include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Symbol/SaveCoreOptions.h" #include "lldb/Target/Process.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Status.h" @@ -639,6 +640,18 @@ static ObjectFileInstances &GetObjectFileInstances() { return g_instances; } +bool PluginManager::IsRegisteredObjectFilePluginName(llvm::StringRef name) { + if (name.empty()) + return false; + + const auto &instances = GetObjectFileInstances().GetInstances(); + for (auto &instance : instances) { + if (instance.name == name) + return true; + } + return false; +} + bool PluginManager::RegisterPlugin( llvm::StringRef name, llvm::StringRef description, ObjectFileCreateInstance create_callback, @@ -689,12 +702,22 @@ PluginManager::GetObjectFileCreateMemoryCallbackForPluginName( } Status PluginManager::SaveCore(const lldb::ProcessSP &process_sp, - const FileSpec &outfile, - lldb::SaveCoreStyle &core_style, - llvm::StringRef plugin_name) { - if (plugin_name.empty()) { + const lldb_private::SaveCoreOptions &options) { + Status error; + if (!options.GetOutputFile()) { + error.SetErrorString("No output file specified"); + return error; + } + + if (!process_sp) { + error.SetErrorString("Invalid process"); + return error; + } + + if (!options.GetPluginName().has_value()) { // Try saving core directly from the process plugin first. - llvm::Expected<bool> ret = process_sp->SaveCore(outfile.GetPath()); + llvm::Expected<bool> ret = + process_sp->SaveCore(options.GetOutputFile()->GetPath()); if (!ret) return Status(ret.takeError()); if (ret.get()) @@ -702,17 +725,20 @@ Status PluginManager::SaveCore(const lldb::ProcessSP &process_sp, } // Fall back to object plugins. - Status error; + const auto &plugin_name = options.GetPluginName().value_or(""); auto &instances = GetObjectFileInstances().GetInstances(); for (auto &instance : instances) { if (plugin_name.empty() || instance.name == plugin_name) { - if (instance.save_core && - instance.save_core(process_sp, outfile, core_style, error)) + if (instance.save_core && instance.save_core(process_sp, options, error)) return error; } } - error.SetErrorString( - "no ObjectFile plugins were able to save a core for this process"); + + // Check to see if any of the object file plugins tried and failed to save. + // If none ran, set the error message. + if (error.Success()) + error.SetErrorString( + "no ObjectFile plugins were able to save a core for this process"); return error; } diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index 0dcb1be..2c70054 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -6519,14 +6519,15 @@ struct page_object { }; bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, - const FileSpec &outfile, - lldb::SaveCoreStyle &core_style, Status &error) { - if (!process_sp) - return false; - - // Default on macOS is to create a dirty-memory-only corefile. + const lldb_private::SaveCoreOptions &options, + Status &error) { + auto core_style = options.GetStyle(); if (core_style == SaveCoreStyle::eSaveCoreUnspecified) core_style = SaveCoreStyle::eSaveCoreDirtyOnly; + // The FileSpec and Process are already checked in PluginManager::SaveCore. + assert(options.GetOutputFile().has_value()); + assert(process_sp); + const FileSpec outfile = options.GetOutputFile().value(); Target &target = process_sp->GetTarget(); const ArchSpec target_arch = target.GetArchitecture(); diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h index 55bc688..e7af90e 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h @@ -62,8 +62,7 @@ public: lldb_private::ModuleSpecList &specs); static bool SaveCore(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb::SaveCoreStyle &core_style, + const lldb_private::SaveCoreOptions &options, lldb_private::Status &error); static bool MagicBytesMatch(lldb::DataBufferSP data_sp, lldb::addr_t offset, diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp index 7c875aa..faa144b 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp @@ -56,18 +56,20 @@ size_t ObjectFileMinidump::GetModuleSpecifications( } bool ObjectFileMinidump::SaveCore(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb::SaveCoreStyle &core_style, + const lldb_private::SaveCoreOptions &options, lldb_private::Status &error) { - // Set default core style if it isn't set. + // Output file and process_sp are both checked in PluginManager::SaveCore. + assert(options.GetOutputFile().has_value()); + assert(process_sp); + + // Minidump defaults to stacks only. + SaveCoreStyle core_style = options.GetStyle(); if (core_style == SaveCoreStyle::eSaveCoreUnspecified) core_style = SaveCoreStyle::eSaveCoreStackOnly; - if (!process_sp) - return false; - llvm::Expected<lldb::FileUP> maybe_core_file = FileSystem::Instance().Open( - outfile, File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate); + options.GetOutputFile().value(), + File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate); if (!maybe_core_file) { error = maybe_core_file.takeError(); return false; diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h index b5c4044..0cd31a0 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h +++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h @@ -55,8 +55,7 @@ public: // Saves dump in Minidump file format static bool SaveCore(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb::SaveCoreStyle &core_style, + const lldb_private::SaveCoreOptions &options, lldb_private::Status &error); private: diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index be0020c..bda691a 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -355,11 +355,12 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( } bool ObjectFilePECOFF::SaveCore(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb::SaveCoreStyle &core_style, + const lldb_private::SaveCoreOptions &options, lldb_private::Status &error) { - core_style = eSaveCoreFull; - return SaveMiniDump(process_sp, outfile, error); + // Outfile and process_sp are validated by PluginManager::SaveCore + assert(options.GetOutputFile().has_value()); + assert(process_sp); + return SaveMiniDump(process_sp, options, error); } bool ObjectFilePECOFF::MagicBytesMatch(DataBufferSP data_sp) { diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h index c59701f..2eb2b3b 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h @@ -82,8 +82,7 @@ public: lldb_private::ModuleSpecList &specs); static bool SaveCore(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb::SaveCoreStyle &core_style, + const lldb_private::SaveCoreOptions &options, lldb_private::Status &error); static bool MagicBytesMatch(lldb::DataBufferSP data_sp); diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp index e5cb369..61cd74d 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp @@ -21,11 +21,12 @@ namespace lldb_private { bool SaveMiniDump(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, + const SaveCoreOptions &core_options, lldb_private::Status &error) { if (!process_sp) return false; #ifdef _WIN32 + const auto &outfile = core_options.GetOutputFile().value(); HANDLE process_handle = ::OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process_sp->GetID()); const std::string file_name = outfile.GetPath(); diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h b/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h index 04b93e22..03c0ece 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h +++ b/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h @@ -14,7 +14,7 @@ namespace lldb_private { bool SaveMiniDump(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, + const SaveCoreOptions &core_options, lldb_private::Status &error); } // namespace lldb_private diff --git a/lldb/source/Symbol/CMakeLists.txt b/lldb/source/Symbol/CMakeLists.txt index ad3488d..e49477d 100644 --- a/lldb/source/Symbol/CMakeLists.txt +++ b/lldb/source/Symbol/CMakeLists.txt @@ -6,6 +6,7 @@ add_lldb_library(lldbSymbol NO_PLUGIN_DEPENDENCIES CompilerDecl.cpp CompilerDeclContext.cpp CompilerType.cpp + SaveCoreOptions.cpp DWARFCallFrameInfo.cpp DebugMacros.cpp DeclVendor.cpp diff --git a/lldb/source/Symbol/SaveCoreOptions.cpp b/lldb/source/Symbol/SaveCoreOptions.cpp new file mode 100644 index 0000000..0f6fdac --- /dev/null +++ b/lldb/source/Symbol/SaveCoreOptions.cpp @@ -0,0 +1,53 @@ +//===-- SaveCoreOptions.cpp -------------------------------------*- 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 "lldb/Symbol/SaveCoreOptions.h" +#include "lldb/Core/PluginManager.h" + +using namespace lldb; +using namespace lldb_private; + +Status SaveCoreOptions::SetPluginName(const char *name) { + Status error; + if (!name || !name[0]) { + m_plugin_name = std::nullopt; + return error; + } + + if (!PluginManager::IsRegisteredObjectFilePluginName(name)) { + error.SetErrorStringWithFormat( + "plugin name '%s' is not a valid ObjectFile plugin name", name); + return error; + } + + m_plugin_name = name; + return error; +} + +void SaveCoreOptions::SetStyle(lldb::SaveCoreStyle style) { m_style = style; } + +void SaveCoreOptions::SetOutputFile(FileSpec file) { m_file = file; } + +std::optional<std::string> SaveCoreOptions::GetPluginName() const { + return m_plugin_name; +} + +lldb::SaveCoreStyle SaveCoreOptions::GetStyle() const { + return m_style.value_or(lldb::eSaveCoreUnspecified); +} + +const std::optional<lldb_private::FileSpec> +SaveCoreOptions::GetOutputFile() const { + return m_file; +} + +void SaveCoreOptions::Clear() { + m_file = std::nullopt; + m_plugin_name = std::nullopt; + m_style = std::nullopt; +} diff --git a/lldb/test/API/functionalities/process_save_core/TestProcessSaveCore.py b/lldb/test/API/functionalities/process_save_core/TestProcessSaveCore.py index c3f0e75..07d06bd 100644 --- a/lldb/test/API/functionalities/process_save_core/TestProcessSaveCore.py +++ b/lldb/test/API/functionalities/process_save_core/TestProcessSaveCore.py @@ -2,7 +2,6 @@ Test saving a core file (or mini dump). """ - import os import lldb from lldbsuite.test.decorators import * @@ -21,6 +20,8 @@ class ProcessSaveCoreTestCase(TestBase): target = self.dbg.CreateTarget(exe) process = target.LaunchSimple(None, None, self.get_process_working_directory()) self.assertNotEqual(process.GetState(), lldb.eStateStopped) + options = SBSaveCoreOptions() + options.SetOutputFile(SBFileSpec(core)) error = process.SaveCore(core) self.assertTrue(error.Fail()) diff --git a/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py b/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py index 1e171e7..96511d7 100644 --- a/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py +++ b/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py @@ -132,8 +132,13 @@ class ProcessSaveCoreMinidumpTestCase(TestBase): stacks_to_sp_map, ) + options = lldb.SBSaveCoreOptions() + core_sb_stack_spec = lldb.SBFileSpec(core_sb_stack) + options.SetOutputFile(core_sb_stack_spec) + options.SetPluginName("minidump") + options.SetStyle(lldb.eSaveCoreStackOnly) # validate saving via SBProcess - error = process.SaveCore(core_sb_stack, "minidump", lldb.eSaveCoreStackOnly) + error = process.SaveCore(options) self.assertTrue(error.Success()) self.assertTrue(os.path.isfile(core_sb_stack)) self.verify_core_file( @@ -144,7 +149,12 @@ class ProcessSaveCoreMinidumpTestCase(TestBase): stacks_to_sp_map, ) - error = process.SaveCore(core_sb_dirty, "minidump", lldb.eSaveCoreDirtyOnly) + options = lldb.SBSaveCoreOptions() + core_sb_dirty_spec = lldb.SBFileSpec(core_sb_dirty) + options.SetOutputFile(core_sb_dirty_spec) + options.SetPluginName("minidump") + options.SetStyle(lldb.eSaveCoreDirtyOnly) + error = process.SaveCore(options) self.assertTrue(error.Success()) self.assertTrue(os.path.isfile(core_sb_dirty)) self.verify_core_file( @@ -157,7 +167,12 @@ class ProcessSaveCoreMinidumpTestCase(TestBase): # Minidump can now save full core files, but they will be huge and # they might cause this test to timeout. - error = process.SaveCore(core_sb_full, "minidump", lldb.eSaveCoreFull) + options = lldb.SBSaveCoreOptions() + core_sb_full_spec = lldb.SBFileSpec(core_sb_full) + options.SetOutputFile(core_sb_full_spec) + options.SetPluginName("minidump") + options.SetStyle(lldb.eSaveCoreFull) + error = process.SaveCore(options) self.assertTrue(error.Success()) self.assertTrue(os.path.isfile(core_sb_full)) self.verify_core_file( diff --git a/lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py b/lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py new file mode 100644 index 0000000..c509e81 --- /dev/null +++ b/lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py @@ -0,0 +1,28 @@ +"""Test the SBSaveCoreOptions APIs.""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * + + +class SBSaveCoreOptionsAPICase(TestBase): + def test_plugin_name_assignment(self): + """Test assignment ensuring valid plugin names only.""" + options = lldb.SBSaveCoreOptions() + error = options.SetPluginName(None) + self.assertTrue(error.Success()) + self.assertEqual(options.GetPluginName(), None) + error = options.SetPluginName("Not a real plugin") + self.assertTrue(error.Fail()) + self.assertEqual(options.GetPluginName(), None) + error = options.SetPluginName("minidump") + self.assertTrue(error.Success()) + self.assertEqual(options.GetPluginName(), "minidump") + error = options.SetPluginName("") + self.assertTrue(error.Success()) + self.assertEqual(options.GetPluginName(), None) + + def test_default_corestyle_behavior(self): + """Test that the default core style is unspecified.""" + options = lldb.SBSaveCoreOptions() + self.assertEqual(options.GetStyle(), lldb.eSaveCoreUnspecified) diff --git a/llvm/docs/CompileCudaWithLLVM.rst b/llvm/docs/CompileCudaWithLLVM.rst index 0371d7a..1b1a272 100644 --- a/llvm/docs/CompileCudaWithLLVM.rst +++ b/llvm/docs/CompileCudaWithLLVM.rst @@ -514,7 +514,7 @@ Modern CPUs and GPUs are architecturally quite different, so code that's fast on a CPU isn't necessarily fast on a GPU. We've made a number of changes to LLVM to make it generate good GPU code. Among these changes are: -* `Straight-line scalar optimizations <https://goo.gl/4Rb9As>`_ -- These +* `Straight-line scalar optimizations <https://docs.google.com/document/d/1momWzKFf4D6h8H3YlfgKQ3qeZy5ayvMRh6yR-Xn2hUE>`_ -- These reduce redundancy within straight-line code. * `Aggressive speculative execution diff --git a/llvm/include/llvm/CodeGen/TargetCallingConv.h b/llvm/include/llvm/CodeGen/TargetCallingConv.h index 0ff4e1f..cb00556 100644 --- a/llvm/include/llvm/CodeGen/TargetCallingConv.h +++ b/llvm/include/llvm/CodeGen/TargetCallingConv.h @@ -45,9 +45,9 @@ namespace ISD { unsigned IsHva : 1; ///< HVA field for unsigned IsHvaStart : 1; ///< HVA structure start unsigned IsSecArgPass : 1; ///< Second argument - unsigned MemAlign : 4; ///< Log 2 of alignment when arg is passed in memory - ///< (including byval/byref). The max alignment is - ///< verified in IR verification. + unsigned MemAlign : 6; ///< Log 2 of alignment when arg is passed in memory + ///< (including byval/byref). The max alignment is + ///< verified in IR verification. unsigned OrigAlign : 5; ///< Log 2 of original alignment unsigned IsInConsecutiveRegsLast : 1; unsigned IsInConsecutiveRegs : 1; @@ -67,7 +67,7 @@ namespace ISD { IsSecArgPass(0), MemAlign(0), OrigAlign(0), IsInConsecutiveRegsLast(0), IsInConsecutiveRegs(0), IsCopyElisionCandidate(0), IsPointer(0) { - static_assert(sizeof(*this) == 3 * sizeof(unsigned), "flags are too big"); + static_assert(sizeof(*this) == 4 * sizeof(unsigned), "flags are too big"); } bool isZExt() const { return IsZExt; } diff --git a/llvm/include/llvm/Object/ArchiveWriter.h b/llvm/include/llvm/Object/ArchiveWriter.h index e41b3d5..95b81f5 100644 --- a/llvm/include/llvm/Object/ArchiveWriter.h +++ b/llvm/include/llvm/Object/ArchiveWriter.h @@ -48,25 +48,30 @@ enum class SymtabWritingMode { BigArchive64 // Only write the 64-bit symbol table. }; +void warnToStderr(Error Err); + // Write an archive directly to an output stream. Error writeArchiveToStream(raw_ostream &Out, ArrayRef<NewArchiveMember> NewMembers, SymtabWritingMode WriteSymtab, object::Archive::Kind Kind, bool Deterministic, - bool Thin, std::optional<bool> IsEC = std::nullopt); + bool Thin, std::optional<bool> IsEC = std::nullopt, + function_ref<void(Error)> Warn = warnToStderr); Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers, SymtabWritingMode WriteSymtab, object::Archive::Kind Kind, bool Deterministic, bool Thin, std::unique_ptr<MemoryBuffer> OldArchiveBuf = nullptr, - std::optional<bool> IsEC = std::nullopt); + std::optional<bool> IsEC = std::nullopt, + function_ref<void(Error)> Warn = warnToStderr); // writeArchiveToBuffer is similar to writeArchive but returns the Archive in a // buffer instead of writing it out to a file. Expected<std::unique_ptr<MemoryBuffer>> writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers, SymtabWritingMode WriteSymtab, object::Archive::Kind Kind, - bool Deterministic, bool Thin); + bool Deterministic, bool Thin, + function_ref<void(Error)> Warn = warnToStderr); } #endif diff --git a/llvm/include/llvm/SandboxIR/Tracker.h b/llvm/include/llvm/SandboxIR/Tracker.h index a91b9f1..b88eb3d 100644 --- a/llvm/include/llvm/SandboxIR/Tracker.h +++ b/llvm/include/llvm/SandboxIR/Tracker.h @@ -53,6 +53,7 @@ namespace llvm::sandboxir { class BasicBlock; +class Instruction; class Tracker; /// The base class for IR Change classes. @@ -135,6 +136,46 @@ public: #endif }; +class RemoveFromParent : public IRChangeBase { + /// The instruction that is about to get removed. + Instruction *RemovedI = nullptr; + /// This is either the next instr, or the parent BB if at the end of the BB. + PointerUnion<Instruction *, BasicBlock *> NextInstrOrBB; + +public: + RemoveFromParent(Instruction *RemovedI, Tracker &Tracker); + void revert() final; + void accept() final {}; + Instruction *getInstruction() const { return RemovedI; } +#ifndef NDEBUG + void dump(raw_ostream &OS) const final { + dumpCommon(OS); + OS << "RemoveFromParent"; + } + LLVM_DUMP_METHOD void dump() const final; +#endif // NDEBUG +}; + +class MoveInstr : public IRChangeBase { + /// The instruction that moved. + Instruction *MovedI; + /// This is either the next instruction in the block, or the parent BB if at + /// the end of the BB. + PointerUnion<Instruction *, BasicBlock *> NextInstrOrBB; + +public: + MoveInstr(sandboxir::Instruction *I, Tracker &Tracker); + void revert() final; + void accept() final {} +#ifndef NDEBUG + void dump(raw_ostream &OS) const final { + dumpCommon(OS); + OS << "MoveInstr"; + } + LLVM_DUMP_METHOD void dump() const final; +#endif // NDEBUG +}; + /// The tracker collects all the change objects and implements the main API for /// saving / reverting / accepting. class Tracker { diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp index 91994f3..84214c4 100644 --- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp +++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp @@ -1730,7 +1730,7 @@ bool MemoryDepChecker::Dependence::isBackward() const { } bool MemoryDepChecker::Dependence::isPossiblyBackward() const { - return isBackward() || Type == Unknown; + return isBackward() || Type == Unknown || Type == IndirectUnsafe; } bool MemoryDepChecker::Dependence::isForward() const { diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 75a53c1..c5c4076 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -324,13 +324,6 @@ namespace { class Verifier : public InstVisitor<Verifier>, VerifierSupport { friend class InstVisitor<Verifier>; - - // ISD::ArgFlagsTy::MemAlign only have 4 bits for alignment, so - // the alignment size should not exceed 2^15. Since encode(Align) - // would plus the shift value by 1, the alignment size should - // not exceed 2^14, otherwise it can NOT be properly lowered - // in backend. - static constexpr unsigned ParamMaxAlignment = 1 << 14; DominatorTree DT; /// When verifying a basic block, keep track of all of the @@ -2021,31 +2014,43 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty, } if (isa<PointerType>(Ty)) { + if (Attrs.hasAttribute(Attribute::Alignment)) { + Align AttrAlign = Attrs.getAlignment().valueOrOne(); + Check(AttrAlign.value() <= Value::MaximumAlignment, + "huge alignment values are unsupported", V); + } if (Attrs.hasAttribute(Attribute::ByVal)) { - if (Attrs.hasAttribute(Attribute::Alignment)) { - Align AttrAlign = Attrs.getAlignment().valueOrOne(); - Align MaxAlign(ParamMaxAlignment); - Check(AttrAlign <= MaxAlign, - "Attribute 'align' exceed the max size 2^14", V); - } SmallPtrSet<Type *, 4> Visited; Check(Attrs.getByValType()->isSized(&Visited), "Attribute 'byval' does not support unsized types!", V); + Check(DL.getTypeAllocSize(Attrs.getByValType()).getKnownMinValue() < + (1ULL << 32), + "huge 'byval' arguments are unsupported", V); } if (Attrs.hasAttribute(Attribute::ByRef)) { SmallPtrSet<Type *, 4> Visited; Check(Attrs.getByRefType()->isSized(&Visited), "Attribute 'byref' does not support unsized types!", V); + Check(DL.getTypeAllocSize(Attrs.getByRefType()).getKnownMinValue() < + (1ULL << 32), + "huge 'byref' arguments are unsupported", V); } if (Attrs.hasAttribute(Attribute::InAlloca)) { SmallPtrSet<Type *, 4> Visited; Check(Attrs.getInAllocaType()->isSized(&Visited), "Attribute 'inalloca' does not support unsized types!", V); + Check(DL.getTypeAllocSize(Attrs.getInAllocaType()).getKnownMinValue() < + (1ULL << 32), + "huge 'inalloca' arguments are unsupported", V); } if (Attrs.hasAttribute(Attribute::Preallocated)) { SmallPtrSet<Type *, 4> Visited; Check(Attrs.getPreallocatedType()->isSized(&Visited), "Attribute 'preallocated' does not support unsized types!", V); + Check( + DL.getTypeAllocSize(Attrs.getPreallocatedType()).getKnownMinValue() < + (1ULL << 32), + "huge 'preallocated' arguments are unsupported", V); } } @@ -3511,12 +3516,15 @@ void Verifier::visitCallBase(CallBase &Call) { "not allowed. Please use the @llvm.amdgpu.cs.chain intrinsic instead.", Call); + // Disallow passing/returning values with alignment higher than we can + // represent. + // FIXME: Consider making DataLayout cap the alignment, so this isn't + // necessary. auto VerifyTypeAlign = [&](Type *Ty, const Twine &Message) { if (!Ty->isSized()) return; Align ABIAlign = DL.getABITypeAlign(Ty); - Align MaxAlign(ParamMaxAlignment); - Check(ABIAlign <= MaxAlign, + Check(ABIAlign.value() <= Value::MaximumAlignment, "Incorrect alignment of " + Message + " to called function!", Call); }; diff --git a/llvm/lib/Object/ArchiveWriter.cpp b/llvm/lib/Object/ArchiveWriter.cpp index 34f12cf..1140455 100644 --- a/llvm/lib/Object/ArchiveWriter.cpp +++ b/llvm/lib/Object/ArchiveWriter.cpp @@ -482,7 +482,8 @@ static uint64_t computeHeadersSize(object::Archive::Kind Kind, } static Expected<std::unique_ptr<SymbolicFile>> -getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context) { +getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context, + object::Archive::Kind Kind, function_ref<void(Error)> Warn) { const file_magic Type = identify_magic(Buf.getBuffer()); // Don't attempt to read non-symbolic file types. if (!object::SymbolicFile::isSymbolicFile(Type, &Context)) @@ -490,8 +491,36 @@ getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context) { if (Type == file_magic::bitcode) { auto ObjOrErr = object::SymbolicFile::createSymbolicFile( Buf, file_magic::bitcode, &Context); - if (!ObjOrErr) - return ObjOrErr.takeError(); + // An error reading a bitcode file most likely indicates that the file + // was created by a compiler from the future. Normally we don't try to + // implement forwards compatibility for bitcode files, but when creating an + // archive we can implement best-effort forwards compatibility by treating + // the file as a blob and not creating symbol index entries for it. lld and + // mold ignore the archive symbol index, so provided that you use one of + // these linkers, LTO will work as long as lld or the gold plugin is newer + // than the compiler. We only ignore errors if the archive format is one + // that is supported by a linker that is known to ignore the index, + // otherwise there's no chance of this working so we may as well error out. + // We print a warning on read failure so that users of linkers that rely on + // the symbol index can diagnose the issue. + // + // This is the same behavior as GNU ar when the linker plugin returns an + // error when reading the input file. If the bitcode file is actually + // malformed, it will be diagnosed at link time. + if (!ObjOrErr) { + switch (Kind) { + case object::Archive::K_BSD: + case object::Archive::K_GNU: + case object::Archive::K_GNU64: + Warn(ObjOrErr.takeError()); + return nullptr; + case object::Archive::K_AIXBIG: + case object::Archive::K_COFF: + case object::Archive::K_DARWIN: + case object::Archive::K_DARWIN64: + return ObjOrErr.takeError(); + } + } return std::move(*ObjOrErr); } else { auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf); @@ -751,7 +780,7 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, object::Archive::Kind Kind, bool Thin, bool Deterministic, SymtabWritingMode NeedSymbols, SymMap *SymMap, LLVMContext &Context, ArrayRef<NewArchiveMember> NewMembers, - std::optional<bool> IsEC) { + std::optional<bool> IsEC, function_ref<void(Error)> Warn) { static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'}; uint64_t MemHeadPadSize = 0; uint64_t Pos = @@ -819,8 +848,10 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, if (NeedSymbols != SymtabWritingMode::NoSymtab || isAIXBigArchive(Kind)) { for (const NewArchiveMember &M : NewMembers) { - Expected<std::unique_ptr<SymbolicFile>> SymFileOrErr = - getSymbolicFile(M.Buf->getMemBufferRef(), Context); + Expected<std::unique_ptr<SymbolicFile>> SymFileOrErr = getSymbolicFile( + M.Buf->getMemBufferRef(), Context, Kind, [&](Error Err) { + Warn(createFileError(M.MemberName, std::move(Err))); + }); if (!SymFileOrErr) return createFileError(M.MemberName, SymFileOrErr.takeError()); SymFiles.push_back(std::move(*SymFileOrErr)); @@ -1001,7 +1032,8 @@ Error writeArchiveToStream(raw_ostream &Out, ArrayRef<NewArchiveMember> NewMembers, SymtabWritingMode WriteSymtab, object::Archive::Kind Kind, bool Deterministic, - bool Thin, std::optional<bool> IsEC) { + bool Thin, std::optional<bool> IsEC, + function_ref<void(Error)> Warn) { assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode"); SmallString<0> SymNamesBuf; @@ -1023,7 +1055,7 @@ Error writeArchiveToStream(raw_ostream &Out, Expected<std::vector<MemberData>> DataOrErr = computeMemberData( StringTable, SymNames, Kind, Thin, Deterministic, WriteSymtab, - isCOFFArchive(Kind) ? &SymMap : nullptr, Context, NewMembers, IsEC); + isCOFFArchive(Kind) ? &SymMap : nullptr, Context, NewMembers, IsEC, Warn); if (Error E = DataOrErr.takeError()) return E; std::vector<MemberData> &Data = *DataOrErr; @@ -1266,11 +1298,15 @@ Error writeArchiveToStream(raw_ostream &Out, return Error::success(); } +void warnToStderr(Error Err) { + llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "warning: "); +} + Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers, SymtabWritingMode WriteSymtab, object::Archive::Kind Kind, bool Deterministic, bool Thin, std::unique_ptr<MemoryBuffer> OldArchiveBuf, - std::optional<bool> IsEC) { + std::optional<bool> IsEC, function_ref<void(Error)> Warn) { Expected<sys::fs::TempFile> Temp = sys::fs::TempFile::create(ArcName + ".temp-archive-%%%%%%%.a"); if (!Temp) @@ -1278,7 +1314,7 @@ Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers, raw_fd_ostream Out(Temp->FD, false); if (Error E = writeArchiveToStream(Out, NewMembers, WriteSymtab, Kind, - Deterministic, Thin, IsEC)) { + Deterministic, Thin, IsEC, Warn)) { if (Error DiscardError = Temp->discard()) return joinErrors(std::move(E), std::move(DiscardError)); return E; @@ -1302,12 +1338,14 @@ Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers, Expected<std::unique_ptr<MemoryBuffer>> writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers, SymtabWritingMode WriteSymtab, object::Archive::Kind Kind, - bool Deterministic, bool Thin) { + bool Deterministic, bool Thin, + function_ref<void(Error)> Warn) { SmallVector<char, 0> ArchiveBufferVector; raw_svector_ostream ArchiveStream(ArchiveBufferVector); - if (Error E = writeArchiveToStream(ArchiveStream, NewMembers, WriteSymtab, - Kind, Deterministic, Thin, std::nullopt)) + if (Error E = + writeArchiveToStream(ArchiveStream, NewMembers, WriteSymtab, Kind, + Deterministic, Thin, std::nullopt, Warn)) return std::move(E); return std::make_unique<SmallVectorMemoryBuffer>( diff --git a/llvm/lib/SandboxIR/SandboxIR.cpp b/llvm/lib/SandboxIR/SandboxIR.cpp index c6daf1a..8713499 100644 --- a/llvm/lib/SandboxIR/SandboxIR.cpp +++ b/llvm/lib/SandboxIR/SandboxIR.cpp @@ -333,6 +333,10 @@ Instruction *Instruction::getPrevNode() const { } void Instruction::removeFromParent() { + auto &Tracker = Ctx.getTracker(); + if (Tracker.isTracking()) + Tracker.track(std::make_unique<RemoveFromParent>(this, Tracker)); + // Detach all the LLVM IR instructions from their parent BB. for (llvm::Instruction *I : getLLVMInstrs()) I->removeFromParent(); @@ -367,6 +371,11 @@ void Instruction::moveBefore(BasicBlock &BB, const BBIterator &WhereIt) { if (std::next(getIterator()) == WhereIt) // Destination is same as origin, nothing to do. return; + + auto &Tracker = Ctx.getTracker(); + if (Tracker.isTracking()) + Tracker.track(std::make_unique<MoveInstr>(this, Tracker)); + auto *LLVMBB = cast<llvm::BasicBlock>(BB.Val); llvm::BasicBlock::iterator It; if (WhereIt == BB.end()) { diff --git a/llvm/lib/SandboxIR/Tracker.cpp b/llvm/lib/SandboxIR/Tracker.cpp index 2336a00..626c9c2 100644 --- a/llvm/lib/SandboxIR/Tracker.cpp +++ b/llvm/lib/SandboxIR/Tracker.cpp @@ -98,6 +98,54 @@ void EraseFromParent::dump() const { dump(dbgs()); dbgs() << "\n"; } +#endif // NDEBUG + +RemoveFromParent::RemoveFromParent(Instruction *RemovedI, Tracker &Tracker) + : IRChangeBase(Tracker), RemovedI(RemovedI) { + if (auto *NextI = RemovedI->getNextNode()) + NextInstrOrBB = NextI; + else + NextInstrOrBB = RemovedI->getParent(); +} + +void RemoveFromParent::revert() { + if (auto *NextI = NextInstrOrBB.dyn_cast<Instruction *>()) { + RemovedI->insertBefore(NextI); + } else { + auto *BB = NextInstrOrBB.get<BasicBlock *>(); + RemovedI->insertInto(BB, BB->end()); + } +} + +#ifndef NDEBUG +void RemoveFromParent::dump() const { + dump(dbgs()); + dbgs() << "\n"; +} +#endif + +MoveInstr::MoveInstr(Instruction *MovedI, Tracker &Tracker) + : IRChangeBase(Tracker), MovedI(MovedI) { + if (auto *NextI = MovedI->getNextNode()) + NextInstrOrBB = NextI; + else + NextInstrOrBB = MovedI->getParent(); +} + +void MoveInstr::revert() { + if (auto *NextI = NextInstrOrBB.dyn_cast<Instruction *>()) { + MovedI->moveBefore(NextI); + } else { + auto *BB = NextInstrOrBB.get<BasicBlock *>(); + MovedI->moveBefore(*BB, BB->end()); + } +} + +#ifndef NDEBUG +void MoveInstr::dump() const { + dump(dbgs()); + dbgs() << "\n"; +} #endif void Tracker::track(std::unique_ptr<IRChangeBase> &&Change) { diff --git a/llvm/lib/Target/AMDGPU/FLATInstructions.td b/llvm/lib/Target/AMDGPU/FLATInstructions.td index 56cc6ff..88c6039 100644 --- a/llvm/lib/Target/AMDGPU/FLATInstructions.td +++ b/llvm/lib/Target/AMDGPU/FLATInstructions.td @@ -1589,15 +1589,13 @@ let OtherPredicates = [isGFX12Plus] in { let WaveSizePredicate = isWave32 in { defm : GlobalFLATLoadPats <GLOBAL_LOAD_TR_B64_w32, int_amdgcn_global_load_tr_b64, v2i32>; - defm : GlobalFLATLoadPats <GLOBAL_LOAD_TR_B128_w32, int_amdgcn_global_load_tr_b128, v8i16>; - defm : GlobalFLATLoadPats <GLOBAL_LOAD_TR_B128_w32, int_amdgcn_global_load_tr_b128, v8f16>; - defm : GlobalFLATLoadPats <GLOBAL_LOAD_TR_B128_w32, int_amdgcn_global_load_tr_b128, v8bf16>; + foreach vt = [v8i16, v8f16, v8bf16] in + defm : GlobalFLATLoadPats <GLOBAL_LOAD_TR_B128_w32, int_amdgcn_global_load_tr_b128, vt>; } let WaveSizePredicate = isWave64 in { defm : GlobalFLATLoadPats <GLOBAL_LOAD_TR_B64_w64, int_amdgcn_global_load_tr_b64, i32>; - defm : GlobalFLATLoadPats <GLOBAL_LOAD_TR_B128_w64, int_amdgcn_global_load_tr_b128, v4i16>; - defm : GlobalFLATLoadPats <GLOBAL_LOAD_TR_B128_w64, int_amdgcn_global_load_tr_b128, v4f16>; - defm : GlobalFLATLoadPats <GLOBAL_LOAD_TR_B128_w64, int_amdgcn_global_load_tr_b128, v4bf16>; + foreach vt = [v4i16, v4f16, v4bf16] in + defm : GlobalFLATLoadPats <GLOBAL_LOAD_TR_B128_w64, int_amdgcn_global_load_tr_b128, vt>; } } diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp index c7d41f6..9bda288 100644 --- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -11,11 +11,11 @@ /// reads. /// /// The algorithm of the tool is similar to Memcheck -/// (http://goo.gl/QKbem). We associate a few shadow bits with every -/// byte of the application memory, poison the shadow of the malloc-ed -/// or alloca-ed memory, load the shadow bits on every memory read, -/// propagate the shadow bits through some of the arithmetic -/// instruction (including MOV), store the shadow bits on every memory +/// (https://static.usenix.org/event/usenix05/tech/general/full_papers/seward/seward_html/usenix2005.html) +/// We associate a few shadow bits with every byte of the application memory, +/// poison the shadow of the malloc-ed or alloca-ed memory, load the shadow, +/// bits on every memory read, propagate the shadow bits through some of the +/// arithmetic instruction (including MOV), store the shadow bits on every memory /// write, report a bug on some other instructions (e.g. JMP) if the /// associated shadow is poisoned. /// diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index 748db41..fbca4cd 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -2767,18 +2767,17 @@ InnerLoopVectorizer::getOrCreateVectorTripCount(BasicBlock *InsertBlock) { Value *InnerLoopVectorizer::createBitOrPointerCast(Value *V, VectorType *DstVTy, const DataLayout &DL) { // Verify that V is a vector type with same number of elements as DstVTy. - auto *DstFVTy = cast<VectorType>(DstVTy); - auto VF = DstFVTy->getElementCount(); + auto VF = DstVTy->getElementCount(); auto *SrcVecTy = cast<VectorType>(V->getType()); assert(VF == SrcVecTy->getElementCount() && "Vector dimensions do not match"); Type *SrcElemTy = SrcVecTy->getElementType(); - Type *DstElemTy = DstFVTy->getElementType(); + Type *DstElemTy = DstVTy->getElementType(); assert((DL.getTypeSizeInBits(SrcElemTy) == DL.getTypeSizeInBits(DstElemTy)) && "Vector elements must have same size"); // Do a direct cast if element types are castable. if (CastInst::isBitOrNoopPointerCastable(SrcElemTy, DstElemTy, DL)) { - return Builder.CreateBitOrPointerCast(V, DstFVTy); + return Builder.CreateBitOrPointerCast(V, DstVTy); } // V cannot be directly casted to desired vector type. // May happen when V is a floating point vector but DstVTy is a vector of @@ -2792,7 +2791,7 @@ Value *InnerLoopVectorizer::createBitOrPointerCast(Value *V, VectorType *DstVTy, IntegerType::getIntNTy(V->getContext(), DL.getTypeSizeInBits(SrcElemTy)); auto *VecIntTy = VectorType::get(IntTy, VF); Value *CastVal = Builder.CreateBitOrPointerCast(V, VecIntTy); - return Builder.CreateBitOrPointerCast(CastVal, DstFVTy); + return Builder.CreateBitOrPointerCast(CastVal, DstVTy); } void InnerLoopVectorizer::emitIterationCountCheck(BasicBlock *Bypass) { diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp index 3a49f95..4445985 100644 --- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp +++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp @@ -117,7 +117,7 @@ private: bool foldShuffleOfShuffles(Instruction &I); bool foldShuffleToIdentity(Instruction &I); bool foldShuffleFromReductions(Instruction &I); - bool foldTruncFromReductions(Instruction &I); + bool foldCastFromReductions(Instruction &I); bool foldSelectShuffle(Instruction &I, bool FromReduction = false); void replaceValue(Value &Old, Value &New) { @@ -2113,15 +2113,20 @@ bool VectorCombine::foldShuffleFromReductions(Instruction &I) { /// Determine if its more efficient to fold: /// reduce(trunc(x)) -> trunc(reduce(x)). -bool VectorCombine::foldTruncFromReductions(Instruction &I) { +/// reduce(sext(x)) -> sext(reduce(x)). +/// reduce(zext(x)) -> zext(reduce(x)). +bool VectorCombine::foldCastFromReductions(Instruction &I) { auto *II = dyn_cast<IntrinsicInst>(&I); if (!II) return false; + bool TruncOnly = false; Intrinsic::ID IID = II->getIntrinsicID(); switch (IID) { case Intrinsic::vector_reduce_add: case Intrinsic::vector_reduce_mul: + TruncOnly = true; + break; case Intrinsic::vector_reduce_and: case Intrinsic::vector_reduce_or: case Intrinsic::vector_reduce_xor: @@ -2133,35 +2138,37 @@ bool VectorCombine::foldTruncFromReductions(Instruction &I) { unsigned ReductionOpc = getArithmeticReductionInstruction(IID); Value *ReductionSrc = I.getOperand(0); - Value *TruncSrc; - if (!match(ReductionSrc, m_OneUse(m_Trunc(m_Value(TruncSrc))))) + Value *Src; + if (!match(ReductionSrc, m_OneUse(m_Trunc(m_Value(Src)))) && + (TruncOnly || !match(ReductionSrc, m_OneUse(m_ZExtOrSExt(m_Value(Src)))))) return false; - auto *TruncSrcTy = cast<VectorType>(TruncSrc->getType()); + auto CastOpc = + (Instruction::CastOps)cast<Instruction>(ReductionSrc)->getOpcode(); + + auto *SrcTy = cast<VectorType>(Src->getType()); auto *ReductionSrcTy = cast<VectorType>(ReductionSrc->getType()); Type *ResultTy = I.getType(); TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput; InstructionCost OldCost = TTI.getArithmeticReductionCost( ReductionOpc, ReductionSrcTy, std::nullopt, CostKind); - if (auto *Trunc = dyn_cast<CastInst>(ReductionSrc)) - OldCost += - TTI.getCastInstrCost(Instruction::Trunc, ReductionSrcTy, TruncSrcTy, - TTI::CastContextHint::None, CostKind, Trunc); + OldCost += TTI.getCastInstrCost(CastOpc, ReductionSrcTy, SrcTy, + TTI::CastContextHint::None, CostKind, + cast<CastInst>(ReductionSrc)); InstructionCost NewCost = - TTI.getArithmeticReductionCost(ReductionOpc, TruncSrcTy, std::nullopt, + TTI.getArithmeticReductionCost(ReductionOpc, SrcTy, std::nullopt, CostKind) + - TTI.getCastInstrCost(Instruction::Trunc, ResultTy, - ReductionSrcTy->getScalarType(), + TTI.getCastInstrCost(CastOpc, ResultTy, ReductionSrcTy->getScalarType(), TTI::CastContextHint::None, CostKind); if (OldCost <= NewCost || !NewCost.isValid()) return false; - Value *NewReduction = Builder.CreateIntrinsic( - TruncSrcTy->getScalarType(), II->getIntrinsicID(), {TruncSrc}); - Value *NewTruncation = Builder.CreateTrunc(NewReduction, ResultTy); - replaceValue(I, *NewTruncation); + Value *NewReduction = Builder.CreateIntrinsic(SrcTy->getScalarType(), + II->getIntrinsicID(), {Src}); + Value *NewCast = Builder.CreateCast(CastOpc, NewReduction, ResultTy); + replaceValue(I, *NewCast); return true; } @@ -2559,7 +2566,7 @@ bool VectorCombine::run() { switch (Opcode) { case Instruction::Call: MadeChange |= foldShuffleFromReductions(I); - MadeChange |= foldTruncFromReductions(I); + MadeChange |= foldCastFromReductions(I); break; case Instruction::ICmp: case Instruction::FCmp: diff --git a/llvm/test/Instrumentation/MemorySanitizer/AArch64/neon_vst_origins.ll b/llvm/test/Instrumentation/MemorySanitizer/AArch64/neon_vst_origins.ll new file mode 100644 index 0000000..ff4c4c2 --- /dev/null +++ b/llvm/test/Instrumentation/MemorySanitizer/AArch64/neon_vst_origins.ll @@ -0,0 +1,158 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 +; Test memory sanitizer instrumentation for Arm NEON VST instructions, with +; origin tracking. These tests are deliberately shorter than neon_vst.ll, due +; to the verbosity of the output. +; +; RUN: opt < %s -passes=msan -msan-track-origins=2 -S | FileCheck %s +; +; Forked from llvm/test/CodeGen/AArch64/arm64-st1.ll + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64--linux-android9001" + +; ----------------------------------------------------------------------------------------------------------------------------------------------- + +define void @st2_16b(<16 x i8> %A, <16 x i8> %B, ptr %P) nounwind sanitize_memory { +; +; CHECK-LABEL: define void @st2_16b +; CHECK-SAME: (<16 x i8> [[A:%.*]], <16 x i8> [[B:%.*]], ptr [[P:%.*]]) #[[ATTR0:[0-9]+]] { +; CHECK-NEXT: [[TMP1:%.*]] = load <16 x i8>, ptr @__msan_param_tls, align 8 +; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr @__msan_param_origin_tls, align 4 +; CHECK-NEXT: [[TMP3:%.*]] = load <16 x i8>, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 16) to ptr), align 8 +; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_origin_tls to i64), i64 16) to ptr), align 4 +; CHECK-NEXT: [[TMP5:%.*]] = load i64, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 32) to ptr), align 8 +; CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_origin_tls to i64), i64 32) to ptr), align 4 +; CHECK-NEXT: call void @llvm.donothing() +; CHECK-NEXT: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP1]] to i128 +; CHECK-NEXT: [[_MSCMP:%.*]] = icmp ne i128 [[TMP7]], 0 +; CHECK-NEXT: br i1 [[_MSCMP]], label [[TMP8:%.*]], label [[TMP9:%.*]], !prof [[PROF0:![0-9]+]] +; CHECK: 8: +; CHECK-NEXT: call void @__msan_warning_with_origin_noreturn(i32 [[TMP2]]) #[[ATTR4:[0-9]+]] +; CHECK-NEXT: unreachable +; CHECK: 9: +; CHECK-NEXT: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP3]] to i128 +; CHECK-NEXT: [[_MSCMP1:%.*]] = icmp ne i128 [[TMP10]], 0 +; CHECK-NEXT: br i1 [[_MSCMP1]], label [[TMP11:%.*]], label [[TMP12:%.*]], !prof [[PROF0]] +; CHECK: 11: +; CHECK-NEXT: call void @__msan_warning_with_origin_noreturn(i32 [[TMP4]]) #[[ATTR4]] +; CHECK-NEXT: unreachable +; CHECK: 12: +; CHECK-NEXT: [[_MSCMP2:%.*]] = icmp ne i64 [[TMP5]], 0 +; CHECK-NEXT: br i1 [[_MSCMP2]], label [[TMP13:%.*]], label [[TMP14:%.*]], !prof [[PROF0]] +; CHECK: 13: +; CHECK-NEXT: call void @__msan_warning_with_origin_noreturn(i32 [[TMP6]]) #[[ATTR4]] +; CHECK-NEXT: unreachable +; CHECK: 14: +; CHECK-NEXT: call void @llvm.aarch64.neon.st2.v16i8.p0(<16 x i8> [[A]], <16 x i8> [[B]], ptr [[P]]) +; CHECK-NEXT: ret void +; + call void @llvm.aarch64.neon.st2.v16i8.p0(<16 x i8> %A, <16 x i8> %B, ptr %P) + ret void +} + +define void @st3_16b(<16 x i8> %A, <16 x i8> %B, <16 x i8> %C, ptr %P) nounwind sanitize_memory { +; +; CHECK-LABEL: define void @st3_16b +; CHECK-SAME: (<16 x i8> [[A:%.*]], <16 x i8> [[B:%.*]], <16 x i8> [[C:%.*]], ptr [[P:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[TMP1:%.*]] = load <16 x i8>, ptr @__msan_param_tls, align 8 +; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr @__msan_param_origin_tls, align 4 +; CHECK-NEXT: [[TMP3:%.*]] = load <16 x i8>, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 16) to ptr), align 8 +; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_origin_tls to i64), i64 16) to ptr), align 4 +; CHECK-NEXT: [[TMP5:%.*]] = load <16 x i8>, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 32) to ptr), align 8 +; CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_origin_tls to i64), i64 32) to ptr), align 4 +; CHECK-NEXT: [[TMP7:%.*]] = load i64, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 48) to ptr), align 8 +; CHECK-NEXT: [[TMP8:%.*]] = load i32, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_origin_tls to i64), i64 48) to ptr), align 4 +; CHECK-NEXT: call void @llvm.donothing() +; CHECK-NEXT: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP1]] to i128 +; CHECK-NEXT: [[_MSCMP:%.*]] = icmp ne i128 [[TMP9]], 0 +; CHECK-NEXT: br i1 [[_MSCMP]], label [[TMP10:%.*]], label [[TMP11:%.*]], !prof [[PROF0]] +; CHECK: 10: +; CHECK-NEXT: call void @__msan_warning_with_origin_noreturn(i32 [[TMP2]]) #[[ATTR4]] +; CHECK-NEXT: unreachable +; CHECK: 11: +; CHECK-NEXT: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP3]] to i128 +; CHECK-NEXT: [[_MSCMP1:%.*]] = icmp ne i128 [[TMP12]], 0 +; CHECK-NEXT: br i1 [[_MSCMP1]], label [[TMP13:%.*]], label [[TMP14:%.*]], !prof [[PROF0]] +; CHECK: 13: +; CHECK-NEXT: call void @__msan_warning_with_origin_noreturn(i32 [[TMP4]]) #[[ATTR4]] +; CHECK-NEXT: unreachable +; CHECK: 14: +; CHECK-NEXT: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP5]] to i128 +; CHECK-NEXT: [[_MSCMP2:%.*]] = icmp ne i128 [[TMP15]], 0 +; CHECK-NEXT: br i1 [[_MSCMP2]], label [[TMP16:%.*]], label [[TMP17:%.*]], !prof [[PROF0]] +; CHECK: 16: +; CHECK-NEXT: call void @__msan_warning_with_origin_noreturn(i32 [[TMP6]]) #[[ATTR4]] +; CHECK-NEXT: unreachable +; CHECK: 17: +; CHECK-NEXT: [[_MSCMP3:%.*]] = icmp ne i64 [[TMP7]], 0 +; CHECK-NEXT: br i1 [[_MSCMP3]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]] +; CHECK: 18: +; CHECK-NEXT: call void @__msan_warning_with_origin_noreturn(i32 [[TMP8]]) #[[ATTR4]] +; CHECK-NEXT: unreachable +; CHECK: 19: +; CHECK-NEXT: call void @llvm.aarch64.neon.st3.v16i8.p0(<16 x i8> [[A]], <16 x i8> [[B]], <16 x i8> [[C]], ptr [[P]]) +; CHECK-NEXT: ret void +; + call void @llvm.aarch64.neon.st3.v16i8.p0(<16 x i8> %A, <16 x i8> %B, <16 x i8> %C, ptr %P) + ret void +} + +define void @st4_16b(<16 x i8> %A, <16 x i8> %B, <16 x i8> %C, <16 x i8> %D, ptr %P) nounwind sanitize_memory { +; +; CHECK-LABEL: define void @st4_16b +; CHECK-SAME: (<16 x i8> [[A:%.*]], <16 x i8> [[B:%.*]], <16 x i8> [[C:%.*]], <16 x i8> [[D:%.*]], ptr [[P:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[TMP1:%.*]] = load <16 x i8>, ptr @__msan_param_tls, align 8 +; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr @__msan_param_origin_tls, align 4 +; CHECK-NEXT: [[TMP3:%.*]] = load <16 x i8>, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 16) to ptr), align 8 +; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_origin_tls to i64), i64 16) to ptr), align 4 +; CHECK-NEXT: [[TMP5:%.*]] = load <16 x i8>, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 32) to ptr), align 8 +; CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_origin_tls to i64), i64 32) to ptr), align 4 +; CHECK-NEXT: [[TMP7:%.*]] = load <16 x i8>, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 48) to ptr), align 8 +; CHECK-NEXT: [[TMP8:%.*]] = load i32, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_origin_tls to i64), i64 48) to ptr), align 4 +; CHECK-NEXT: [[TMP9:%.*]] = load i64, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 64) to ptr), align 8 +; CHECK-NEXT: [[TMP10:%.*]] = load i32, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_origin_tls to i64), i64 64) to ptr), align 4 +; CHECK-NEXT: call void @llvm.donothing() +; CHECK-NEXT: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP1]] to i128 +; CHECK-NEXT: [[_MSCMP:%.*]] = icmp ne i128 [[TMP11]], 0 +; CHECK-NEXT: br i1 [[_MSCMP]], label [[TMP12:%.*]], label [[TMP13:%.*]], !prof [[PROF0]] +; CHECK: 12: +; CHECK-NEXT: call void @__msan_warning_with_origin_noreturn(i32 [[TMP2]]) #[[ATTR4]] +; CHECK-NEXT: unreachable +; CHECK: 13: +; CHECK-NEXT: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP3]] to i128 +; CHECK-NEXT: [[_MSCMP1:%.*]] = icmp ne i128 [[TMP14]], 0 +; CHECK-NEXT: br i1 [[_MSCMP1]], label [[TMP15:%.*]], label [[TMP16:%.*]], !prof [[PROF0]] +; CHECK: 15: +; CHECK-NEXT: call void @__msan_warning_with_origin_noreturn(i32 [[TMP4]]) #[[ATTR4]] +; CHECK-NEXT: unreachable +; CHECK: 16: +; CHECK-NEXT: [[TMP17:%.*]] = bitcast <16 x i8> [[TMP5]] to i128 +; CHECK-NEXT: [[_MSCMP2:%.*]] = icmp ne i128 [[TMP17]], 0 +; CHECK-NEXT: br i1 [[_MSCMP2]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]] +; CHECK: 18: +; CHECK-NEXT: call void @__msan_warning_with_origin_noreturn(i32 [[TMP6]]) #[[ATTR4]] +; CHECK-NEXT: unreachable +; CHECK: 19: +; CHECK-NEXT: [[TMP20:%.*]] = bitcast <16 x i8> [[TMP7]] to i128 +; CHECK-NEXT: [[_MSCMP3:%.*]] = icmp ne i128 [[TMP20]], 0 +; CHECK-NEXT: br i1 [[_MSCMP3]], label [[TMP21:%.*]], label [[TMP22:%.*]], !prof [[PROF0]] +; CHECK: 21: +; CHECK-NEXT: call void @__msan_warning_with_origin_noreturn(i32 [[TMP8]]) #[[ATTR4]] +; CHECK-NEXT: unreachable +; CHECK: 22: +; CHECK-NEXT: [[_MSCMP4:%.*]] = icmp ne i64 [[TMP9]], 0 +; CHECK-NEXT: br i1 [[_MSCMP4]], label [[TMP23:%.*]], label [[TMP24:%.*]], !prof [[PROF0]] +; CHECK: 23: +; CHECK-NEXT: call void @__msan_warning_with_origin_noreturn(i32 [[TMP10]]) #[[ATTR4]] +; CHECK-NEXT: unreachable +; CHECK: 24: +; CHECK-NEXT: call void @llvm.aarch64.neon.st4.v16i8.p0(<16 x i8> [[A]], <16 x i8> [[B]], <16 x i8> [[C]], <16 x i8> [[D]], ptr [[P]]) +; CHECK-NEXT: ret void +; + call void @llvm.aarch64.neon.st4.v16i8.p0(<16 x i8> %A, <16 x i8> %B, <16 x i8> %C, <16 x i8> %D, ptr %P) + ret void +} + +declare void @llvm.aarch64.neon.st2.v16i8.p0(<16 x i8>, <16 x i8>, ptr) nounwind sanitize_memory readonly +declare void @llvm.aarch64.neon.st3.v16i8.p0(<16 x i8>, <16 x i8>, <16 x i8>, ptr) nounwind sanitize_memory readonly +declare void @llvm.aarch64.neon.st4.v16i8.p0(<16 x i8>, <16 x i8>, <16 x i8>, <16 x i8>, ptr) nounwind sanitize_memory readonly diff --git a/llvm/test/MC/AArch64/elf-reloc-ptrauth.s b/llvm/test/MC/AArch64/elf-reloc-ptrauth.s index 3bd8f5c..057b298 100644 --- a/llvm/test/MC/AArch64/elf-reloc-ptrauth.s +++ b/llvm/test/MC/AArch64/elf-reloc-ptrauth.s @@ -3,16 +3,16 @@ // RUN: llvm-mc -triple=aarch64 -filetype=obj %s | \ // RUN: llvm-readelf -S -r -x .test - | FileCheck %s --check-prefix=RELOC -// RELOC: Relocation section '.rela.test' at offset 0x230 contains 8 entries: +// RELOC: Relocation section '.rela.test' at offset {{.*}} contains 8 entries: // RELOC-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend -// RELOC-NEXT: 0000000000000000 0000000100000244 R_AARCH64_AUTH_ABS64 0000000000000000 .helper + 0 -// RELOC-NEXT: 0000000000000010 0000000800000244 R_AARCH64_AUTH_ABS64 0000000000000000 _g1 + 0 -// RELOC-NEXT: 0000000000000020 0000000900000244 R_AARCH64_AUTH_ABS64 0000000000000000 _g2 + 0 -// RELOC-NEXT: 0000000000000030 0000000a00000244 R_AARCH64_AUTH_ABS64 0000000000000000 _g3 + 0 -// RELOC-NEXT: 0000000000000040 0000000b00000244 R_AARCH64_AUTH_ABS64 0000000000000000 _g4 + 7 -// RELOC-NEXT: 0000000000000050 0000000c00000244 R_AARCH64_AUTH_ABS64 0000000000000000 _g5 - 3 -// RELOC-NEXT: 0000000000000060 0000000200000244 R_AARCH64_AUTH_ABS64 0000000000000000 _g 6 + 0 -// RELOC-NEXT: 0000000000000070 0000000d00000244 R_AARCH64_AUTH_ABS64 0000000000000000 _g 7 + 7 +// RELOC-NEXT: 0000000000000000 {{.*}} R_AARCH64_AUTH_ABS64 0000000000000000 .helper + 0 +// RELOC-NEXT: 0000000000000010 {{.*}} R_AARCH64_AUTH_ABS64 0000000000000000 _g1 + 0 +// RELOC-NEXT: 0000000000000020 {{.*}} R_AARCH64_AUTH_ABS64 0000000000000000 _g2 + 0 +// RELOC-NEXT: 0000000000000030 {{.*}} R_AARCH64_AUTH_ABS64 0000000000000000 _g3 + 0 +// RELOC-NEXT: 0000000000000040 {{.*}} R_AARCH64_AUTH_ABS64 0000000000000000 _g4 + 7 +// RELOC-NEXT: 0000000000000050 {{.*}} R_AARCH64_AUTH_ABS64 0000000000000000 _g5 - 3 +// RELOC-NEXT: 0000000000000060 {{.*}} R_AARCH64_AUTH_ABS64 0000000000000000 _g 6 + 0 +// RELOC-NEXT: 0000000000000070 {{.*}} R_AARCH64_AUTH_ABS64 0000000000000000 _g 7 + 7 // RELOC: Hex dump of section '.test': // VVVVVVVV addend, not needed for rela diff --git a/llvm/test/Object/archive-malformed-object.test b/llvm/test/Object/archive-malformed-object.test index a927629..021df7e 100644 --- a/llvm/test/Object/archive-malformed-object.test +++ b/llvm/test/Object/archive-malformed-object.test @@ -1,27 +1,51 @@ ## Show that the archive library emits error messages when adding malformed -## objects. +## object files and skips symbol tables for "malformed" bitcode files, which +## are assumed to be bitcode files generated by compilers from the future. # RUN: rm -rf %t.dir # RUN: split-file %s %t.dir # RUN: cd %t.dir -## Malformed bitcode object is the first file member of archive if the symbol table is required. +## Create a malformed bitcode object. # RUN: llvm-as input.ll -o input.bc # RUN: cp input.bc good.bc # RUN: %python -c "with open('input.bc', 'a') as f: f.truncate(10)" -# RUN: not llvm-ar rc bad.a input.bc 2>&1 | FileCheck %s --check-prefix=ERR1 -## Malformed bitcode object is the last file member of archive if the symbol table is required. +## Malformed bitcode objects either warn or error depending on the archive format +## (see switch in getSymbolicFile). If the archive was created with a warning, +## we want to check that the archive map is empty. llvm-nm will fail when it +## tries to read the malformed bitcode file, but it's supposed to print the +## archive map first, which in this case it won't because there won't be one. # RUN: rm -rf bad.a -# RUN: not llvm-ar rc bad.a good.bc input.bc 2>&1 | FileCheck %s --check-prefix=ERR1 +# RUN: llvm-ar --format=bsd rc bad.a input.bc 2>&1 | FileCheck %s --check-prefix=WARN1 +# RUN: not llvm-nm --print-armap bad.a | count 0 +# RUN: rm -rf bad.a +# RUN: llvm-ar --format=gnu rc bad.a input.bc 2>&1 | FileCheck %s --check-prefix=WARN1 +# RUN: not llvm-nm --print-armap bad.a | count 0 +# RUN: rm -rf bad.a +# RUN: not llvm-ar --format=bigarchive rc bad.a input.bc 2>&1 | FileCheck %s --check-prefix=ERR1 +# RUN: rm -rf bad.a +# RUN: not llvm-ar --format=coff rc bad.a input.bc 2>&1 | FileCheck %s --check-prefix=ERR1 +# RUN: rm -rf bad.a +# RUN: not llvm-ar --format=darwin rc bad.a input.bc 2>&1 | FileCheck %s --check-prefix=ERR1 + +## Malformed bitcode object is the last file member of archive and +## the symbol table is required. In this case we check that the +## symbol table contains entries for the good object only. +# RUN: rm -rf bad.a +# RUN: llvm-ar rc bad.a good.bc input.bc 2>&1 | FileCheck %s --check-prefix=WARN1 +# RUN: not llvm-nm --print-armap bad.a | FileCheck %s --check-prefix=ARMAP ## Malformed bitcode object if the symbol table is not required for big archive. +## For big archives we print an error instead of a warning because the AIX linker +## presumably requires the index. # RUN: rm -rf bad.a # RUN: not llvm-ar --format=bigarchive rcS bad.a input.bc 2>&1 | FileCheck %s --check-prefix=ERR1 # RUN: rm -rf bad.a # RUN: not llvm-ar --format=bigarchive rcS bad.a good.bc input.bc 2>&1 | FileCheck %s --check-prefix=ERR1 # ERR1: error: bad.a: 'input.bc': Invalid bitcode signature +# WARN1: warning: 'input.bc': Invalid bitcode signature ## Non-bitcode malformed file. # RUN: yaml2obj input.yaml -o input.o @@ -29,17 +53,23 @@ # ERR2: error: bad.a: 'input.o': section header table goes past the end of the file: e_shoff = 0x9999 -## Don't emit an error if the symbol table is not required for formats other than the big archive format. -# RUN: llvm-ar --format=gnu rcS good.a input.o input.bc +## Don't emit an error or warning if the symbol table is not required for formats other than the big archive format. +# RUN: llvm-ar --format=gnu rcS good.a input.o input.bc 2>&1 | count 0 # RUN: llvm-ar t good.a | FileCheck %s --check-prefix=CONTENTS # CONTENTS: input.o # CONTENTS-NEXT: input.bc +# ARMAP: Archive map +# ARMAP-NEXT: foo in good.bc +# ARMAP-EMPTY: + #--- input.ll target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-linux" +@foo = global i32 1 + #--- input.yaml --- !ELF FileHeader: diff --git a/llvm/test/Transforms/VectorCombine/RISCV/vecreduce-of-cast.ll b/llvm/test/Transforms/VectorCombine/RISCV/vecreduce-of-cast.ll index 9b1aa19..f04bcc9 100644 --- a/llvm/test/Transforms/VectorCombine/RISCV/vecreduce-of-cast.ll +++ b/llvm/test/Transforms/VectorCombine/RISCV/vecreduce-of-cast.ll @@ -74,8 +74,8 @@ define i16 @reduce_mul_trunc_v8i64_i16(<8 x i64> %a0) { define i32 @reduce_or_sext_v8i8_to_v8i32(<8 x i8> %a0) { ; CHECK-LABEL: @reduce_or_sext_v8i8_to_v8i32( -; CHECK-NEXT: [[TR:%.*]] = sext <8 x i8> [[A0:%.*]] to <8 x i32> -; CHECK-NEXT: [[RED:%.*]] = tail call i32 @llvm.vector.reduce.or.v8i32(<8 x i32> [[TR]]) +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.vector.reduce.or.v8i8(<8 x i8> [[A0:%.*]]) +; CHECK-NEXT: [[RED:%.*]] = sext i8 [[TMP1]] to i32 ; CHECK-NEXT: ret i32 [[RED]] ; %tr = sext <8 x i8> %a0 to <8 x i32> @@ -85,8 +85,8 @@ define i32 @reduce_or_sext_v8i8_to_v8i32(<8 x i8> %a0) { define i32 @reduce_or_sext_v8i16_to_v8i32(<8 x i16> %a0) { ; CHECK-LABEL: @reduce_or_sext_v8i16_to_v8i32( -; CHECK-NEXT: [[TR:%.*]] = sext <8 x i16> [[A0:%.*]] to <8 x i32> -; CHECK-NEXT: [[RED:%.*]] = tail call i32 @llvm.vector.reduce.or.v8i32(<8 x i32> [[TR]]) +; CHECK-NEXT: [[TMP1:%.*]] = call i16 @llvm.vector.reduce.or.v8i16(<8 x i16> [[A0:%.*]]) +; CHECK-NEXT: [[RED:%.*]] = sext i16 [[TMP1]] to i32 ; CHECK-NEXT: ret i32 [[RED]] ; %tr = sext <8 x i16> %a0 to <8 x i32> @@ -96,8 +96,8 @@ define i32 @reduce_or_sext_v8i16_to_v8i32(<8 x i16> %a0) { define i32 @reduce_or_zext_v8i8_to_v8i32(<8 x i8> %a0) { ; CHECK-LABEL: @reduce_or_zext_v8i8_to_v8i32( -; CHECK-NEXT: [[TR:%.*]] = zext <8 x i8> [[A0:%.*]] to <8 x i32> -; CHECK-NEXT: [[RED:%.*]] = tail call i32 @llvm.vector.reduce.or.v8i32(<8 x i32> [[TR]]) +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.vector.reduce.or.v8i8(<8 x i8> [[A0:%.*]]) +; CHECK-NEXT: [[RED:%.*]] = zext i8 [[TMP1]] to i32 ; CHECK-NEXT: ret i32 [[RED]] ; %tr = zext <8 x i8> %a0 to <8 x i32> @@ -107,8 +107,8 @@ define i32 @reduce_or_zext_v8i8_to_v8i32(<8 x i8> %a0) { define i32 @reduce_or_zext_v8i16_to_v8i32(<8 x i16> %a0) { ; CHECK-LABEL: @reduce_or_zext_v8i16_to_v8i32( -; CHECK-NEXT: [[TR:%.*]] = zext <8 x i16> [[A0:%.*]] to <8 x i32> -; CHECK-NEXT: [[RED:%.*]] = tail call i32 @llvm.vector.reduce.or.v8i32(<8 x i32> [[TR]]) +; CHECK-NEXT: [[TMP1:%.*]] = call i16 @llvm.vector.reduce.or.v8i16(<8 x i16> [[A0:%.*]]) +; CHECK-NEXT: [[RED:%.*]] = zext i16 [[TMP1]] to i32 ; CHECK-NEXT: ret i32 [[RED]] ; %tr = zext <8 x i16> %a0 to <8 x i32> @@ -116,6 +116,20 @@ define i32 @reduce_or_zext_v8i16_to_v8i32(<8 x i16> %a0) { ret i32 %red } +; Negative case - narrowing the reduce (to i8) is illegal. +; TODO: We could narrow to i16 instead. +define i32 @reduce_add_trunc_v8i8_to_v8i32(<8 x i8> %a0) { +; CHECK-LABEL: @reduce_add_trunc_v8i8_to_v8i32( +; CHECK-NEXT: [[TR:%.*]] = zext <8 x i8> [[A0:%.*]] to <8 x i32> +; CHECK-NEXT: [[RED:%.*]] = tail call i32 @llvm.vector.reduce.add.v8i32(<8 x i32> [[TR]]) +; CHECK-NEXT: ret i32 [[RED]] +; + %tr = zext <8 x i8> %a0 to <8 x i32> + %red = tail call i32 @llvm.vector.reduce.add.v8i32(<8 x i32> %tr) + ret i32 %red +} + + declare i32 @llvm.vector.reduce.add.v8i32(<8 x i32>) declare i16 @llvm.vector.reduce.add.v8i16(<8 x i16>) declare i8 @llvm.vector.reduce.add.v8i8(<8 x i8>) diff --git a/llvm/test/Verifier/byval-size-limit.ll b/llvm/test/Verifier/byval-size-limit.ll new file mode 100644 index 0000000..3eb462b --- /dev/null +++ b/llvm/test/Verifier/byval-size-limit.ll @@ -0,0 +1,4 @@ +; RUN: not llvm-as < %s 2>&1 | FileCheck %s + +; CHECK: huge 'byval' arguments are unsupported +define void @f(ptr byval([2147483648 x i16])) { ret void } diff --git a/llvm/test/Verifier/param-align.ll b/llvm/test/Verifier/param-align.ll index bfd01cb..caa8f9a 100644 --- a/llvm/test/Verifier/param-align.ll +++ b/llvm/test/Verifier/param-align.ll @@ -2,19 +2,19 @@ ; Large vector for intrinsics is valid ; CHECK-NOT: llvm.fshr -define dso_local <8192 x i32> @test_intrin(<8192 x i32> %l, <8192 x i32> %r, <8192 x i32> %amt) { +define dso_local <2147483648 x i32> @test_intrin(<2147483648 x i32> %l, <2147483648 x i32> %r, <2147483648 x i32> %amt) { entry: - %b = call <8192 x i32> @llvm.fshr.v8192i32(<8192 x i32> %l, <8192 x i32> %r, <8192 x i32> %amt) - ret <8192 x i32> %b + %b = call <2147483648 x i32> @llvm.fshr.v8192i32(<2147483648 x i32> %l, <2147483648 x i32> %r, <2147483648 x i32> %amt) + ret <2147483648 x i32> %b } -declare <8192 x i32> @llvm.fshr.v8192i32 (<8192 x i32> %l, <8192 x i32> %r, <8192 x i32> %amt) +declare <2147483648 x i32> @llvm.fshr.v8192i32 (<2147483648 x i32> %l, <2147483648 x i32> %r, <2147483648 x i32> %amt) ; CHECK: Incorrect alignment of argument passed to called function! ; CHECK: bar -define dso_local void @foo(<8192 x float> noundef %vec) { +define dso_local void @foo(<2147483648 x float> noundef %vec) { entry: - call void @bar(<8192 x float> %vec) + call void @bar(<2147483648 x float> %vec) ret void } -declare dso_local void @bar(<8192 x float>) +declare dso_local void @bar(<2147483648 x float>) diff --git a/llvm/test/Verifier/param-attr-align.ll b/llvm/test/Verifier/param-attr-align.ll index 038bfa3..700efe5 100644 --- a/llvm/test/Verifier/param-attr-align.ll +++ b/llvm/test/Verifier/param-attr-align.ll @@ -1,9 +1,9 @@ ; RUN: not llvm-as < %s 2>&1 | FileCheck %s -; CHECK: Attribute 'align' exceed the max size 2^14 +; CHECK: huge alignments are not supported yet define dso_local void @foo(ptr %p) { entry: - call void @bar(ptr noundef byval(<8 x float>) align 32768 %p) + call void @bar(ptr noundef byval(<8 x float>) align 8589934592 %p) ret void } diff --git a/llvm/test/Verifier/param-ret-align.ll b/llvm/test/Verifier/param-ret-align.ll index dd302c3..98cbb4e 100644 --- a/llvm/test/Verifier/param-ret-align.ll +++ b/llvm/test/Verifier/param-ret-align.ll @@ -2,19 +2,19 @@ ; Large vector for intrinsics is valid ; CHECK-NOT: llvm.fshr -define dso_local <8192 x i32> @test_intrin(<8192 x i32> %l, <8192 x i32> %r, <8192 x i32> %amt) { +define dso_local <2147483648 x i32> @test_intrin(<2147483648 x i32> %l, <2147483648 x i32> %r, <2147483648 x i32> %amt) { entry: - %b = call <8192 x i32> @llvm.fshr.v8192i32(<8192 x i32> %l, <8192 x i32> %r, <8192 x i32> %amt) - ret <8192 x i32> %b + %b = call <2147483648 x i32> @llvm.fshr.v8192i32(<2147483648 x i32> %l, <2147483648 x i32> %r, <2147483648 x i32> %amt) + ret <2147483648 x i32> %b } -declare <8192 x i32> @llvm.fshr.v8192i32 (<8192 x i32> %l, <8192 x i32> %r, <8192 x i32> %amt) +declare <2147483648 x i32> @llvm.fshr.v2147483648i32 (<2147483648 x i32> %l, <2147483648 x i32> %r, <2147483648 x i32> %amt) ; CHECK: Incorrect alignment of return type to called function! ; CHECK: bar define dso_local void @foo() { entry: - call <8192 x float> @bar() + call <2147483648 x float> @bar() ret void } -declare dso_local <8192 x float> @bar() +declare dso_local <2147483648 x float> @bar() diff --git a/llvm/unittests/ADT/SetOperationsTest.cpp b/llvm/unittests/ADT/SetOperationsTest.cpp index b3d931c..da84c8a 100644 --- a/llvm/unittests/ADT/SetOperationsTest.cpp +++ b/llvm/unittests/ADT/SetOperationsTest.cpp @@ -8,6 +8,8 @@ #include "llvm/ADT/SetOperations.h" #include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -16,6 +18,7 @@ using namespace llvm; using testing::IsEmpty; +using testing::UnorderedElementsAre; namespace { @@ -199,6 +202,38 @@ TEST(SetOperationsTest, SetSubtract) { EXPECT_EQ(ExpectedSet2, Set2); } +TEST(SetOperationsTest, SetSubtractSmallPtrSet) { + int A[4]; + + // Set1.size() < Set2.size() + SmallPtrSet<int *, 4> Set1 = {&A[0], &A[1]}; + SmallPtrSet<int *, 4> Set2 = {&A[1], &A[2], &A[3]}; + set_subtract(Set1, Set2); + EXPECT_THAT(Set1, UnorderedElementsAre(&A[0])); + + // Set1.size() > Set2.size() + Set1 = {&A[0], &A[1], &A[2]}; + Set2 = {&A[0], &A[2]}; + set_subtract(Set1, Set2); + EXPECT_THAT(Set1, UnorderedElementsAre(&A[1])); +} + +TEST(SetOperationsTest, SetSubtractSmallVector) { + int A[4]; + + // Set1.size() < Set2.size() + SmallPtrSet<int *, 4> Set1 = {&A[0], &A[1]}; + SmallVector<int *> Set2 = {&A[1], &A[2], &A[3]}; + set_subtract(Set1, Set2); + EXPECT_THAT(Set1, UnorderedElementsAre(&A[0])); + + // Set1.size() > Set2.size() + Set1 = {&A[0], &A[1], &A[2]}; + Set2 = {&A[0], &A[2]}; + set_subtract(Set1, Set2); + EXPECT_THAT(Set1, UnorderedElementsAre(&A[1])); +} + TEST(SetOperationsTest, SetSubtractRemovedRemaining) { std::set<int> Removed, Remaining; diff --git a/llvm/unittests/SandboxIR/TrackerTest.cpp b/llvm/unittests/SandboxIR/TrackerTest.cpp index 4e5dccf..354cd18 100644 --- a/llvm/unittests/SandboxIR/TrackerTest.cpp +++ b/llvm/unittests/SandboxIR/TrackerTest.cpp @@ -198,3 +198,175 @@ define void @foo(i32 %v1) { EXPECT_EQ(&*It++, Ret); EXPECT_EQ(It, BB->end()); } + +// TODO: Test multi-instruction patterns. +TEST_F(TrackerTest, RemoveFromParent) { + parseIR(C, R"IR( +define i32 @foo(i32 %arg) { + %add0 = add i32 %arg, %arg + %add1 = add i32 %add0, %arg + ret i32 %add1 +} +)IR"); + Function &LLVMF = *M->getFunction("foo"); + sandboxir::Context Ctx(C); + + auto *F = Ctx.createFunction(&LLVMF); + auto *Arg = F->getArg(0); + auto *BB = &*F->begin(); + auto It = BB->begin(); + sandboxir::Instruction *Add0 = &*It++; + sandboxir::Instruction *Add1 = &*It++; + sandboxir::Instruction *Ret = &*It++; + + Ctx.save(); + // Check removeFromParent(). + Add1->removeFromParent(); + It = BB->begin(); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Ret); + EXPECT_EQ(It, BB->end()); + // Removed instruction still be connected to operands and users. + EXPECT_EQ(Add1->getOperand(0), Add0); + EXPECT_EQ(Add1->getOperand(1), Arg); + EXPECT_EQ(Add0->getNumUses(), 1u); + + // Check revert(). + Ctx.revert(); + It = BB->begin(); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Add1); + EXPECT_EQ(&*It++, Ret); + EXPECT_EQ(It, BB->end()); + EXPECT_EQ(Add1->getOperand(0), Add0); + + // Same for the last instruction in the block. + Ctx.save(); + Ret->removeFromParent(); + It = BB->begin(); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Add1); + EXPECT_EQ(It, BB->end()); + EXPECT_EQ(Ret->getOperand(0), Add1); + Ctx.revert(); + It = BB->begin(); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Add1); + EXPECT_EQ(&*It++, Ret); + EXPECT_EQ(It, BB->end()); +} + +// TODO: Test multi-instruction patterns. +TEST_F(TrackerTest, MoveInstr) { + parseIR(C, R"IR( +define i32 @foo(i32 %arg) { + %add0 = add i32 %arg, %arg + %add1 = add i32 %add0, %arg + ret i32 %add1 +} +)IR"); + Function &LLVMF = *M->getFunction("foo"); + sandboxir::Context Ctx(C); + + auto *F = Ctx.createFunction(&LLVMF); + auto *BB = &*F->begin(); + auto It = BB->begin(); + sandboxir::Instruction *Add0 = &*It++; + sandboxir::Instruction *Add1 = &*It++; + sandboxir::Instruction *Ret = &*It++; + + // Check moveBefore(Instruction *) with tracking enabled. + Ctx.save(); + Add1->moveBefore(Add0); + It = BB->begin(); + EXPECT_EQ(&*It++, Add1); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Ret); + EXPECT_EQ(It, BB->end()); + // Check revert(). + Ctx.revert(); + It = BB->begin(); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Add1); + EXPECT_EQ(&*It++, Ret); + EXPECT_EQ(It, BB->end()); + + // Same for the last instruction in the block. + Ctx.save(); + Ret->moveBefore(Add0); + It = BB->begin(); + EXPECT_EQ(&*It++, Ret); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Add1); + EXPECT_EQ(It, BB->end()); + Ctx.revert(); + It = BB->begin(); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Add1); + EXPECT_EQ(&*It++, Ret); + EXPECT_EQ(It, BB->end()); + + // Check moveBefore(BasicBlock &, BasicBlock::iterator) with tracking enabled. + Ctx.save(); + Add1->moveBefore(*BB, Add0->getIterator()); + It = BB->begin(); + EXPECT_EQ(&*It++, Add1); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Ret); + EXPECT_EQ(It, BB->end()); + // Check revert(). + Ctx.revert(); + It = BB->begin(); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Add1); + EXPECT_EQ(&*It++, Ret); + EXPECT_EQ(It, BB->end()); + + // Same for the last instruction in the block. + Ctx.save(); + Ret->moveBefore(*BB, Add0->getIterator()); + It = BB->begin(); + EXPECT_EQ(&*It++, Ret); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Add1); + EXPECT_EQ(It, BB->end()); + // Check revert(). + Ctx.revert(); + It = BB->begin(); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Add1); + EXPECT_EQ(&*It++, Ret); + EXPECT_EQ(It, BB->end()); + + // Check moveAfter(Instruction *) with tracking enabled. + Ctx.save(); + Add0->moveAfter(Add1); + It = BB->begin(); + EXPECT_EQ(&*It++, Add1); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Ret); + EXPECT_EQ(It, BB->end()); + // Check revert(). + Ctx.revert(); + It = BB->begin(); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Add1); + EXPECT_EQ(&*It++, Ret); + EXPECT_EQ(It, BB->end()); + + // Same for the last instruction in the block. + Ctx.save(); + Ret->moveAfter(Add0); + It = BB->begin(); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Ret); + EXPECT_EQ(&*It++, Add1); + EXPECT_EQ(It, BB->end()); + // Check revert(). + Ctx.revert(); + It = BB->begin(); + EXPECT_EQ(&*It++, Add0); + EXPECT_EQ(&*It++, Add1); + EXPECT_EQ(&*It++, Ret); + EXPECT_EQ(It, BB->end()); +} diff --git a/llvm/utils/gn/secondary/libcxx/include/BUILD.gn b/llvm/utils/gn/secondary/libcxx/include/BUILD.gn index 0349e63..27f29c3 100644 --- a/llvm/utils/gn/secondary/libcxx/include/BUILD.gn +++ b/llvm/utils/gn/secondary/libcxx/include/BUILD.gn @@ -604,6 +604,8 @@ if (current_toolchain == default_toolchain) { "__memory/concepts.h", "__memory/construct_at.h", "__memory/destruct_n.h", + "__memory/inout_ptr.h", + "__memory/out_ptr.h", "__memory/pointer_traits.h", "__memory/ranges_construct_at.h", "__memory/ranges_uninitialized_algorithms.h", diff --git a/llvm/utils/gn/secondary/lldb/source/API/BUILD.gn b/llvm/utils/gn/secondary/lldb/source/API/BUILD.gn index f0bf6a8..148f2cb 100644 --- a/llvm/utils/gn/secondary/lldb/source/API/BUILD.gn +++ b/llvm/utils/gn/secondary/lldb/source/API/BUILD.gn @@ -86,6 +86,7 @@ target(liblldb_type, "liblldb") { "SBQueue.cpp", "SBQueueItem.cpp", "SBReproducer.cpp", + "SBSaveCoreOptions.cpp", "SBScriptObject.cpp", "SBSection.cpp", "SBSourceManager.cpp", diff --git a/llvm/utils/gn/secondary/lldb/source/Symbol/BUILD.gn b/llvm/utils/gn/secondary/lldb/source/Symbol/BUILD.gn index db769f2..3b1df82 100644 --- a/llvm/utils/gn/secondary/lldb/source/Symbol/BUILD.gn +++ b/llvm/utils/gn/secondary/lldb/source/Symbol/BUILD.gn @@ -29,6 +29,7 @@ static_library("Symbol") { "ObjectContainer.cpp", "ObjectFile.cpp", "PostfixExpression.cpp", + "SaveCoreOptions.cpp", "Symbol.cpp", "SymbolContext.cpp", "SymbolFile.cpp", diff --git a/llvm/utils/lit/lit/builtin_commands/cat.py b/llvm/utils/lit/lit/builtin_commands/cat.py index 6fb2152..d6dbe88 100644 --- a/llvm/utils/lit/lit/builtin_commands/cat.py +++ b/llvm/utils/lit/lit/builtin_commands/cat.py @@ -10,7 +10,7 @@ except ImportError: def convertToCaretAndMNotation(data): newdata = StringIO() if isinstance(data, str): - data = bytearray(data) + data = bytearray(data.encode()) for intval in data: if intval == 9 or intval == 10: diff --git a/mlir/lib/Dialect/ArmSME/Transforms/TileAllocation.cpp b/mlir/lib/Dialect/ArmSME/Transforms/TileAllocation.cpp index 5cac770..3a2042d 100644 --- a/mlir/lib/Dialect/ArmSME/Transforms/TileAllocation.cpp +++ b/mlir/lib/Dialect/ArmSME/Transforms/TileAllocation.cpp @@ -620,6 +620,7 @@ void allocateTilesToLiveRanges( if (!activeRanges.remove(rangeToSpill)) { bool removed = inactiveRanges.remove(rangeToSpill); assert(removed && "expected a range to be removed!"); + (void)removed; } } rangeToSpill->tileId = tileAllocator.allocateInMemoryTileId(); diff --git a/utils/bazel/WORKSPACE b/utils/bazel/WORKSPACE index 298b64f..7baca11 100644 --- a/utils/bazel/WORKSPACE +++ b/utils/bazel/WORKSPACE @@ -2,7 +2,6 @@ # See https://llvm.org/LICENSE.txt for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") @@ -29,6 +28,14 @@ llvm_configure(name = "llvm-project") maybe( http_archive, + name = "rules_python", + sha256 = "778aaeab3e6cfd56d681c89f5c10d7ad6bf8d2f1a72de9de55b23081b2d31618", + strip_prefix = "rules_python-0.34.0", + url = "https://github.com/bazelbuild/rules_python/releases/download/0.34.0/rules_python-0.34.0.tar.gz", +) + +maybe( + http_archive, name = "llvm_zlib", build_file = "@llvm-raw//utils/bazel/third_party_build:zlib-ng.BUILD", sha256 = "e36bb346c00472a1f9ff2a0a4643e590a254be6379da7cddd9daeb9a7f296731", @@ -76,10 +83,11 @@ apple_support_dependencies() # Note: that building from source requires `m4` to be installed on the host machine. # This is a known issue: https://github.com/bazelbuild/rules_foreign_cc/issues/755. -git_repository( +http_archive( name = "rules_foreign_cc", - remote = "https://github.com/bazelbuild/rules_foreign_cc.git", - tag = "0.9.0", + sha256 = "4b33d62cf109bcccf286b30ed7121129cc34cf4f4ed9d8a11f38d9108f40ba74", + strip_prefix = "rules_foreign_cc-0.11.1", + url = "https://github.com/bazelbuild/rules_foreign_cc/releases/download/0.11.1/rules_foreign_cc-0.11.1.tar.gz", ) load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies") @@ -112,11 +120,12 @@ maybe( ) maybe( - new_git_repository, + http_archive, name = "pfm", build_file = "@llvm-raw//utils/bazel/third_party_build:pfm.BUILD", - remote = "https://git.code.sf.net/p/perfmon2/libpfm4", - tag = "v4.12.1", + sha256 = "d18b97764c755528c1051d376e33545d0eb60c6ebf85680436813fa5b04cc3d1", + strip_prefix = "libpfm-4.13.0", + urls = ["https://versaweb.dl.sourceforge.net/project/perfmon2/libpfm4/libpfm-4.13.0.tar.gz"], ) maybe( @@ -129,3 +138,21 @@ maybe( "https://github.com/facebook/zstd/releases/download/v1.5.2/zstd-1.5.2.tar.gz", ], ) + +maybe( + http_archive, + name = "pybind11", + build_file = "@llvm-raw//utils/bazel/third_party_build:pybind.BUILD", + sha256 = "201966a61dc826f1b1879a24a3317a1ec9214a918c8eb035be2f30c3e9cfbdcb", + strip_prefix = "pybind11-2.10.3", + url = "https://github.com/pybind/pybind11/archive/v2.10.3.zip", +) + +load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains") + +py_repositories() + +python_register_toolchains( + name = "python_3_12", + python_version = "3.12", +) diff --git a/utils/bazel/llvm-project-overlay/lldb/BUILD.bazel b/utils/bazel/llvm-project-overlay/lldb/BUILD.bazel index cc57386..6d5a1b8 100644 --- a/utils/bazel/llvm-project-overlay/lldb/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/lldb/BUILD.bazel @@ -707,7 +707,9 @@ cc_library( cc_library( name = "Headers", - hdrs = glob(["include/lldb/lldb-*.h"]), + hdrs = glob(["include/lldb/lldb-*.h"]) + [ + "include/lldb/Symbol/SaveCoreOptions.h", + ], strip_include_prefix = "include", ) diff --git a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel index fe67286..0d0224e 100644 --- a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel @@ -918,24 +918,14 @@ exports_files( glob(["lib/Bindings/Python/**/*.cpp"]), ) -# In the targets related to Python bindings, the projects @pybind11 and -# @local_config_python are defined by @pybind11_bazel. The latter contains -# python headers, and can be configured in an out-of-tree bazel project via -# -# load("@pybind11_bazel//:python_configure.bzl", "python_configure") -# python_configure(name = "local_config_python") -# -# For more up-to-date instructions, see -# https://github.com/pybind/pybind11_bazel -# -# Some out-of-tree projects alias @python_runtime//:headers to -# @local_config_python//:python_headers. - -MLIR_BINDINGS_PYTHON_HEADERS = [ - "lib/Bindings/Python/*.h", - "include/mlir-c/Bindings/Python/*.h", - "include/mlir/Bindings/Python/*.h", -] +filegroup( + name = "MLIRBindingsPythonHeaderFiles", + srcs = glob([ + "lib/Bindings/Python/*.h", + "include/mlir-c/Bindings/Python/*.h", + "include/mlir/Bindings/Python/*.h", + ]), +) cc_library( name = "MLIRBindingsPythonHeaders", @@ -943,16 +933,12 @@ cc_library( "include", "lib/Bindings/Python", ], - tags = [ - "manual", # External dependency - "nobuildkite", # TODO(gcmn): Add support for this target - ], - textual_hdrs = glob(MLIR_BINDINGS_PYTHON_HEADERS), + textual_hdrs = [":MLIRBindingsPythonHeaderFiles"], deps = [ ":CAPIIRHeaders", ":CAPITransformsHeaders", - "@local_config_python//:python_headers", "@pybind11", + "@rules_python//python/cc:current_py_cc_headers", ], ) @@ -962,16 +948,12 @@ cc_library( "include", "lib/Bindings/Python", ], - tags = [ - "manual", # External dependency - "nobuildkite", # TODO(gcmn): Add support for this target - ], - textual_hdrs = glob(MLIR_BINDINGS_PYTHON_HEADERS), + textual_hdrs = [":MLIRBindingsPythonHeaderFiles"], deps = [ ":CAPIIR", ":CAPITransforms", - "@local_config_python//:python_headers", "@pybind11", + "@rules_python//python/cc:current_py_cc_headers", ], ) @@ -986,26 +968,25 @@ PYBIND11_FEATURES = [ "-use_header_modules", ] -MLIR_PYTHON_BINDINGS_SOURCES = [ - "lib/Bindings/Python/IRAffine.cpp", - "lib/Bindings/Python/IRAttributes.cpp", - "lib/Bindings/Python/IRCore.cpp", - "lib/Bindings/Python/IRInterfaces.cpp", - "lib/Bindings/Python/IRModule.cpp", - "lib/Bindings/Python/IRTypes.cpp", - "lib/Bindings/Python/Pass.cpp", - "lib/Bindings/Python/Rewrite.cpp", -] +filegroup( + name = "MLIRBindingsPythonSourceFiles", + srcs = [ + "lib/Bindings/Python/IRAffine.cpp", + "lib/Bindings/Python/IRAttributes.cpp", + "lib/Bindings/Python/IRCore.cpp", + "lib/Bindings/Python/IRInterfaces.cpp", + "lib/Bindings/Python/IRModule.cpp", + "lib/Bindings/Python/IRTypes.cpp", + "lib/Bindings/Python/Pass.cpp", + "lib/Bindings/Python/Rewrite.cpp", + ], +) cc_library( name = "MLIRBindingsPythonCore", - srcs = MLIR_PYTHON_BINDINGS_SOURCES, + srcs = [":MLIRBindingsPythonSourceFiles"], copts = PYBIND11_COPTS, features = PYBIND11_FEATURES, - tags = [ - "manual", # External dependency - "nobuildkite", # TODO(gcmn): Add support for this target - ], deps = [ ":CAPIAsync", ":CAPIDebug", @@ -1015,20 +996,16 @@ cc_library( ":Support", ":config", "//llvm:Support", - "@local_config_python//:python_headers", "@pybind11", + "@rules_python//python/cc:current_py_cc_headers", ], ) cc_library( name = "MLIRBindingsPythonCoreNoCAPI", - srcs = MLIR_PYTHON_BINDINGS_SOURCES, + srcs = [":MLIRBindingsPythonSourceFiles"], copts = PYBIND11_COPTS, features = PYBIND11_FEATURES, - tags = [ - "manual", # External dependency - "nobuildkite", # TODO(gcmn): Add support for this target - ], deps = [ ":CAPIAsyncHeaders", ":CAPIDebugHeaders", @@ -1037,8 +1014,8 @@ cc_library( ":Support", ":config", "//llvm:Support", - "@local_config_python//:python_headers", "@pybind11", + "@rules_python//python/cc:current_py_cc_headers", ], ) @@ -1046,10 +1023,6 @@ cc_library( # MLIRBindingsPythonCoreNoCAPI. cc_library( name = "MLIRBindingsPythonCAPIObjects", - tags = [ - "manual", # External dependency - "nobuildkite", # TODO(gcmn): Add support for this target - ], deps = [ ":CAPIAsyncObjects", ":CAPIDebugObjects", @@ -1068,10 +1041,6 @@ cc_binary( features = PYBIND11_FEATURES, linkshared = 1, linkstatic = 0, - tags = [ - "manual", # External dependency - "nobuildkite", # TODO(gcmn): Add support for this target - ], deps = [ ":MLIRBindingsPythonCore", ":MLIRBindingsPythonHeadersAndDeps", @@ -1085,10 +1054,6 @@ cc_binary( features = PYBIND11_FEATURES, linkshared = 1, linkstatic = 0, - tags = [ - "manual", # External dependency - "nobuildkite", # TODO(gcmn): Add support for this target - ], deps = [ ":CAPIIR", ":CAPILinalg", @@ -1103,10 +1068,6 @@ cc_binary( features = PYBIND11_FEATURES, linkshared = 1, linkstatic = 0, - tags = [ - "manual", # External dependency - "nobuildkite", - ], deps = [ ":CAPIIR", ":CAPILLVM", @@ -1122,10 +1083,6 @@ cc_binary( features = PYBIND11_FEATURES, linkshared = 1, linkstatic = 0, - tags = [ - "manual", # External dependency - "nobuildkite", # TODO(gcmn): Add support for this target - ], deps = [ ":CAPIIR", ":CAPIQuant", @@ -1141,10 +1098,6 @@ cc_binary( features = PYBIND11_FEATURES, linkshared = 1, linkstatic = 0, - tags = [ - "manual", # External dependency - "nobuildkite", # TODO(gcmn): Add support for this target - ], deps = [ ":CAPIIR", ":CAPISparseTensor", @@ -1161,15 +1114,11 @@ cc_binary( features = PYBIND11_FEATURES, linkshared = 1, linkstatic = 0, - tags = [ - "manual", # External dependency - "nobuildkite", # TODO(gcmn): Add support for this target - ], deps = [ ":CAPIExecutionEngine", ":MLIRBindingsPythonHeadersAndDeps", - "@local_config_python//:python_headers", "@pybind11", + "@rules_python//python/cc:current_py_cc_headers", ], ) @@ -1181,15 +1130,11 @@ cc_binary( features = PYBIND11_FEATURES, linkshared = 1, linkstatic = 0, - tags = [ - "manual", # External dependency - "nobuildkite", # TODO(gcmn): Add support for this target - ], deps = [ ":CAPILinalg", ":MLIRBindingsPythonHeadersAndDeps", - "@local_config_python//:python_headers", "@pybind11", + "@rules_python//python/cc:current_py_cc_headers", ], ) diff --git a/utils/bazel/third_party_build/pybind.BUILD b/utils/bazel/third_party_build/pybind.BUILD new file mode 100644 index 0000000..d9fb431 --- /dev/null +++ b/utils/bazel/third_party_build/pybind.BUILD @@ -0,0 +1,15 @@ +cc_library( + name = "pybind11", + hdrs = glob( + include = ["include/pybind11/**/*.h"], + exclude = [ + # Deprecated file that just emits a warning + "include/pybind11/common.h", + ], + ), + includes = ["include"], + visibility = ["//visibility:public"], + deps = [ + "@rules_python//python/cc:current_py_cc_headers", + ], +) |