diff --git a/llvm/include/llvm/Support/BCD.h b/llvm/include/llvm/Support/BCD.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Support/BCD.h @@ -0,0 +1,53 @@ +//===- llvm/Support/BCD.h - Binary-Coded Decimal utility functions -*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file declares some utility functions for encoding/decoding BCD values. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BCD_H +#define LLVM_SUPPORT_BCD_H + +#include +#include +#include + +namespace llvm { + +// Decode a packed BCD value. +// Maximum value of int64_t is 9,223,372,036,854,775,807. These are 18 usable +// decimal digits. Thus BCD numbers of up to 9 bytes can be converted. +// Please note that s390 supports BCD numbers up to a length of 16 bytes. +inline int64_t decodePackedBCD(const uint8_t *Ptr, size_t ByteLen, + bool IsSigned = true) { + assert(ByteLen >= 1 && ByteLen <= 9 && "Invalid BCD number"); + int64_t Value = 0; + size_t RunLen = ByteLen - static_cast(IsSigned); + for (size_t I = 0; I < RunLen; ++I) { + uint8_t DecodedByteValue = ((Ptr[I] >> 4) & 0x0f) * 10 + (Ptr[I] & 0x0f); + Value = (Value * 100) + DecodedByteValue; + } + if (IsSigned) { + uint8_t DecodedByteValue = (Ptr[ByteLen - 1] >> 4) & 0x0f; + uint8_t Sign = Ptr[ByteLen - 1] & 0x0f; + Value = (Value * 10) + DecodedByteValue; + if (Sign == 0x0d || Sign == 0x0b) + Value *= -1; + } + return Value; +} + +template +inline ResultT decodePackedBCD(const ValT Val, bool IsSigned = true) { + return static_cast(decodePackedBCD( + reinterpret_cast(&Val), sizeof(ValT), IsSigned)); +} + +} // namespace llvm + +#endif // LLVM_SUPPORT_BCD_H diff --git a/llvm/lib/Support/Host.cpp b/llvm/lib/Support/Host.cpp --- a/llvm/lib/Support/Host.cpp +++ b/llvm/lib/Support/Host.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/Config/llvm-config.h" +#include "llvm/Support/BCD.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" @@ -296,6 +297,22 @@ return "generic"; } +namespace { +StringRef getCPUNameFromS390Model(unsigned int Id, bool HaveVectorSupport) { + if (Id >= 8561 && HaveVectorSupport) + return "z15"; + if (Id >= 3906 && HaveVectorSupport) + return "z14"; + if (Id >= 2964 && HaveVectorSupport) + return "z13"; + if (Id >= 2827) + return "zEC12"; + if (Id >= 2817) + return "z196"; + return "generic"; +} +} // end anonymous namespace + StringRef sys::detail::getHostCPUNameForS390x(StringRef ProcCpuinfoContent) { // STIDP is a privileged operation, so use /proc/cpuinfo instead. @@ -331,18 +348,8 @@ if (Pos != StringRef::npos) { Pos += sizeof("machine = ") - 1; unsigned int Id; - if (!Lines[I].drop_front(Pos).getAsInteger(10, Id)) { - if (Id >= 8561 && HaveVectorSupport) - return "z15"; - if (Id >= 3906 && HaveVectorSupport) - return "z14"; - if (Id >= 2964 && HaveVectorSupport) - return "z13"; - if (Id >= 2827) - return "zEC12"; - if (Id >= 2817) - return "z196"; - } + if (!Lines[I].drop_front(Pos).getAsInteger(10, Id)) + return getCPUNameFromS390Model(Id, HaveVectorSupport); } break; } @@ -1229,6 +1236,29 @@ StringRef Content = P ? P->getBuffer() : ""; return detail::getHostCPUNameForS390x(Content); } +#elif defined(__MVS__) +StringRef sys::getHostCPUName() { + // Get pointer to Communications Vector Table (CVT). + // The pointer is located at offset 16 of the Prefixed Save Area (PSA). + // It is stored as 31 bit pointer and will be zero-extended to 64 bit. + int *StartToCVTOffset = reinterpret_cast(0x10); + // Since its stored as a 31-bit pointer, get the 4 bytes from the start + // of address. + int ReadValue = *StartToCVTOffset; + // Explicitly clear the high order bit. + ReadValue = (ReadValue & 0x7FFFFFFF); + char *CVT = reinterpret_cast(ReadValue); + // The model number is located in the CVT prefix at offset -6 and stored as + // signless packed decimal. + uint16_t Id = *(uint16_t *)&CVT[-6]; + // Convert number to integer. + Id = decodePackedBCD(Id, false); + // Check for vector support. It's stored in field CVTFLAG5 (offset 244), + // bit CVTVEF (X'80'). The facilities list is part of the PSA but the vector + // extension can only be used if bit CVTVEF is on. + bool HaveVectorSupport = CVT[244] & 0x80; + return getCPUNameFromS390Model(Id, HaveVectorSupport); +} #elif defined(__APPLE__) && defined(__aarch64__) StringRef sys::getHostCPUName() { return "cyclone"; diff --git a/llvm/unittests/Support/Host.cpp b/llvm/unittests/Support/Host.cpp --- a/llvm/unittests/Support/Host.cpp +++ b/llvm/unittests/Support/Host.cpp @@ -310,6 +310,54 @@ EXPECT_EQ(sys::detail::getHostCPUNameForARM(Snapdragon865ProcCPUInfo), "cortex-a77"); } +TEST(getLinuxHostCPUName, s390x) { + SmallVector ModelIDs( + {"8561", "3906", "2964", "2827", "2817", "7"}); + SmallVector VectorSupport({"", "vx"}); + SmallVector ExpectedCPUs; + + // Model Id: 8561 + ExpectedCPUs.push_back("zEC12"); + ExpectedCPUs.push_back("z15"); + + // Model Id: 3906 + ExpectedCPUs.push_back("zEC12"); + ExpectedCPUs.push_back("z14"); + + // Model Id: 2964 + ExpectedCPUs.push_back("zEC12"); + ExpectedCPUs.push_back("z13"); + + // Model Id: 2827 + ExpectedCPUs.push_back("zEC12"); + ExpectedCPUs.push_back("zEC12"); + + // Model Id: 2817 + ExpectedCPUs.push_back("z196"); + ExpectedCPUs.push_back("z196"); + + // Model Id: 7 + ExpectedCPUs.push_back("generic"); + ExpectedCPUs.push_back("generic"); + + const std::string DummyBaseVectorInfo = + "features : esan3 zarch stfle msa ldisp eimm dfp edat etf3eh highgprs " + "te "; + const std::string DummyBaseMachineInfo = + "processor 0: version = FF, identification = 059C88, machine = "; + + int CheckIndex = 0; + for (size_t I = 0; I < ModelIDs.size(); I++) { + for (size_t J = 0; J < VectorSupport.size(); J++) { + const std::string DummyCPUInfo = DummyBaseVectorInfo + VectorSupport[J] + + "\n" + DummyBaseMachineInfo + + ModelIDs[I]; + EXPECT_EQ(sys::detail::getHostCPUNameForS390x(DummyCPUInfo), + ExpectedCPUs[CheckIndex++]); + } + } +} + #if defined(__APPLE__) || defined(_AIX) static bool runAndGetCommandOutput( const char *ExePath, ArrayRef argv,