Index: include/llvm/XRay/XRayRecord.h =================================================================== --- include/llvm/XRay/XRayRecord.h +++ include/llvm/XRay/XRayRecord.h @@ -53,7 +53,7 @@ /// This may or may not correspond to actual record types in the raw trace (as /// the loader implementation may synthesize this information in the process of /// of loading). -enum class RecordTypes { ENTER, EXIT }; +enum class RecordTypes { ENTER, EXIT, TAIL_EXIT }; struct XRayRecord { /// The type of record. Index: include/llvm/XRay/YAMLXRayRecord.h =================================================================== --- include/llvm/XRay/YAMLXRayRecord.h +++ include/llvm/XRay/YAMLXRayRecord.h @@ -54,6 +54,7 @@ static void enumeration(IO &IO, xray::RecordTypes &Type) { IO.enumCase(Type, "function-enter", xray::RecordTypes::ENTER); IO.enumCase(Type, "function-exit", xray::RecordTypes::EXIT); + IO.enumCase(Type, "function-tail-exit", xray::RecordTypes::TAIL_EXIT); } }; Index: lib/XRay/Trace.cpp =================================================================== --- lib/XRay/Trace.cpp +++ lib/XRay/Trace.cpp @@ -48,7 +48,7 @@ FileHeader.NonstopTSC = Bitfield & 1uL << 1; FileHeader.CycleFrequency = HeaderExtractor.getU64(&OffsetPtr); std::memcpy(&FileHeader.FreeFormData, Data.bytes_begin() + OffsetPtr, 16); - if (FileHeader.Version != 1) + if (FileHeader.Version != 1 && FileHeader.Version != 2) return make_error( Twine("Unsupported XRay file version: ") + Twine(FileHeader.Version), std::make_error_code(std::errc::invalid_argument)); @@ -94,6 +94,14 @@ case 1: Record.Type = RecordTypes::EXIT; break; + case 2: + if (FileHeader.Version == 2) + Record.Type = RecordTypes::TAIL_EXIT; + else + return make_error( + Twine("Unsupported record type: ") + Twine(int{Type}) + + "; Tail exits only supported in Version 2 of the log.", + std::make_error_code(std::errc::executable_format_error)); default: return make_error( Twine("Unknown record type '") + Twine(int{Type}) + "'", @@ -320,8 +328,8 @@ Record.Type = RecordTypes::ENTER; break; case static_cast(RecordTypes::EXIT): - case 2: // TAIL_EXIT is not yet defined in RecordTypes. - Record.Type = RecordTypes::EXIT; + case 2: + Record.Type = RecordTypes::TAIL_EXIT; break; default: // Cast to an unsigned integer to not interpret the record type as a char. @@ -443,7 +451,7 @@ // Having iterated over everything we've been given, we've either consumed // everything and ended up in the end state, or were told to skip the rest. bool Finished = State.Expects == FDRState::Token::SCAN_TO_END_OF_THREAD_BUF && - State.CurrentBufferSize == State.CurrentBufferConsumed; + State.CurrentBufferSize == State.CurrentBufferConsumed; if (State.Expects != FDRState::Token::NEW_BUFFER_RECORD_OR_EOF && !Finished) return make_error( Twine("Encountered EOF with unexpected state expectation ") + @@ -535,8 +543,7 @@ Trace T; if (Version == 1 && Type == NAIVE_FORMAT) { - if (auto E = - loadNaiveFormatLog(Data, T.FileHeader, T.Records)) + if (auto E = loadNaiveFormatLog(Data, T.FileHeader, T.Records)) return std::move(E); } else if (Version == 1 && Type == FLIGHT_DATA_RECORDER_FORMAT) { if (auto E = loadFDRLog(Data, T.FileHeader, T.Records)) Index: tools/llvm-xray/xray-account.cc =================================================================== --- tools/llvm-xray/xray-account.cc +++ tools/llvm-xray/xray-account.cc @@ -150,7 +150,8 @@ ThreadStack.emplace_back(Record.FuncId, Record.TSC); break; } - case RecordTypes::EXIT: { + case RecordTypes::EXIT: + case RecordTypes::TAIL_EXIT: { if (ThreadStack.empty()) return false; @@ -419,6 +420,9 @@ case RecordTypes::EXIT: Stream << "exit"; break; + case RecordTypes::TAIL_EXIT: + Stream << "tail-exit"; + break; } } }; Index: tools/llvm-xray/xray-converter.cc =================================================================== --- tools/llvm-xray/xray-converter.cc +++ tools/llvm-xray/xray-converter.cc @@ -128,6 +128,8 @@ case RecordTypes::EXIT: Writer.write(uint8_t{1}); break; + case RecordTypes::TAIL_EXIT: + Writer.write(uint8_t{2}); } Writer.write(R.FuncId); Writer.write(R.TSC); Index: tools/llvm-xray/xray-graph.cc =================================================================== --- tools/llvm-xray/xray-graph.cc +++ tools/llvm-xray/xray-graph.cc @@ -214,7 +214,8 @@ ThreadStack.push_back({Record.FuncId, Record.TSC}); break; } - case RecordTypes::EXIT: { + case RecordTypes::EXIT: + case RecordTypes::TAIL_EXIT: { // FIXME: Refactor this and the account subcommand to reduce code // duplication if (ThreadStack.size() == 0 || ThreadStack.back().FuncId != Record.FuncId) { Index: tools/llvm-xray/xray-stacks.cc =================================================================== --- tools/llvm-xray/xray-stacks.cc +++ tools/llvm-xray/xray-stacks.cc @@ -352,7 +352,8 @@ } return AccountRecordStatus::OK; } - case RecordTypes::EXIT: { + case RecordTypes::EXIT: + case RecordTypes::TAIL_EXIT: { bool wasLastRecordExit = state->wasLastRecordExit; state->wasLastRecordExit = true; // The exit case is more interesting, since we want to be able to deduce