180 changes: 0 additions & 180 deletions libc/src/__support/FPUtil/XFloat.h

This file was deleted.

1 change: 1 addition & 0 deletions libc/src/stdbit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ set(prefixes
leading_zeros
leading_ones
trailing_zeros
trailing_ones
)
set(suffixes c s i l ll)
foreach(prefix IN LISTS prefixes)
Expand Down
20 changes: 20 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_uc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation of stdc_trailing_ones_uc ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/stdbit/stdc_trailing_ones_uc.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned, stdc_trailing_ones_uc, (unsigned char value)) {
return static_cast<unsigned>(cpp::countr_one(value));
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_uc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for stdc_trailing_ones_uc --------*- 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 LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_UC_H
#define LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_UC_H

namespace LIBC_NAMESPACE {

unsigned stdc_trailing_ones_uc(unsigned char value);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_UC_H
20 changes: 20 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_ui.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation of stdc_trailing_ones_ui ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/stdbit/stdc_trailing_ones_ui.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned, stdc_trailing_ones_ui, (unsigned value)) {
return static_cast<unsigned>(cpp::countr_one(value));
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_ui.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for stdc_trailing_ones_ui --------*- 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 LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_UI_H
#define LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_UI_H

namespace LIBC_NAMESPACE {

unsigned stdc_trailing_ones_ui(unsigned value);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_UI_H
20 changes: 20 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_ul.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation of stdc_trailing_ones_ul ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/stdbit/stdc_trailing_ones_ul.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned, stdc_trailing_ones_ul, (unsigned long value)) {
return static_cast<unsigned>(cpp::countr_one(value));
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_ul.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for stdc_trailing_ones_ul --------*- 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 LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_UL_H
#define LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_UL_H

namespace LIBC_NAMESPACE {

unsigned stdc_trailing_ones_ul(unsigned long value);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_UL_H
21 changes: 21 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_ull.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===-- Implementation of stdc_trailing_ones_ull --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/stdbit/stdc_trailing_ones_ull.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned, stdc_trailing_ones_ull,
(unsigned long long value)) {
return static_cast<unsigned>(cpp::countr_one(value));
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_ull.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for stdc_trailing_ones_ull --------*- 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 LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_ULL_H
#define LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_ULL_H

namespace LIBC_NAMESPACE {

unsigned stdc_trailing_ones_ull(unsigned long long value);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_ULL_H
20 changes: 20 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_us.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation of stdc_trailing_ones_us ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/stdbit/stdc_trailing_ones_us.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned, stdc_trailing_ones_us, (unsigned short value)) {
return static_cast<unsigned>(cpp::countr_one(value));
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_us.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for stdc_trailing_ones_us --------*- 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 LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_US_H
#define LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_US_H

namespace LIBC_NAMESPACE {

unsigned stdc_trailing_ones_us(unsigned short value);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_US_H
2 changes: 2 additions & 0 deletions libc/src/stdio/printf_core/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ int convert(Writer *writer, const FormatSection &to_conv) {
case 'o':
case 'x':
case 'X':
case 'b':
case 'B':
return convert_int(writer, to_conv);
#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT
case 'f':
Expand Down
22 changes: 16 additions & 6 deletions libc/src/stdio/printf_core/int_converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,17 @@ using HexFmt = IntegerToString<uintmax_t, radix::Hex>;
using HexFmtUppercase = IntegerToString<uintmax_t, radix::Hex::Uppercase>;
using OctFmt = IntegerToString<uintmax_t, radix::Oct>;
using DecFmt = IntegerToString<uintmax_t>;
using BinFmt = IntegerToString<uintmax_t, radix::Bin>;

LIBC_INLINE constexpr size_t num_buf_size() {
constexpr auto max = [](size_t a, size_t b) -> size_t {
return (a < b) ? b : a;
};
return max(HexFmt::buffer_size(),
max(HexFmtUppercase::buffer_size(),
max(OctFmt::buffer_size(), DecFmt::buffer_size())));
cpp::array<size_t, 5> sizes{
HexFmt::buffer_size(), HexFmtUppercase::buffer_size(),
OctFmt::buffer_size(), DecFmt::buffer_size(), BinFmt::buffer_size()};

auto result = sizes[0];
for (size_t i = 1; i < sizes.size(); i++)
result = cpp::max(result, sizes[i]);
return result;
}

LIBC_INLINE cpp::optional<cpp::string_view>
Expand All @@ -52,6 +55,8 @@ num_to_strview(uintmax_t num, cpp::span<char> bufref, char conv_name) {
return HexFmtUppercase::format_to(bufref, num);
} else if (conv_name == 'o') {
return OctFmt::format_to(bufref, num);
} else if (to_lower(conv_name) == 'b') {
return BinFmt::format_to(bufref, num);
} else {
return DecFmt::format_to(bufref, num);
}
Expand Down Expand Up @@ -116,6 +121,11 @@ LIBC_INLINE int convert_int(Writer *writer, const FormatSection &to_conv) {
prefix_len = 2;
prefix[0] = '0';
prefix[1] = a + ('x' - 'a');
} else if ((to_lower(to_conv.conv_name) == 'b') &&
((flags & FormatFlags::ALTERNATE_FORM) != 0) && num != 0) {
prefix_len = 2;
prefix[0] = '0';
prefix[1] = a + ('b' - 'a');
} else {
prefix_len = (sign_char == 0 ? 0 : 1);
prefix[0] = sign_char;
Expand Down
4 changes: 4 additions & 0 deletions libc/src/stdio/printf_core/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ template <typename ArgProvider> class Parser {
case ('x'):
case ('X'):
case ('u'):
case ('b'):
case ('B'):
switch (lm) {
case (LengthModifier::hh):
case (LengthModifier::h):
Expand Down Expand Up @@ -484,6 +486,8 @@ template <typename ArgProvider> class Parser {
case ('x'):
case ('X'):
case ('u'):
case ('b'):
case ('B'):
switch (lm) {
case (LengthModifier::hh):
case (LengthModifier::h):
Expand Down
13 changes: 13 additions & 0 deletions libc/test/include/stdbit_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ unsigned stdc_trailing_zeros_us(unsigned short) noexcept { return 0xCBU; }
unsigned stdc_trailing_zeros_ui(unsigned) noexcept { return 0xCCU; }
unsigned stdc_trailing_zeros_ul(unsigned long) noexcept { return 0xCDU; }
unsigned stdc_trailing_zeros_ull(unsigned long long) noexcept { return 0xCFU; }
unsigned stdc_trailing_ones_uc(unsigned char) noexcept { return 0xDAU; }
unsigned stdc_trailing_ones_us(unsigned short) noexcept { return 0xDBU; }
unsigned stdc_trailing_ones_ui(unsigned) noexcept { return 0xDCU; }
unsigned stdc_trailing_ones_ul(unsigned long) noexcept { return 0xDDU; }
unsigned stdc_trailing_ones_ull(unsigned long long) noexcept { return 0xDFU; }
}

#include "include/llvm-libc-macros/stdbit-macros.h"
Expand Down Expand Up @@ -65,3 +70,11 @@ TEST(LlvmLibcStdbitTest, TypeGenericMacroTrailingZeros) {
EXPECT_EQ(stdc_trailing_zeros(0UL), 0xCDU);
EXPECT_EQ(stdc_trailing_zeros(0ULL), 0xCFU);
}

TEST(LlvmLibcStdbitTest, TypeGenericMacroTrailingOnes) {
EXPECT_EQ(stdc_trailing_ones(static_cast<unsigned char>(0U)), 0xDAU);
EXPECT_EQ(stdc_trailing_ones(static_cast<unsigned short>(0U)), 0xDBU);
EXPECT_EQ(stdc_trailing_ones(0U), 0xDCU);
EXPECT_EQ(stdc_trailing_ones(0UL), 0xDDU);
EXPECT_EQ(stdc_trailing_ones(0ULL), 0xDFU);
}
1 change: 1 addition & 0 deletions libc/test/src/stdbit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ set(prefixes
leading_zeros
leading_ones
trailing_zeros
trailing_ones
)
set(suffixes c s i l ll)
foreach(prefix IN LISTS prefixes)
Expand Down
21 changes: 21 additions & 0 deletions libc/test/src/stdbit/stdc_trailing_ones_uc_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===-- Unittests for stdc_trailing_ones_uc -------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/limits.h"
#include "src/stdbit/stdc_trailing_ones_uc.h"
#include "test/UnitTest/Test.h"

TEST(LlvmLibcStdcTrailingOnesUcTest, ALL) {
EXPECT_EQ(LIBC_NAMESPACE::stdc_trailing_ones_uc(UCHAR_MAX),
static_cast<unsigned>(UCHAR_WIDTH));
}

TEST(LlvmLibcStdcTrailingOnesUcTest, ZeroHot) {
for (unsigned i = 0U; i != UCHAR_WIDTH; ++i)
EXPECT_EQ(LIBC_NAMESPACE::stdc_trailing_ones_uc(~(1U << i)), i);
}
21 changes: 21 additions & 0 deletions libc/test/src/stdbit/stdc_trailing_ones_ui_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===-- Unittests for stdc_trailing_ones_ui -------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/limits.h"
#include "src/stdbit/stdc_trailing_ones_ui.h"
#include "test/UnitTest/Test.h"

TEST(LlvmLibcStdcTrailingOnesUiTest, ALL) {
EXPECT_EQ(LIBC_NAMESPACE::stdc_trailing_ones_ui(UINT_MAX),
static_cast<unsigned>(UINT_WIDTH));
}

TEST(LlvmLibcStdcTrailingOnesUiTest, ZeroHot) {
for (unsigned i = 0U; i != UINT_WIDTH; ++i)
EXPECT_EQ(LIBC_NAMESPACE::stdc_trailing_ones_ui(~(1U << i)), i);
}
21 changes: 21 additions & 0 deletions libc/test/src/stdbit/stdc_trailing_ones_ul_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===-- Unittests for stdc_trailing_ones_ul -------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/limits.h"
#include "src/stdbit/stdc_trailing_ones_ul.h"
#include "test/UnitTest/Test.h"

TEST(LlvmLibcStdcTrailingOnesUlTest, ALL) {
EXPECT_EQ(LIBC_NAMESPACE::stdc_trailing_ones_ul(ULONG_MAX),
static_cast<unsigned>(ULONG_WIDTH));
}

TEST(LlvmLibcStdcTrailingOnesUlTest, ZeroHot) {
for (unsigned i = 0U; i != ULONG_WIDTH; ++i)
EXPECT_EQ(LIBC_NAMESPACE::stdc_trailing_ones_ul(~(1UL << i)), i);
}
21 changes: 21 additions & 0 deletions libc/test/src/stdbit/stdc_trailing_ones_ull_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===-- Unittests for stdc_trailing_ones_ull ------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/limits.h"
#include "src/stdbit/stdc_trailing_ones_ull.h"
#include "test/UnitTest/Test.h"

TEST(LlvmLibcStdcTrailingOnesUllTest, ALL) {
EXPECT_EQ(LIBC_NAMESPACE::stdc_trailing_ones_ull(ULLONG_MAX),
static_cast<unsigned>(ULLONG_WIDTH));
}

TEST(LlvmLibcStdcTrailingOnesUllTest, ZeroHot) {
for (unsigned i = 0U; i != ULLONG_WIDTH; ++i)
EXPECT_EQ(LIBC_NAMESPACE::stdc_trailing_ones_ull(~(1ULL << i)), i);
}
21 changes: 21 additions & 0 deletions libc/test/src/stdbit/stdc_trailing_ones_us_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===-- Unittests for stdc_trailing_ones_us -------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/limits.h"
#include "src/stdbit/stdc_trailing_ones_us.h"
#include "test/UnitTest/Test.h"

TEST(LlvmLibcStdcTrailingOnesUsTest, ALL) {
EXPECT_EQ(LIBC_NAMESPACE::stdc_trailing_ones_us(USHRT_MAX),
static_cast<unsigned>(USHRT_WIDTH));
}

TEST(LlvmLibcStdcTrailingOnesUsTest, ZeroHot) {
for (unsigned i = 0U; i != USHRT_WIDTH; ++i)
EXPECT_EQ(LIBC_NAMESPACE::stdc_trailing_ones_us(~(1U << i)), i);
}
14 changes: 14 additions & 0 deletions libc/test/src/stdio/printf_core/converter_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,20 @@ TEST_F(LlvmLibcPrintfConverterTest, HexConversion) {
ASSERT_EQ(writer.get_chars_written(), 18);
}

TEST_F(LlvmLibcPrintfConverterTest, BinaryConversion) {
LIBC_NAMESPACE::printf_core::FormatSection section;
section.has_conv = true;
section.raw_string = "%b";
section.conv_name = 'b';
section.conv_val_raw = 42;
LIBC_NAMESPACE::printf_core::convert(&writer, section);

wb.buff[wb.buff_cur] = '\0';

ASSERT_STREQ(str, "101010");
ASSERT_EQ(writer.get_chars_written(), 6);
}

TEST_F(LlvmLibcPrintfConverterTest, PointerConversion) {

LIBC_NAMESPACE::printf_core::FormatSection section;
Expand Down
113 changes: 113 additions & 0 deletions libc/test/src/stdio/sprintf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,119 @@ TEST(LlvmLibcSPrintfTest, HexConv) {
ASSERT_STREQ(buff, "007F 0x1000000000 002 ");
}

TEST(LlvmLibcSPrintfTest, BinConv) {
char buff[64];
int written;

// Basic Tests.

written = LIBC_NAMESPACE::sprintf(buff, "%b", 42);
EXPECT_EQ(written, 6);
ASSERT_STREQ(buff, "101010");

written = LIBC_NAMESPACE::sprintf(buff, "%B", 12081991);
EXPECT_EQ(written, 24);
ASSERT_STREQ(buff, "101110000101101101000111");

// Min Width Tests.

written = LIBC_NAMESPACE::sprintf(buff, "%10b", 0b101010);
EXPECT_EQ(written, 10);
ASSERT_STREQ(buff, " 101010");

written = LIBC_NAMESPACE::sprintf(buff, "%2B", 0b101010);
EXPECT_EQ(written, 6);
ASSERT_STREQ(buff, "101010");

// Precision Tests.

written = LIBC_NAMESPACE::sprintf(buff, "%b", 0);
EXPECT_EQ(written, 1);
ASSERT_STREQ(buff, "0");

written = LIBC_NAMESPACE::sprintf(buff, "%.0b", 0);
EXPECT_EQ(written, 0);
ASSERT_STREQ(buff, "");

written = LIBC_NAMESPACE::sprintf(buff, "%.5b", 0b111);
EXPECT_EQ(written, 5);
ASSERT_STREQ(buff, "00111");

written = LIBC_NAMESPACE::sprintf(buff, "%.2b", 0b111);
EXPECT_EQ(written, 3);
ASSERT_STREQ(buff, "111");

written = LIBC_NAMESPACE::sprintf(buff, "%3b", 0b111);
EXPECT_EQ(written, 3);
ASSERT_STREQ(buff, "111");

// Flag Tests.

written = LIBC_NAMESPACE::sprintf(buff, "%-5b", 0b111);
EXPECT_EQ(written, 5);
ASSERT_STREQ(buff, "111 ");

written = LIBC_NAMESPACE::sprintf(buff, "%#b", 0b111);
EXPECT_EQ(written, 5);
ASSERT_STREQ(buff, "0b111");

written = LIBC_NAMESPACE::sprintf(buff, "%#b", 0);
EXPECT_EQ(written, 1);
ASSERT_STREQ(buff, "0");

written = LIBC_NAMESPACE::sprintf(buff, "%#B", 0b111);
EXPECT_EQ(written, 5);
ASSERT_STREQ(buff, "0B111");

written = LIBC_NAMESPACE::sprintf(buff, "%05b", 0b111);
EXPECT_EQ(written, 5);
ASSERT_STREQ(buff, "00111");

written = LIBC_NAMESPACE::sprintf(buff, "%0#6b", 0b111);
EXPECT_EQ(written, 6);
ASSERT_STREQ(buff, "0b0111");

written = LIBC_NAMESPACE::sprintf(buff, "%-#6b", 0b111);
EXPECT_EQ(written, 6);
ASSERT_STREQ(buff, "0b111 ");

// Combined Tests.

written = LIBC_NAMESPACE::sprintf(buff, "%#-07b", 0b111);
EXPECT_EQ(written, 7);
ASSERT_STREQ(buff, "0b111 ");

written = LIBC_NAMESPACE::sprintf(buff, "%7.5b", 0b111);
EXPECT_EQ(written, 7);
ASSERT_STREQ(buff, " 00111");

written = LIBC_NAMESPACE::sprintf(buff, "%#9.5B", 0b111);
EXPECT_EQ(written, 9);
ASSERT_STREQ(buff, " 0B00111");

written = LIBC_NAMESPACE::sprintf(buff, "%#.b", 0);
EXPECT_EQ(written, 0);
ASSERT_STREQ(buff, "");

written = LIBC_NAMESPACE::sprintf(buff, "%-7.5b", 0b111);
EXPECT_EQ(written, 7);
ASSERT_STREQ(buff, "00111 ");

written = LIBC_NAMESPACE::sprintf(buff, "%5.4b", 0b1111);
EXPECT_EQ(written, 5);
ASSERT_STREQ(buff, " 1111");

// Multiple Conversion Tests.

written = LIBC_NAMESPACE::sprintf(buff, "%10B %-#10b", 0b101, 0b110);
EXPECT_EQ(written, 21);
ASSERT_STREQ(buff, " 101 0b110 ");

written = LIBC_NAMESPACE::sprintf(buff, "%-5.4b%#.4b", 0b101, 0b110);
EXPECT_EQ(written, 11);
ASSERT_STREQ(buff, "0101 0b0110");
}

TEST(LlvmLibcSPrintfTest, PointerConv) {
char buff[64];
int written;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class small_iter_allocator {
public:
using value_type = T;
using pointer = small_pointer<T>;
using size_type = std::int16_t;
using size_type = std::uint16_t;
using difference_type = std::int16_t;

small_iter_allocator() TEST_NOEXCEPT {}
Expand All @@ -37,49 +37,77 @@ class small_iter_allocator {
friend bool operator!=(small_iter_allocator, small_iter_allocator) { return false; }
};

template <class T>
class final_small_iter_allocator final {
public:
using value_type = T;
using pointer = small_pointer<T>;
using size_type = std::uint16_t;
using difference_type = std::int16_t;

final_small_iter_allocator() TEST_NOEXCEPT {}

template <class U>
final_small_iter_allocator(final_small_iter_allocator<U>) TEST_NOEXCEPT {}

T* allocate(std::size_t n);
void deallocate(T* p, std::size_t);

friend bool operator==(final_small_iter_allocator, final_small_iter_allocator) { return true; }
friend bool operator!=(final_small_iter_allocator, final_small_iter_allocator) { return false; }
};

#if __SIZE_WIDTH__ == 64

static_assert(sizeof(std::deque<int>) == 48, "");
static_assert(sizeof(std::deque<int, min_allocator<int> >) == 48, "");
static_assert(sizeof(std::deque<int, test_allocator<int> >) == 80, "");
static_assert(sizeof(std::deque<int, small_iter_allocator<int> >) == 12, "");
static_assert(sizeof(std::deque<int, final_small_iter_allocator<int> >) == 16, "");

static_assert(sizeof(std::deque<char>) == 48, "");
static_assert(sizeof(std::deque<char, min_allocator<char> >) == 48, "");
static_assert(sizeof(std::deque<char, test_allocator<char> >) == 80, "");
static_assert(sizeof(std::deque<char, small_iter_allocator<char> >) == 12, "");
static_assert(sizeof(std::deque<char, final_small_iter_allocator<char> >) == 16, "");

static_assert(TEST_ALIGNOF(std::deque<int>) == 8, "");
static_assert(TEST_ALIGNOF(std::deque<int, min_allocator<int> >) == 8, "");
static_assert(TEST_ALIGNOF(std::deque<int, test_allocator<int> >) == 8, "");
static_assert(TEST_ALIGNOF(std::deque<int, small_iter_allocator<int> >) == 2, "");
static_assert(TEST_ALIGNOF(std::deque<int, final_small_iter_allocator<int> >) == 2, "");

static_assert(TEST_ALIGNOF(std::deque<char>) == 8, "");
static_assert(TEST_ALIGNOF(std::deque<char, min_allocator<char> >) == 8, "");
static_assert(TEST_ALIGNOF(std::deque<char, test_allocator<char> >) == 8, "");
static_assert(TEST_ALIGNOF(std::deque<char, small_iter_allocator<char> >) == 2, "");
static_assert(TEST_ALIGNOF(std::deque<char, final_small_iter_allocator<char> >) == 2, "");

#elif __SIZE_WIDTH__ == 32

static_assert(sizeof(std::deque<int>) == 24, "");
static_assert(sizeof(std::deque<int, min_allocator<int> >) == 24, "");
static_assert(sizeof(std::deque<int, test_allocator<int> >) == 48, "");
static_assert(sizeof(std::deque<int, small_iter_allocator<int> >) == 12, "");
static_assert(sizeof(std::deque<int, final_small_iter_allocator<int> >) == 16, "");

static_assert(sizeof(std::deque<char>) == 24, "");
static_assert(sizeof(std::deque<char, min_allocator<char> >) == 24, "");
static_assert(sizeof(std::deque<char, test_allocator<char> >) == 48, "");
static_assert(sizeof(std::deque<char, small_iter_allocator<char> >) == 12, "");
static_assert(sizeof(std::deque<char, final_small_iter_allocator<char> >) == 16, "");

static_assert(TEST_ALIGNOF(std::deque<int>) == 4, "");
static_assert(TEST_ALIGNOF(std::deque<int, min_allocator<int> >) == 4, "");
static_assert(TEST_ALIGNOF(std::deque<int, test_allocator<int> >) == 4, "");
static_assert(TEST_ALIGNOF(std::deque<int, small_iter_allocator<int> >) == 2, "");
static_assert(TEST_ALIGNOF(std::deque<int, final_small_iter_allocator<int> >) == 2, "");

static_assert(TEST_ALIGNOF(std::deque<char>) == 4, "");
static_assert(TEST_ALIGNOF(std::deque<char, min_allocator<char> >) == 4, "");
static_assert(TEST_ALIGNOF(std::deque<char, test_allocator<char> >) == 4, "");
static_assert(TEST_ALIGNOF(std::deque<char, small_iter_allocator<char> >) == 2, "");
static_assert(TEST_ALIGNOF(std::deque<char, final_small_iter_allocator<char> >) == 2, "");

#else
# error std::size_t has an unexpected size
Expand Down
86 changes: 86 additions & 0 deletions libcxx/test/libcxx/containers/sequences/list/abi.compile.pass.cpp
Original file line number Diff line number Diff line change
@@ -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
//
//===----------------------------------------------------------------------===//

#include <list>

#include "min_allocator.h"
#include "test_allocator.h"
#include "test_macros.h"

template <class T>
class small_pointer {
std::uint16_t offset;
};

template <class T>
class small_iter_allocator {
public:
using value_type = T;
using pointer = small_pointer<T>;
using size_type = std::int16_t;
using difference_type = std::int16_t;

small_iter_allocator() TEST_NOEXCEPT {}

template <class U>
small_iter_allocator(small_iter_allocator<U>) TEST_NOEXCEPT {}

T* allocate(std::size_t n);
void deallocate(T* p, std::size_t);

friend bool operator==(small_iter_allocator, small_iter_allocator) { return true; }
friend bool operator!=(small_iter_allocator, small_iter_allocator) { return false; }
};

#if __SIZE_WIDTH__ == 64

static_assert(sizeof(std::list<int>) == 24, "");
static_assert(sizeof(std::list<int, min_allocator<int> >) == 24, "");
static_assert(sizeof(std::list<int, test_allocator<int> >) == 40, "");
static_assert(sizeof(std::list<int, small_iter_allocator<int> >) == 6, "");

static_assert(sizeof(std::list<char>) == 24, "");
static_assert(sizeof(std::list<char, min_allocator<char> >) == 24, "");
static_assert(sizeof(std::list<char, test_allocator<char> >) == 40, "");
static_assert(sizeof(std::list<char, small_iter_allocator<char> >) == 6, "");

static_assert(TEST_ALIGNOF(std::list<int>) == 8, "");
static_assert(TEST_ALIGNOF(std::list<int, min_allocator<int> >) == 8, "");
static_assert(TEST_ALIGNOF(std::list<int, test_allocator<int> >) == 8, "");
static_assert(TEST_ALIGNOF(std::list<int, small_iter_allocator<int> >) == 2, "");

static_assert(TEST_ALIGNOF(std::list<char>) == 8, "");
static_assert(TEST_ALIGNOF(std::list<char, min_allocator<char> >) == 8, "");
static_assert(TEST_ALIGNOF(std::list<char, test_allocator<char> >) == 8, "");
static_assert(TEST_ALIGNOF(std::list<char, small_iter_allocator<char> >) == 2, "");

#elif __SIZE_WIDTH__ == 32

static_assert(sizeof(std::list<int>) == 12, "");
static_assert(sizeof(std::list<int, min_allocator<int> >) == 12, "");
static_assert(sizeof(std::list<int, test_allocator<int> >) == 24, "");
static_assert(sizeof(std::list<int, small_iter_allocator<int> >) == 6, "");

static_assert(sizeof(std::list<char>) == 12, "");
static_assert(sizeof(std::list<char, min_allocator<char> >) == 12, "");
static_assert(sizeof(std::list<char, test_allocator<char> >) == 24, "");
static_assert(sizeof(std::list<char, small_iter_allocator<char> >) == 6, "");

static_assert(TEST_ALIGNOF(std::list<int>) == 4, "");
static_assert(TEST_ALIGNOF(std::list<int, min_allocator<int> >) == 4, "");
static_assert(TEST_ALIGNOF(std::list<int, test_allocator<int> >) == 4, "");
static_assert(TEST_ALIGNOF(std::list<int, small_iter_allocator<int> >) == 2, "");

static_assert(TEST_ALIGNOF(std::list<char>) == 4, "");
static_assert(TEST_ALIGNOF(std::list<char, min_allocator<char> >) == 4, "");
static_assert(TEST_ALIGNOF(std::list<char, test_allocator<char> >) == 4, "");
static_assert(TEST_ALIGNOF(std::list<char, small_iter_allocator<char> >) == 2, "");

#else
# error std::size_t has an unexpected size
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//===----------------------------------------------------------------------===//
//
// 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 <vector>

#include "min_allocator.h"
#include "test_allocator.h"
#include "test_macros.h"

template <class T>
class small_pointer {
std::uint16_t offset;
};

template <class T>
class small_iter_allocator {
public:
using value_type = T;
using pointer = small_pointer<T>;
using size_type = std::int16_t;
using difference_type = std::int16_t;

small_iter_allocator() TEST_NOEXCEPT {}

template <class U>
small_iter_allocator(small_iter_allocator<U>) TEST_NOEXCEPT {}

T* allocate(std::size_t n);
void deallocate(T* p, std::size_t);

friend bool operator==(small_iter_allocator, small_iter_allocator) { return true; }
friend bool operator!=(small_iter_allocator, small_iter_allocator) { return false; }
};

#if __SIZE_WIDTH__ == 64

static_assert(sizeof(std::vector<bool>) == 24, "");
static_assert(sizeof(std::vector<bool, min_allocator<bool> >) == 24, "");
static_assert(sizeof(std::vector<bool, test_allocator<bool> >) == 40, "");
static_assert(sizeof(std::vector<bool, small_iter_allocator<bool> >) == 6, "");

static_assert(TEST_ALIGNOF(std::vector<bool>) == 8, "");
static_assert(TEST_ALIGNOF(std::vector<bool, min_allocator<bool> >) == 8, "");
static_assert(TEST_ALIGNOF(std::vector<bool, test_allocator<bool> >) == 8, "");
static_assert(TEST_ALIGNOF(std::vector<bool, small_iter_allocator<bool> >) == 2, "");

#elif __SIZE_WIDTH__ == 32

static_assert(sizeof(std::vector<bool>) == 12, "");
static_assert(sizeof(std::vector<bool, min_allocator<bool> >) == 12, "");
static_assert(sizeof(std::vector<bool, test_allocator<bool> >) == 24, "");
static_assert(sizeof(std::vector<bool, small_iter_allocator<bool> >) == 6, "");

static_assert(TEST_ALIGNOF(std::vector<bool>) == 4, "");
static_assert(TEST_ALIGNOF(std::vector<bool, min_allocator<bool> >) == 4, "");
static_assert(TEST_ALIGNOF(std::vector<bool, test_allocator<bool> >) == 4, "");
static_assert(TEST_ALIGNOF(std::vector<bool, small_iter_allocator<bool> >) == 2, "");

#else
# error std::size_t has an unexpected size
#endif
Original file line number Diff line number Diff line change
@@ -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
//
//===----------------------------------------------------------------------===//

#include <vector>

#include "min_allocator.h"
#include "test_allocator.h"
#include "test_macros.h"

template <class T>
class small_pointer {
std::uint16_t offset;
};

template <class T>
class small_iter_allocator {
public:
using value_type = T;
using pointer = small_pointer<T>;
using size_type = std::int16_t;
using difference_type = std::int16_t;

small_iter_allocator() TEST_NOEXCEPT {}

template <class U>
small_iter_allocator(small_iter_allocator<U>) TEST_NOEXCEPT {}

T* allocate(std::size_t n);
void deallocate(T* p, std::size_t);

friend bool operator==(small_iter_allocator, small_iter_allocator) { return true; }
friend bool operator!=(small_iter_allocator, small_iter_allocator) { return false; }
};

#if __SIZE_WIDTH__ == 64

static_assert(sizeof(std::vector<int>) == 24, "");
static_assert(sizeof(std::vector<int, min_allocator<int> >) == 24, "");
static_assert(sizeof(std::vector<int, test_allocator<int> >) == 40, "");
static_assert(sizeof(std::vector<int, small_iter_allocator<int> >) == 6, "");

static_assert(sizeof(std::vector<char>) == 24, "");
static_assert(sizeof(std::vector<char, min_allocator<char> >) == 24, "");
static_assert(sizeof(std::vector<char, test_allocator<char> >) == 40, "");
static_assert(sizeof(std::vector<char, small_iter_allocator<char> >) == 6, "");

static_assert(TEST_ALIGNOF(std::vector<int>) == 8, "");
static_assert(TEST_ALIGNOF(std::vector<int, min_allocator<int> >) == 8, "");
static_assert(TEST_ALIGNOF(std::vector<int, test_allocator<int> >) == 8, "");
static_assert(TEST_ALIGNOF(std::vector<int, small_iter_allocator<int> >) == 2, "");

static_assert(TEST_ALIGNOF(std::vector<char>) == 8, "");
static_assert(TEST_ALIGNOF(std::vector<char, min_allocator<char> >) == 8, "");
static_assert(TEST_ALIGNOF(std::vector<char, test_allocator<char> >) == 8, "");
static_assert(TEST_ALIGNOF(std::vector<char, small_iter_allocator<char> >) == 2, "");

#elif __SIZE_WIDTH__ == 32

static_assert(sizeof(std::vector<int>) == 12, "");
static_assert(sizeof(std::vector<int, min_allocator<int> >) == 12, "");
static_assert(sizeof(std::vector<int, test_allocator<int> >) == 24, "");
static_assert(sizeof(std::vector<int, small_iter_allocator<int> >) == 6, "");

static_assert(sizeof(std::vector<char>) == 12, "");
static_assert(sizeof(std::vector<char, min_allocator<char> >) == 12, "");
static_assert(sizeof(std::vector<char, test_allocator<char> >) == 24, "");
static_assert(sizeof(std::vector<char, small_iter_allocator<char> >) == 6, "");

static_assert(TEST_ALIGNOF(std::vector<int>) == 4, "");
static_assert(TEST_ALIGNOF(std::vector<int, min_allocator<int> >) == 4, "");
static_assert(TEST_ALIGNOF(std::vector<int, test_allocator<int> >) == 4, "");
static_assert(TEST_ALIGNOF(std::vector<int, small_iter_allocator<int> >) == 2, "");

static_assert(TEST_ALIGNOF(std::vector<char>) == 4, "");
static_assert(TEST_ALIGNOF(std::vector<char, min_allocator<char> >) == 4, "");
static_assert(TEST_ALIGNOF(std::vector<char, test_allocator<char> >) == 4, "");
static_assert(TEST_ALIGNOF(std::vector<char, small_iter_allocator<char> >) == 2, "");

#else
# error std::size_t has an unexpected size
#endif
12 changes: 6 additions & 6 deletions lld/test/wasm/build-id.test
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,18 @@ foo:


# DEFAULT: Contents of section build_id:
# DEFAULT-NEXT: 0000 10299168 1e3c845a 3c8f80ae 2f16cc22 .).h.<.Z<.../.."
# DEFAULT-NEXT: 0010 2d
# DEFAULT-NEXT: 0079 10299168 1e3c845a 3c8f80ae 2f16cc22 .).h.<.Z<.../.."
# DEFAULT-NEXT: 0089 2d

# SHA1: Contents of section build_id:
# SHA1-NEXT: 0000 145abdda 387a9bc4 e3aed3c3 3319cd37 .Z..8z......3..7
# SHA1-NEXT: 0010 0212237c e4 ..#|.
# SHA1-NEXT: 0079 145abdda 387a9bc4 e3aed3c3 3319cd37 .Z..8z......3..7
# SHA1-NEXT: 0089 0212237c e4 ..#|.

# UUID: Contents of section build_id:
# UUID-NEXT: 0000 10
# UUID-NEXT: 0079 10

# HEX: Contents of section build_id:
# HEX-NEXT: 0000 04123456 78 ..4Vx
# HEX-NEXT: 0079 04123456 78 ..4Vx


# NONE-NOT: Contents of section build_id:
14 changes: 7 additions & 7 deletions lld/test/wasm/merge-string-debug.s
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@

# CHECK: Hex dump of section '.debug_str':

# CHECK-O0: 0x00000000 636c616e 67207665 7273696f 6e203133 clang version 13
# CHECK-O0: 0x00000010 2e302e30 00666f6f 62617200 636c616e .0.0.foobar.clan
# CHECK-O0: 0x00000020 67207665 7273696f 6e203133 2e302e30 g version 13.0.0
# CHECK-O0: 0x00000030 00626172 00666f6f 00 .bar.foo.
# CHECK-O0: 0x00000025 636c616e 67207665 7273696f 6e203133 clang version 13
# CHECK-O0: 0x00000035 2e302e30 00666f6f 62617200 636c616e .0.0.foobar.clan
# CHECK-O0: 0x00000045 67207665 7273696f 6e203133 2e302e30 g version 13.0.0
# CHECK-O0: 0x00000055 00626172 00666f6f 00 .bar.foo.

# CHECK-O1: 0x00000000 666f6f62 61720066 6f6f0063 6c616e67 foobar.foo.clang
# CHECK-O1: 0x00000010 20766572 73696f6e 2031332e 302e3000 version 13.0.0.
# CHECK-O1: 0x00000025 666f6f62 61720066 6f6f0063 6c616e67 foobar.foo.clang
# CHECK-O1: 0x00000035 20766572 73696f6e 2031332e 302e3000 version 13.0.0.

# CHECK-OFFSETS: Hex dump of section '.debug_str_offsets':
# CHECK-OFFSETS: 0x00000000 00000000 00000000 00000000 ............
# CHECK-OFFSETS: 0x0000007e 00000000 00000000 00000000 ............
12 changes: 6 additions & 6 deletions lld/test/wasm/startstop.ll
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ entry:
; CHECK-NEXT: Value: 1024
; CHECK-NEXT: Content: 03000000040000002A0000002B000000

; ASM: 00000001 <get_start>:
; ASM: 0000006e <get_start>:
; ASM-EMPTY:
; ASM-NEXT: 3: i32.const 1024
; ASM-NEXT: 9: end
; ASM-NEXT: 70: i32.const 1024
; ASM-NEXT: 76: end

; ASM: 0000000a <get_end>:
; ASM: 00000077 <get_end>:
; ASM-EMPTY:
; ASM-NEXT: c: i32.const 1040
; ASM-NEXT: 12: end
; ASM-NEXT: 79: i32.const 1040
; ASM-NEXT: 7f: end
1 change: 1 addition & 0 deletions lldb/bindings/headers.swig
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#include "lldb/API/SBScriptObject.h"
#include "lldb/API/SBSection.h"
#include "lldb/API/SBSourceManager.h"
#include "lldb/API/SBStatisticsOptions.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBStringList.h"
#include "lldb/API/SBStructuredData.h"
Expand Down
8 changes: 8 additions & 0 deletions lldb/bindings/interface/SBStatisticsOptionsDocstrings.i
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
%feature("docstring",
"A container for options to use when dumping statistics."
) lldb::SBStatisticsOptions;

%feature("docstring", "Sets whether the statistics should only dump a summary."
) lldb::SBStatisticsOptions::SetSummaryOnly;
%feature("docstring", "Gets whether the statistics only dump a summary."
) lldb::SBStatisticsOptions::GetSummaryOnly;
2 changes: 2 additions & 0 deletions lldb/bindings/interfaces.swig
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
%include "./interface/SBReproducerDocstrings.i"
%include "./interface/SBSectionDocstrings.i"
%include "./interface/SBSourceManagerDocstrings.i"
%include "./interface/SBStatisticsOptionsDocstrings.i"
%include "./interface/SBStreamDocstrings.i"
%include "./interface/SBStringListDocstrings.i"
%include "./interface/SBStructuredDataDocstrings.i"
Expand Down Expand Up @@ -131,6 +132,7 @@
%include "lldb/API/SBScriptObject.h"
%include "lldb/API/SBSection.h"
%include "lldb/API/SBSourceManager.h"
%include "lldb/API/SBStatisticsOptions.h"
%include "lldb/API/SBStream.h"
%include "lldb/API/SBStringList.h"
%include "lldb/API/SBStructuredData.h"
Expand Down
1 change: 1 addition & 0 deletions lldb/include/lldb/API/LLDB.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include "lldb/API/SBReproducer.h"
#include "lldb/API/SBSection.h"
#include "lldb/API/SBSourceManager.h"
#include "lldb/API/SBStatisticsOptions.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBStringList.h"
#include "lldb/API/SBStructuredData.h"
Expand Down
1 change: 1 addition & 0 deletions lldb/include/lldb/API/SBDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ class LLDB_API SBReproducer;
class LLDB_API SBScriptObject;
class LLDB_API SBSection;
class LLDB_API SBSourceManager;
class LLDB_API SBStatisticsOptions;
class LLDB_API SBStream;
class LLDB_API SBStringList;
class LLDB_API SBStructuredData;
Expand Down
36 changes: 36 additions & 0 deletions lldb/include/lldb/API/SBStatisticsOptions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===-- SBStatisticsOptions.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_SBSTATISTICSOPTIONS_H
#define LLDB_API_SBSTATISTICSOPTIONS_H

#include "lldb/API/SBDefines.h"

namespace lldb {

/// This class handles the verbosity when dumping statistics
class LLDB_API SBStatisticsOptions {
public:
SBStatisticsOptions();
SBStatisticsOptions(const lldb::SBStatisticsOptions &rhs);
~SBStatisticsOptions();

const SBStatisticsOptions &operator=(const lldb::SBStatisticsOptions &rhs);

void SetSummaryOnly(bool b);
bool GetSummaryOnly();

protected:
friend class SBTarget;
const lldb_private::StatisticsOptions &ref() const;

private:
std::unique_ptr<lldb_private::StatisticsOptions> m_opaque_up;
};
} // namespace lldb
#endif // LLDB_API_SBSTATISTICSOPTIONS_H
10 changes: 10 additions & 0 deletions lldb/include/lldb/API/SBTarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "lldb/API/SBFileSpec.h"
#include "lldb/API/SBFileSpecList.h"
#include "lldb/API/SBLaunchInfo.h"
#include "lldb/API/SBStatisticsOptions.h"
#include "lldb/API/SBSymbolContextList.h"
#include "lldb/API/SBType.h"
#include "lldb/API/SBValue.h"
Expand Down Expand Up @@ -90,6 +91,15 @@ class LLDB_API SBTarget {
/// A SBStructuredData with the statistics collected.
lldb::SBStructuredData GetStatistics();

/// Returns a dump of the collected statistics.
///
/// \param[in] options
/// An objects object that contains all options for the statistics dumping.
///
/// \return
/// A SBStructuredData with the statistics collected.
lldb::SBStructuredData GetStatistics(SBStatisticsOptions options);

/// Return the platform object associated with the target.
///
/// After return, the platform object should be checked for
Expand Down
15 changes: 13 additions & 2 deletions lldb/include/lldb/Target/Statistics.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,15 @@ struct ConstStringStats {
ConstString::MemoryStats stats = ConstString::GetMemoryStats();
};

struct StatisticsOptions {
bool summary_only = false;
};

/// A class that represents statistics for a since lldb_private::Target.
class TargetStats {
public:
llvm::json::Value ToJSON(Target &target);
llvm::json::Value ToJSON(Target &target,
const lldb_private::StatisticsOptions &options);

void SetLaunchOrAttachTime();
void SetFirstPrivateStopTime();
Expand Down Expand Up @@ -171,9 +176,15 @@ class DebuggerStats {
/// The single target to emit statistics for if non NULL, otherwise dump
/// statistics only for the specified target.
///
/// \param summary_only
/// If true, only report high level summary statistics without
/// targets/modules/breakpoints etc.. details.
///
/// \return
/// Returns a JSON value that contains all target metrics.
static llvm::json::Value ReportStatistics(Debugger &debugger, Target *target);
static llvm::json::Value
ReportStatistics(Debugger &debugger, Target *target,
const lldb_private::StatisticsOptions &options);

protected:
// Collecting stats can be set to true to collect stats that are expensive
Expand Down
3 changes: 2 additions & 1 deletion lldb/include/lldb/Target/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -1599,7 +1599,8 @@ class Target : public std::enable_shared_from_this<Target>,
///
/// \return
/// Returns a JSON value that contains all target metrics.
llvm::json::Value ReportStatistics();
llvm::json::Value
ReportStatistics(const lldb_private::StatisticsOptions &options);

TargetStats &GetStatistics() { return m_stats; }

Expand Down
1 change: 1 addition & 0 deletions lldb/include/lldb/lldb-forward.h
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ struct CompilerContext;
struct LineEntry;
struct PropertyDefinition;
struct ScriptSummaryFormat;
struct StatisticsOptions;
struct StringSummaryFormat;
template <unsigned N> class StreamBuffer;

Expand Down
1 change: 1 addition & 0 deletions lldb/source/API/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ add_lldb_library(liblldb SHARED ${option_framework}
SBScriptObject.cpp
SBSection.cpp
SBSourceManager.cpp
SBStatisticsOptions.cpp
SBStream.cpp
SBStringList.cpp
SBStructuredData.cpp
Expand Down
49 changes: 49 additions & 0 deletions lldb/source/API/SBStatisticsOptions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//===-- SBStatisticsOptions.cpp -------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "lldb/API/SBStatisticsOptions.h"
#include "lldb/Target/Statistics.h"
#include "lldb/Utility/Instrumentation.h"

#include "Utils.h"

using namespace lldb;
using namespace lldb_private;

SBStatisticsOptions::SBStatisticsOptions()
: m_opaque_up(new StatisticsOptions()) {
LLDB_INSTRUMENT_VA(this);
m_opaque_up->summary_only = false;
}

SBStatisticsOptions::SBStatisticsOptions(const SBStatisticsOptions &rhs) {
LLDB_INSTRUMENT_VA(this, rhs);

m_opaque_up = clone(rhs.m_opaque_up);
}

SBStatisticsOptions::~SBStatisticsOptions() = default;

const SBStatisticsOptions &
SBStatisticsOptions::operator=(const SBStatisticsOptions &rhs) {
LLDB_INSTRUMENT_VA(this, rhs);

if (this != &rhs)
m_opaque_up = clone(rhs.m_opaque_up);
return *this;
}

void SBStatisticsOptions::SetSummaryOnly(bool b) {
m_opaque_up->summary_only = b;
}

bool SBStatisticsOptions::GetSummaryOnly() { return m_opaque_up->summary_only; }

const lldb_private::StatisticsOptions &SBStatisticsOptions::ref() const {
return *m_opaque_up;
}
13 changes: 10 additions & 3 deletions lldb/source/API/SBTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,15 +199,22 @@ SBDebugger SBTarget::GetDebugger() const {

SBStructuredData SBTarget::GetStatistics() {
LLDB_INSTRUMENT_VA(this);
SBStatisticsOptions options;
return GetStatistics(options);
}

SBStructuredData SBTarget::GetStatistics(SBStatisticsOptions options) {
LLDB_INSTRUMENT_VA(this);

SBStructuredData data;
TargetSP target_sp(GetSP());
if (!target_sp)
return data;
std::string json_str =
llvm::formatv("{0:2}",
DebuggerStats::ReportStatistics(target_sp->GetDebugger(),
target_sp.get())).str();
llvm::formatv("{0:2}", DebuggerStats::ReportStatistics(
target_sp->GetDebugger(), target_sp.get(),
options.ref()))
.str();
data.m_impl_up->SetObjectSP(StructuredData::ParseJSON(json_str));
return data;
}
Expand Down
10 changes: 9 additions & 1 deletion lldb/source/Commands/CommandObjectStats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ class CommandObjectStatsDump : public CommandObjectParsed {
case 'a':
m_all_targets = true;
break;
case 's':
m_stats_options.summary_only = true;
break;
default:
llvm_unreachable("Unimplemented option");
}
Expand All @@ -83,13 +86,17 @@ class CommandObjectStatsDump : public CommandObjectParsed {

void OptionParsingStarting(ExecutionContext *execution_context) override {
m_all_targets = false;
m_stats_options = StatisticsOptions();
}

llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
return llvm::ArrayRef(g_statistics_dump_options);
}

const StatisticsOptions &GetStatisticsOptions() { return m_stats_options; }

bool m_all_targets = false;
StatisticsOptions m_stats_options = StatisticsOptions();
};

public:
Expand All @@ -109,7 +116,8 @@ class CommandObjectStatsDump : public CommandObjectParsed {
target = m_exe_ctx.GetTargetPtr();

result.AppendMessageWithFormatv(
"{0:2}", DebuggerStats::ReportStatistics(GetDebugger(), target));
"{0:2}", DebuggerStats::ReportStatistics(
GetDebugger(), target, m_options.GetStatisticsOptions()));
result.SetStatus(eReturnStatusSuccessFinishResult);
}

Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Commands/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1412,4 +1412,7 @@ let Command = "trace schema" in {
let Command = "statistics dump" in {
def statistics_dump_all: Option<"all-targets", "a">, Group<1>,
Desc<"Include statistics for all targets.">;
def statistics_dump_summary: Option<"summary", "s">, Group<1>,
Desc<"Dump only high-level summary statistics."
"Exclude targets, modules, breakpoints etc... details.">;
}
200 changes: 123 additions & 77 deletions lldb/source/Target/Statistics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "lldb/Core/Module.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/UnixSignals.h"
Expand Down Expand Up @@ -100,60 +101,94 @@ llvm::json::Value ConstStringStats::ToJSON() const {
return obj;
}

json::Value TargetStats::ToJSON(Target &target) {
CollectStats(target);
json::Value
TargetStats::ToJSON(Target &target,
const lldb_private::StatisticsOptions &options) {
json::Object target_metrics_json;
ProcessSP process_sp = target.GetProcessSP();
const bool summary_only = options.summary_only;
if (!summary_only) {
CollectStats(target);

json::Array json_module_uuid_array;
for (auto module_identifier : m_module_identifiers)
json_module_uuid_array.emplace_back(module_identifier);
json::Array json_module_uuid_array;
for (auto module_identifier : m_module_identifiers)
json_module_uuid_array.emplace_back(module_identifier);

json::Object target_metrics_json{
{m_expr_eval.name, m_expr_eval.ToJSON()},
{m_frame_var.name, m_frame_var.ToJSON()},
{"moduleIdentifiers", std::move(json_module_uuid_array)}};
target_metrics_json.try_emplace(m_expr_eval.name, m_expr_eval.ToJSON());
target_metrics_json.try_emplace(m_frame_var.name, m_frame_var.ToJSON());
target_metrics_json.try_emplace("moduleIdentifiers",
std::move(json_module_uuid_array));

if (m_launch_or_attach_time && m_first_private_stop_time) {
double elapsed_time =
elapsed(*m_launch_or_attach_time, *m_first_private_stop_time);
target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time);
}
if (m_launch_or_attach_time && m_first_public_stop_time) {
double elapsed_time =
elapsed(*m_launch_or_attach_time, *m_first_public_stop_time);
target_metrics_json.try_emplace("firstStopTime", elapsed_time);
if (m_launch_or_attach_time && m_first_private_stop_time) {
double elapsed_time =
elapsed(*m_launch_or_attach_time, *m_first_private_stop_time);
target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time);
}
if (m_launch_or_attach_time && m_first_public_stop_time) {
double elapsed_time =
elapsed(*m_launch_or_attach_time, *m_first_public_stop_time);
target_metrics_json.try_emplace("firstStopTime", elapsed_time);
}
target_metrics_json.try_emplace("targetCreateTime",
m_create_time.get().count());

json::Array breakpoints_array;
double totalBreakpointResolveTime = 0.0;
// Report both the normal breakpoint list and the internal breakpoint list.
for (int i = 0; i < 2; ++i) {
BreakpointList &breakpoints = target.GetBreakpointList(i == 1);
std::unique_lock<std::recursive_mutex> lock;
breakpoints.GetListMutex(lock);
size_t num_breakpoints = breakpoints.GetSize();
for (size_t i = 0; i < num_breakpoints; i++) {
Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
breakpoints_array.push_back(bp->GetStatistics());
totalBreakpointResolveTime += bp->GetResolveTime().count();
}
}
target_metrics_json.try_emplace("breakpoints",
std::move(breakpoints_array));
target_metrics_json.try_emplace("totalBreakpointResolveTime",
totalBreakpointResolveTime);

if (process_sp) {
UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals();
if (unix_signals_sp)
target_metrics_json.try_emplace(
"signals", unix_signals_sp->GetHitCountStatistics());
}
}
target_metrics_json.try_emplace("targetCreateTime",
m_create_time.get().count());

json::Array breakpoints_array;
double totalBreakpointResolveTime = 0.0;
// Rport both the normal breakpoint list and the internal breakpoint list.
for (int i = 0; i < 2; ++i) {
BreakpointList &breakpoints = target.GetBreakpointList(i == 1);

// Counting "totalSharedLibraryEventHitCount" from breakpoints of kind
// "shared-library-event".
{
uint32_t shared_library_event_breakpoint_hit_count = 0;
// The "shared-library-event" is only found in the internal breakpoint list.
BreakpointList &breakpoints = target.GetBreakpointList(/* internal */ true);
std::unique_lock<std::recursive_mutex> lock;
breakpoints.GetListMutex(lock);
size_t num_breakpoints = breakpoints.GetSize();
for (size_t i = 0; i < num_breakpoints; i++) {
Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
breakpoints_array.push_back(bp->GetStatistics());
totalBreakpointResolveTime += bp->GetResolveTime().count();
if (strcmp(bp->GetBreakpointKind(), "shared-library-event") == 0)
shared_library_event_breakpoint_hit_count += bp->GetHitCount();
}

target_metrics_json.try_emplace("totalSharedLibraryEventHitCount",
shared_library_event_breakpoint_hit_count);
}

ProcessSP process_sp = target.GetProcessSP();
if (process_sp) {
UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals();
if (unix_signals_sp)
target_metrics_json.try_emplace("signals",
unix_signals_sp->GetHitCountStatistics());
uint32_t stop_id = process_sp->GetStopID();
target_metrics_json.try_emplace("stopCount", stop_id);
}
target_metrics_json.try_emplace("breakpoints", std::move(breakpoints_array));
target_metrics_json.try_emplace("totalBreakpointResolveTime",
totalBreakpointResolveTime);
target_metrics_json.try_emplace("sourceMapDeduceCount", m_source_map_deduce_count);

llvm::StringRef dyld_plugin_name;
if (process_sp->GetDynamicLoader())
dyld_plugin_name = process_sp->GetDynamicLoader()->GetPluginName();
target_metrics_json.try_emplace("dyldPluginName", dyld_plugin_name);
}
target_metrics_json.try_emplace("sourceMapDeduceCount",
m_source_map_deduce_count);
return target_metrics_json;
}

Expand Down Expand Up @@ -184,8 +219,12 @@ void TargetStats::IncreaseSourceMapDeduceCount() {

bool DebuggerStats::g_collecting_stats = false;

llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger,
Target *target) {
llvm::json::Value DebuggerStats::ReportStatistics(
Debugger &debugger, Target *target,
const lldb_private::StatisticsOptions &options) {

const bool summary_only = options.summary_only;

json::Array json_targets;
json::Array json_modules;
double symtab_parse_time = 0.0;
Expand All @@ -197,12 +236,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger,
uint32_t debug_index_loaded = 0;
uint32_t debug_index_saved = 0;
uint64_t debug_info_size = 0;
if (target) {
json_targets.emplace_back(target->ReportStatistics());
} else {
for (const auto &target : debugger.GetTargetList().Targets())
json_targets.emplace_back(target->ReportStatistics());
}

std::vector<ModuleStats> modules;
std::lock_guard<std::recursive_mutex> guard(
Module::GetAllocationModuleCollectionMutex());
Expand All @@ -215,15 +249,6 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger,
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
Module *module = Module::GetAllocatedModuleAtIndex(image_idx);
ModuleStats module_stat;
module_stat.identifier = (intptr_t)module;
module_stat.path = module->GetFileSpec().GetPath();
if (ConstString object_name = module->GetObjectName()) {
module_stat.path.append(1, '(');
module_stat.path.append(object_name.GetStringRef().str());
module_stat.path.append(1, ')');
}
module_stat.uuid = module->GetUUID().GetAsString();
module_stat.triple = module->GetArchitecture().GetTriple().str();
module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count();
module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count();
Symtab *symtab = module->GetSymtab();
Expand All @@ -237,13 +262,14 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger,
}
SymbolFile *sym_file = module->GetSymbolFile();
if (sym_file) {

if (sym_file->GetObjectFile() != module->GetObjectFile())
module_stat.symfile_path =
sym_file->GetObjectFile()->GetFileSpec().GetPath();
module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count();
module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count();
module_stat.debug_info_size = sym_file->GetDebugInfoSize();
if (!summary_only) {
if (sym_file->GetObjectFile() != module->GetObjectFile())
module_stat.symfile_path =
sym_file->GetObjectFile()->GetFileSpec().GetPath();
ModuleList symbol_modules = sym_file->GetDebugInfoModules();
for (const auto &symbol_module : symbol_modules.Modules())
module_stat.symfile_modules.push_back((intptr_t)symbol_module.get());
}
module_stat.debug_info_index_loaded_from_cache =
sym_file->GetDebugInfoIndexWasLoadedFromCache();
if (module_stat.debug_info_index_loaded_from_cache)
Expand All @@ -252,9 +278,9 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger,
sym_file->GetDebugInfoIndexWasSavedToCache();
if (module_stat.debug_info_index_saved_to_cache)
++debug_index_saved;
ModuleList symbol_modules = sym_file->GetDebugInfoModules();
for (const auto &symbol_module: symbol_modules.Modules())
module_stat.symfile_modules.push_back((intptr_t)symbol_module.get());
module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count();
module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count();
module_stat.debug_info_size = sym_file->GetDebugInfoSize();
module_stat.symtab_stripped = module->GetObjectFile()->IsStripped();
if (module_stat.symtab_stripped)
++num_stripped_modules;
Expand Down Expand Up @@ -284,21 +310,21 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger,
if (module_stat.debug_info_had_incomplete_types)
++num_modules_with_incomplete_types;

json_modules.emplace_back(module_stat.ToJSON());
if (!summary_only) {
module_stat.identifier = (intptr_t)module;
module_stat.path = module->GetFileSpec().GetPath();
if (ConstString object_name = module->GetObjectName()) {
module_stat.path.append(1, '(');
module_stat.path.append(object_name.GetStringRef().str());
module_stat.path.append(1, ')');
}
module_stat.uuid = module->GetUUID().GetAsString();
module_stat.triple = module->GetArchitecture().GetTriple().str();
json_modules.emplace_back(module_stat.ToJSON());
}
}

ConstStringStats const_string_stats;
json::Object json_memory{
{"strings", const_string_stats.ToJSON()},
};

json::Value cmd_stats = debugger.GetCommandInterpreter().GetStatistics();

json::Object global_stats{
{"targets", std::move(json_targets)},
{"modules", std::move(json_modules)},
{"memory", std::move(json_memory)},
{"commands", std::move(cmd_stats)},
{"totalSymbolTableParseTime", symtab_parse_time},
{"totalSymbolTableIndexTime", symtab_index_time},
{"totalSymbolTablesLoadedFromCache", symtabs_loaded},
Expand All @@ -316,5 +342,25 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger,
{"totalDebugInfoEnabled", num_debug_info_enabled_modules},
{"totalSymbolTableStripped", num_stripped_modules},
};

if (target) {
json_targets.emplace_back(target->ReportStatistics(options));
} else {
for (const auto &target : debugger.GetTargetList().Targets())
json_targets.emplace_back(target->ReportStatistics(options));
}
global_stats.try_emplace("targets", std::move(json_targets));

if (!summary_only) {
ConstStringStats const_string_stats;
json::Object json_memory{
{"strings", const_string_stats.ToJSON()},
};
json::Value cmd_stats = debugger.GetCommandInterpreter().GetStatistics();
global_stats.try_emplace("modules", std::move(json_modules));
global_stats.try_emplace("memory", std::move(json_memory));
global_stats.try_emplace("commands", std::move(cmd_stats));
}

return std::move(global_stats);
}
5 changes: 4 additions & 1 deletion lldb/source/Target/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4962,4 +4962,7 @@ std::recursive_mutex &Target::GetAPIMutex() {
}

/// Get metrics associated with this target in JSON format.
llvm::json::Value Target::ReportStatistics() { return m_stats.ToJSON(*this); }
llvm::json::Value
Target::ReportStatistics(const lldb_private::StatisticsOptions &options) {
return m_stats.ToJSON(*this, options);
}
23 changes: 22 additions & 1 deletion lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ def test_stats_api(self):
"""
self.build()
exe = self.getBuildArtifact("a.out")
target = self.dbg.CreateTarget(exe)
# Launch a process and break
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "break here", lldb.SBFileSpec("main.c")
)

# Test enabling/disabling stats
self.assertFalse(target.GetCollectingStats())
Expand Down Expand Up @@ -74,6 +77,24 @@ def test_stats_api(self):
'Make sure the "failures" key in in "frameVariable" dictionary"',
)

# Test statistics summary.
stats_options = lldb.SBStatisticsOptions()
stats_options.SetSummaryOnly(True)
stats_summary = target.GetStatistics(stats_options)
stream_summary = lldb.SBStream()
stats_summary.GetAsJSON(stream_summary)
debug_stats_summary = json.loads(stream_summary.GetData())
self.assertNotIn("modules", debug_stats_summary)
self.assertNotIn("memory", debug_stats_summary)
self.assertNotIn("commands", debug_stats_summary)

# Summary values should be the same as in full statistics.
# Except the parse time on Mac OS X is not deterministic.
for key, value in debug_stats_summary.items():
self.assertIn(key, debug_stats)
if key != "targets" and not key.endswith("Time"):
self.assertEqual(debug_stats[key], value)

def test_command_stats_api(self):
"""
Test GetCommandInterpreter::GetStatistics() API.
Expand Down
2 changes: 1 addition & 1 deletion lldb/test/API/functionalities/stats_api/main.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
int main(void) {
return 0;
return 0; // break here
}
5 changes: 5 additions & 0 deletions llvm/docs/CommandGuide/llvm-objcopy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ multiple file formats.
If specified, symbol and section names specified by other switches are treated
as extended POSIX regular expression patterns.

.. option:: --remove-symbol-prefix <prefix>

Remove ``<prefix>`` from the start of every symbol name. No-op for symbols that do
not start with ``<prefix>``.

.. option:: --remove-section <section>, -R

Remove the specified section from the output. Can be specified multiple times
Expand Down
60 changes: 16 additions & 44 deletions llvm/docs/Passes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ LLVM's Analysis and Transform Passes

Introduction
============
.. warning:: This document is not updated frequently, and the list of passes
is most likely incomplete. It is possible to list passes known by the opt
tool using ``opt -print-passes``.

This document serves as a high level summary of the optimization features that
LLVM provides. Optimizations are implemented as Passes that traverse some
Expand Down Expand Up @@ -193,15 +196,12 @@ memory operations it depends on. It builds on alias analysis information, and
tries to provide a lazy, caching interface to a common kind of alias
information query.

``module-debuginfo``: Decodes module-level debug info
-----------------------------------------------------
``print<module-debuginfo>``: Decodes module-level debug info
------------------------------------------------------------

This pass decodes the debug info metadata in a module and prints in a
This pass decodes the debug info metadata in a module and prints it to standard output in a
(sufficiently-prepared-) human-readable form.

For example, run this pass from ``opt`` along with the ``-analyze`` option, and
it'll print to standard output.

``postdomtree``: Post-Dominator Tree Construction
-------------------------------------------------

Expand All @@ -228,18 +228,18 @@ standard error in a human-readable form.
``print-cfg-sccs``: Print SCCs of each function CFG
---------------------------------------------------

This pass, only available in ``opt``, printsthe SCCs of each function CFG to
This pass, only available in ``opt``, prints the SCCs of each function CFG to
standard error in a human-readable fom.

``print-function``: Print function to stderr
--------------------------------------------
``function(print)``: Print function to stderr
---------------------------------------------

The ``PrintFunctionPass`` class is designed to be pipelined with other
``FunctionPasses``, and prints out the functions of the module as they are
processed.

``print-module``: Print module to stderr
----------------------------------------
``module(print)``: Print module to stderr
-----------------------------------------

This pass simply prints out the entire module when it is executed.

Expand Down Expand Up @@ -924,17 +924,8 @@ code size or making it harder to reverse engineer code.
``strip-dead-debug-info``: Strip debug info for unused symbols
--------------------------------------------------------------

.. FIXME: this description is the same as for -strip

performs code stripping. this transformation can delete:

* names for virtual registers
* symbols for internal globals and functions
* debug information

note that this transformation makes code much less readable, so it should only
be used in situations where the strip utility would be used, such as reducing
code size or making it harder to reverse engineer code.
Performs code stripping. Similar to strip, but only strips debug info for
unused symbols.

``strip-dead-prototypes``: Strip Unused Function Prototypes
-----------------------------------------------------------
Expand All @@ -947,32 +938,13 @@ functions).
``strip-debug-declare``: Strip all ``llvm.dbg.declare`` intrinsics
------------------------------------------------------------------

.. FIXME: this description is the same as for -strip

This pass implements code stripping. Specifically, it can delete:

#. names for virtual registers
#. symbols for internal globals and functions
#. debug information

Note that this transformation makes code much less readable, so it should only
be used in situations where the 'strip' utility would be used, such as reducing
code size or making it harder to reverse engineer code.
Performs code stripping. Similar to strip, but only strips
``llvm.dbg.declare`` intrinsics.

``strip-nondebug``: Strip all symbols, except dbg symbols, from a module
------------------------------------------------------------------------

.. FIXME: this description is the same as for -strip

This pass implements code stripping. Specifically, it can delete:

#. names for virtual registers
#. symbols for internal globals and functions
#. debug information

Note that this transformation makes code much less readable, so it should only
be used in situations where the 'strip' utility would be used, such as reducing
code size or making it harder to reverse engineer code.
Performs code stripping. Similar to strip, but dbg info is preserved.

``tailcallelim``: Tail Call Elimination
---------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion llvm/docs/RISCVUsage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ LLVM supports (to various degrees) a number of experimental extensions. All exp
The primary goal of experimental support is to assist in the process of ratification by providing an existence proof of an implementation, and simplifying efforts to validate the value of a proposed extension against large code bases. Experimental extensions are expected to either transition to ratified status, or be eventually removed. The decision on whether to accept an experimental extension is currently done on an entirely case by case basis; if you want to propose one, attending the bi-weekly RISC-V sync-up call is strongly advised.

``experimental-ssnpm``, ``experimental-smnpm``, ``experimental-smmpm``, ``experimental-sspm``, ``experimental-supm``
LLVM implements the `v0.8.1 draft specification <https://github.com/riscv/riscv-j-extension/blob/master/zjpm-spec.pdf>__`
LLVM implements the `v0.8.1 draft specification <https://github.com/riscv/riscv-j-extension/blob/master/zjpm-spec.pdf>`__.

``experimental-ssqosid``
LLVM implements assembler support for the `v1.0-rc1 draft specification <https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0-rc1>`_.
Expand Down
4 changes: 3 additions & 1 deletion llvm/docs/TableGen/BackEnds.rst
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,9 @@ The table entries in ``ATable`` are sorted in order by ``Val1``, and within
each of those values, by ``Val2``. This allows a binary search of the table,
which is performed in the lookup function by ``std::lower_bound``. The
lookup function returns a reference to the found table entry, or the null
pointer if no entry is found.
pointer if no entry is found. If the table has a single primary key field
which is integral and densely numbered, a direct lookup is generated rather
than a binary search.

This example includes a field whose type TableGen cannot deduce. The ``Kind``
field uses the enumerated type ``CEnum`` defined above. To inform TableGen
Expand Down
14 changes: 10 additions & 4 deletions llvm/include/llvm/CodeGen/GlobalISel/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,10 +343,13 @@ Register getFunctionLiveInPhysReg(MachineFunction &MF,
const TargetRegisterClass &RC,
const DebugLoc &DL, LLT RegTy = LLT());

/// Return the least common multiple type of \p OrigTy and \p TargetTy, by changing the
/// number of vector elements or scalar bitwidth. The intent is a
/// Return the least common multiple type of \p OrigTy and \p TargetTy, by
/// changing the number of vector elements or scalar bitwidth. The intent is a
/// G_MERGE_VALUES, G_BUILD_VECTOR, or G_CONCAT_VECTORS can be constructed from
/// \p OrigTy elements, and unmerged into \p TargetTy
/// \p OrigTy elements, and unmerged into \p TargetTy. It is an error to call
/// this function where one argument is a fixed vector and the other is a
/// scalable vector, since it is illegal to build a G_{MERGE|UNMERGE}_VALUES
/// between fixed and scalable vectors.
LLVM_READNONE
LLT getLCMType(LLT OrigTy, LLT TargetTy);

Expand All @@ -365,7 +368,10 @@ LLT getCoverTy(LLT OrigTy, LLT TargetTy);
/// If these are vectors with different element types, this will try to produce
/// a vector with a compatible total size, but the element type of \p OrigTy. If
/// this can't be satisfied, this will produce a scalar smaller than the
/// original vector elements.
/// original vector elements. It is an error to call this function where
/// one argument is a fixed vector and the other is a scalable vector, since it
/// is illegal to build a G_{MERGE|UNMERGE}_VALUES between fixed and scalable
/// vectors.
///
/// In the worst case, this returns LLT::scalar(1)
LLVM_READNONE
Expand Down
22 changes: 16 additions & 6 deletions llvm/include/llvm/CodeGen/MachineModuleInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,21 +218,31 @@ class MachineModuleInfoWrapperPass : public ImmutablePass {
const MachineModuleInfo &getMMI() const { return MMI; }
};

/// An analysis that produces \c MachineInfo for a module.
/// An analysis that produces \c MachineModuleInfo for a module.
/// This does not produce its own MachineModuleInfo because we need a consistent
/// MachineModuleInfo to keep ownership of MachineFunctions regardless of
/// analysis invalidation/clearing. So something outside the analysis
/// infrastructure must own the MachineModuleInfo.
class MachineModuleAnalysis : public AnalysisInfoMixin<MachineModuleAnalysis> {
friend AnalysisInfoMixin<MachineModuleAnalysis>;
static AnalysisKey Key;

const LLVMTargetMachine *TM;
MachineModuleInfo &MMI;

public:
/// Provide the result type for this analysis pass.
using Result = MachineModuleInfo;
class Result {
MachineModuleInfo &MMI;
Result(MachineModuleInfo &MMI) : MMI(MMI) {}
friend class MachineModuleAnalysis;

MachineModuleAnalysis(const LLVMTargetMachine *TM) : TM(TM) {}
public:
MachineModuleInfo &getMMI() { return MMI; }
};

MachineModuleAnalysis(MachineModuleInfo &MMI) : MMI(MMI) {}

/// Run the analysis pass and produce machine module information.
MachineModuleInfo run(Module &M, ModuleAnalysisManager &);
Result run(Module &M, ModuleAnalysisManager &);
};

} // end namespace llvm
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/CodeGen/Register.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Register {
static_assert(std::numeric_limits<decltype(Reg)>::max() >= 0xFFFFFFFF,
"Reg isn't large enough to hold full range.");

/// isStackSlot - Sometimes it is useful the be able to store a non-negative
/// isStackSlot - Sometimes it is useful to be able to store a non-negative
/// frame index in a variable that normally holds a register. isStackSlot()
/// returns true if Reg is in the range used for stack slots.
///
Expand Down
5 changes: 4 additions & 1 deletion llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ using EntryArrayTy = std::pair<GlobalVariable *, GlobalVariable *>;
/// \param EntryArray Optional pair pointing to the `__start` and `__stop`
/// symbols holding the `__tgt_offload_entry` array.
/// \param Suffix An optional suffix appended to the emitted symbols.
/// \param Relocatable Indicate if we need to change the offloading section to
/// create a relocatable object.
llvm::Error wrapOpenMPBinaries(llvm::Module &M,
llvm::ArrayRef<llvm::ArrayRef<char>> Images,
EntryArrayTy EntryArray,
llvm::StringRef Suffix = "");
llvm::StringRef Suffix = "",
bool Relocatable = false);

/// Wraps the input fatbinary image into the module \p M as global symbols and
/// registers the images with the CUDA runtime.
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/IR/ModuleSummaryIndex.h
Original file line number Diff line number Diff line change
Expand Up @@ -1377,7 +1377,7 @@ class ModuleSummaryIndex {

// Temporary map while building StackIds list. Clear when index is completely
// built via releaseTemporaryMemory.
std::map<uint64_t, unsigned> StackIdToIndex;
DenseMap<uint64_t, unsigned> StackIdToIndex;

// YAML I/O support.
friend yaml::MappingTraits<ModuleSummaryIndex>;
Expand Down
28 changes: 28 additions & 0 deletions llvm/include/llvm/IR/PatternMatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -1711,6 +1711,34 @@ m_BitCast(const OpTy &Op) {
return CastOperator_match<OpTy, Instruction::BitCast>(Op);
}

template <typename Op_t> struct ElementWiseBitCast_match {
Op_t Op;

ElementWiseBitCast_match(const Op_t &OpMatch) : Op(OpMatch) {}

template <typename OpTy> bool match(OpTy *V) {
BitCastInst *I = dyn_cast<BitCastInst>(V);
if (!I)
return false;
Type *SrcType = I->getSrcTy();
Type *DstType = I->getType();
// Make sure the bitcast doesn't change between scalar and vector and
// doesn't change the number of vector elements.
if (SrcType->isVectorTy() != DstType->isVectorTy())
return false;
if (VectorType *SrcVecTy = dyn_cast<VectorType>(SrcType);
SrcVecTy && SrcVecTy->getElementCount() !=
cast<VectorType>(DstType)->getElementCount())
return false;
return Op.match(I->getOperand(0));
}
};

template <typename OpTy>
inline ElementWiseBitCast_match<OpTy> m_ElementWiseBitCast(const OpTy &Op) {
return ElementWiseBitCast_match<OpTy>(Op);
}

/// Matches PtrToInt.
template <typename OpTy>
inline CastOperator_match<OpTy, Instruction::PtrToInt>
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/ObjCopy/CommonConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ struct CommonConfig {
uint64_t PadTo = 0;
StringRef SplitDWO;
StringRef SymbolsPrefix;
StringRef SymbolsPrefixRemove;
StringRef AllocSectionsPrefix;
DiscardType DiscardMode = DiscardType::None;

Expand Down
7 changes: 1 addition & 6 deletions llvm/include/llvm/Target/TargetSchedule.td
Original file line number Diff line number Diff line change
Expand Up @@ -192,15 +192,10 @@ class ProcResourceUnits<ProcResourceKind kind, int num> {
SchedMachineModel SchedModel = ?;
}

// EponymousProcResourceKind helps implement ProcResourceUnits by
// allowing a ProcResourceUnits definition to reference itself. It
// should not be referenced anywhere else.
def EponymousProcResourceKind : ProcResourceKind;

// Subtargets typically define processor resource kind and number of
// units in one place.
class ProcResource<int num> : ProcResourceKind,
ProcResourceUnits<EponymousProcResourceKind, num>;
ProcResourceUnits<!cast<ProcResourceKind>(NAME), num>;

class ProcResGroup<list<ProcResource> resources> : ProcResourceKind {
list<ProcResource> Resources = resources;
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Analysis/InstructionSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3034,7 +3034,7 @@ static Value *simplifyICmpWithConstant(CmpInst::Predicate Pred, Value *LHS,
// floating-point casts:
// icmp slt (bitcast (uitofp X)), 0 --> false
// icmp sgt (bitcast (uitofp X)), -1 --> true
if (match(LHS, m_BitCast(m_UIToFP(m_Value(X))))) {
if (match(LHS, m_ElementWiseBitCast(m_UIToFP(m_Value(X))))) {
if (Pred == ICmpInst::ICMP_SLT && match(RHS, m_Zero()))
return ConstantInt::getFalse(ITy);
if (Pred == ICmpInst::ICMP_SGT && match(RHS, m_AllOnes()))
Expand Down
19 changes: 0 additions & 19 deletions llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6632,9 +6632,6 @@ Error BitcodeReader::materialize(GlobalValue *GV) {
if (Error Err = materializeMetadata())
return Err;

bool NewDebugInfoRequested = F->IsNewDbgInfoFormat;
F->IsNewDbgInfoFormat = false;

// Move the bit stream to the saved position of the deferred function body.
if (Error JumpFailed = Stream.JumpToBit(DFII->second))
return JumpFailed;
Expand Down Expand Up @@ -6710,14 +6707,6 @@ Error BitcodeReader::materialize(GlobalValue *GV) {
// Look for functions that rely on old function attribute behavior.
UpgradeFunctionAttributes(*F);

// If we've materialized a function set up in "new" debug-info mode, the
// contents just loaded will still be in dbg.value mode. Switch to the new
// mode now. NB: we can add more complicated logic here in the future to
// correctly identify when we do and don't need to autoupgrade.
if (NewDebugInfoRequested) {
F->convertToNewDbgValues();
}

// Bring in any functions that this function forward-referenced via
// blockaddresses.
return materializeForwardReferencedFunctions();
Expand Down Expand Up @@ -8042,14 +8031,6 @@ BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll,
return std::move(Err);
}

// If we are operating in a "new debug-info" context, upgrade the debug-info
// in the loaded module. This is a transitional approach as we enable "new"
// debug-info in LLVM, which will eventually be pushed down into the
// autoupgrade path once the bitcode-encoding is finalised. Non-materialised
// functions will be upgraded in the materialize method.
if (UseNewDbgInfoFormat && !M->IsNewDbgInfoFormat)
M->convertToNewDbgValues();

return std::move(M);
}

Expand Down
39 changes: 23 additions & 16 deletions llvm/lib/CodeGen/AtomicExpandPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,16 +322,6 @@ bool AtomicExpand::runOnFunction(Function &F) {
if (isIdempotentRMW(RMWI) && simplifyIdempotentRMW(RMWI)) {
MadeChange = true;
} else {
AtomicRMWInst::BinOp Op = RMWI->getOperation();
unsigned MinCASSize = TLI->getMinCmpXchgSizeInBits() / 8;
unsigned ValueSize = getAtomicOpSize(RMWI);
if (ValueSize < MinCASSize &&
(Op == AtomicRMWInst::Or || Op == AtomicRMWInst::Xor ||
Op == AtomicRMWInst::And)) {
RMWI = widenPartwordAtomicRMW(RMWI);
MadeChange = true;
}

MadeChange |= tryExpandAtomicRMW(RMWI);
}
} else if (CASI)
Expand Down Expand Up @@ -607,6 +597,17 @@ bool AtomicExpand::tryExpandAtomicRMW(AtomicRMWInst *AI) {
return true;
}
case TargetLoweringBase::AtomicExpansionKind::MaskedIntrinsic: {
unsigned MinCASSize = TLI->getMinCmpXchgSizeInBits() / 8;
unsigned ValueSize = getAtomicOpSize(AI);
if (ValueSize < MinCASSize) {
AtomicRMWInst::BinOp Op = AI->getOperation();
// Widen And/Or/Xor and give the target another chance at expanding it.
if (Op == AtomicRMWInst::Or || Op == AtomicRMWInst::Xor ||
Op == AtomicRMWInst::And) {
tryExpandAtomicRMW(widenPartwordAtomicRMW(AI));
return true;
}
}
expandAtomicRMWToMaskedIntrinsic(AI);
return true;
}
Expand Down Expand Up @@ -845,6 +846,14 @@ static Value *performMaskedAtomicOp(AtomicRMWInst::BinOp Op,
/// part of the value.
void AtomicExpand::expandPartwordAtomicRMW(
AtomicRMWInst *AI, TargetLoweringBase::AtomicExpansionKind ExpansionKind) {
// Widen And/Or/Xor and give the target another chance at expanding it.
AtomicRMWInst::BinOp Op = AI->getOperation();
if (Op == AtomicRMWInst::Or || Op == AtomicRMWInst::Xor ||
Op == AtomicRMWInst::And) {
tryExpandAtomicRMW(widenPartwordAtomicRMW(AI));
return;
}

AtomicOrdering MemOpOrder = AI->getOrdering();
SyncScope::ID SSID = AI->getSyncScopeID();

Expand All @@ -855,18 +864,16 @@ void AtomicExpand::expandPartwordAtomicRMW(
AI->getAlign(), TLI->getMinCmpXchgSizeInBits() / 8);

Value *ValOperand_Shifted = nullptr;
if (AI->getOperation() == AtomicRMWInst::Xchg ||
AI->getOperation() == AtomicRMWInst::Add ||
AI->getOperation() == AtomicRMWInst::Sub ||
AI->getOperation() == AtomicRMWInst::Nand) {
if (Op == AtomicRMWInst::Xchg || Op == AtomicRMWInst::Add ||
Op == AtomicRMWInst::Sub || Op == AtomicRMWInst::Nand) {
ValOperand_Shifted =
Builder.CreateShl(Builder.CreateZExt(AI->getValOperand(), PMV.WordType),
PMV.ShiftAmt, "ValOperand_Shifted");
}

auto PerformPartwordOp = [&](IRBuilderBase &Builder, Value *Loaded) {
return performMaskedAtomicOp(AI->getOperation(), Builder, Loaded,
ValOperand_Shifted, AI->getValOperand(), PMV);
return performMaskedAtomicOp(Op, Builder, Loaded, ValOperand_Shifted,
AI->getValOperand(), PMV);
};

Value *OldResult;
Expand Down
154 changes: 93 additions & 61 deletions llvm/lib/CodeGen/GlobalISel/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1071,49 +1071,70 @@ void llvm::getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU) {
}

LLT llvm::getLCMType(LLT OrigTy, LLT TargetTy) {
const unsigned OrigSize = OrigTy.getSizeInBits();
const unsigned TargetSize = TargetTy.getSizeInBits();

if (OrigSize == TargetSize)
if (OrigTy.getSizeInBits() == TargetTy.getSizeInBits())
return OrigTy;

if (OrigTy.isVector()) {
const LLT OrigElt = OrigTy.getElementType();

if (TargetTy.isVector()) {
const LLT TargetElt = TargetTy.getElementType();
if (OrigTy.isVector() && TargetTy.isVector()) {
LLT OrigElt = OrigTy.getElementType();
LLT TargetElt = TargetTy.getElementType();

if (OrigElt.getSizeInBits() == TargetElt.getSizeInBits()) {
int GCDElts =
std::gcd(OrigTy.getNumElements(), TargetTy.getNumElements());
// Prefer the original element type.
ElementCount Mul = OrigTy.getElementCount() * TargetTy.getNumElements();
return LLT::vector(Mul.divideCoefficientBy(GCDElts),
OrigTy.getElementType());
}
} else {
if (OrigElt.getSizeInBits() == TargetSize)
return OrigTy;
// TODO: The docstring for this function says the intention is to use this
// function to build MERGE/UNMERGE instructions. It won't be the case that
// we generate a MERGE/UNMERGE between fixed and scalable vector types. We
// could implement getLCMType between the two in the future if there was a
// need, but it is not worth it now as this function should not be used in
// that way.
assert(((OrigTy.isScalableVector() && !TargetTy.isFixedVector()) ||
(OrigTy.isFixedVector() && !TargetTy.isScalableVector())) &&
"getLCMType not implemented between fixed and scalable vectors.");

if (OrigElt.getSizeInBits() == TargetElt.getSizeInBits()) {
int GCDMinElts = std::gcd(OrigTy.getElementCount().getKnownMinValue(),
TargetTy.getElementCount().getKnownMinValue());
// Prefer the original element type.
ElementCount Mul = OrigTy.getElementCount().multiplyCoefficientBy(
TargetTy.getElementCount().getKnownMinValue());
return LLT::vector(Mul.divideCoefficientBy(GCDMinElts),
OrigTy.getElementType());
}

unsigned LCMSize = std::lcm(OrigSize, TargetSize);
return LLT::fixed_vector(LCMSize / OrigElt.getSizeInBits(), OrigElt);
unsigned LCM = std::lcm(OrigTy.getSizeInBits().getKnownMinValue(),
TargetTy.getSizeInBits().getKnownMinValue());
return LLT::vector(
ElementCount::get(LCM / OrigElt.getSizeInBits(), OrigTy.isScalable()),
OrigElt);
}

if (TargetTy.isVector()) {
unsigned LCMSize = std::lcm(OrigSize, TargetSize);
return LLT::fixed_vector(LCMSize / OrigSize, OrigTy);
// One type is scalar, one type is vector
if (OrigTy.isVector() || TargetTy.isVector()) {
LLT VecTy = OrigTy.isVector() ? OrigTy : TargetTy;
LLT ScalarTy = OrigTy.isVector() ? TargetTy : OrigTy;
LLT EltTy = VecTy.getElementType();
LLT OrigEltTy = OrigTy.isVector() ? OrigTy.getElementType() : OrigTy;

// Prefer scalar type from OrigTy.
if (EltTy.getSizeInBits() == ScalarTy.getSizeInBits())
return LLT::vector(VecTy.getElementCount(), OrigEltTy);

// Different size scalars. Create vector with the same total size.
// LCM will take fixed/scalable from VecTy.
unsigned LCM = std::lcm(EltTy.getSizeInBits().getFixedValue() *
VecTy.getElementCount().getKnownMinValue(),
ScalarTy.getSizeInBits().getFixedValue());
// Prefer type from OrigTy
return LLT::vector(ElementCount::get(LCM / OrigEltTy.getSizeInBits(),
VecTy.getElementCount().isScalable()),
OrigEltTy);
}

unsigned LCMSize = std::lcm(OrigSize, TargetSize);

// At this point, both types are scalars of different size
unsigned LCM = std::lcm(OrigTy.getSizeInBits().getFixedValue(),
TargetTy.getSizeInBits().getFixedValue());
// Preserve pointer types.
if (LCMSize == OrigSize)
if (LCM == OrigTy.getSizeInBits())
return OrigTy;
if (LCMSize == TargetSize)
if (LCM == TargetTy.getSizeInBits())
return TargetTy;

return LLT::scalar(LCMSize);
return LLT::scalar(LCM);
}

LLT llvm::getCoverTy(LLT OrigTy, LLT TargetTy) {
Expand All @@ -1138,45 +1159,56 @@ LLT llvm::getCoverTy(LLT OrigTy, LLT TargetTy) {
}

LLT llvm::getGCDType(LLT OrigTy, LLT TargetTy) {
const unsigned OrigSize = OrigTy.getSizeInBits();
const unsigned TargetSize = TargetTy.getSizeInBits();

if (OrigSize == TargetSize)
if (OrigTy.getSizeInBits() == TargetTy.getSizeInBits())
return OrigTy;

if (OrigTy.isVector()) {
if (OrigTy.isVector() && TargetTy.isVector()) {
LLT OrigElt = OrigTy.getElementType();
if (TargetTy.isVector()) {
LLT TargetElt = TargetTy.getElementType();
if (OrigElt.getSizeInBits() == TargetElt.getSizeInBits()) {
int GCD = std::gcd(OrigTy.getNumElements(), TargetTy.getNumElements());
return LLT::scalarOrVector(ElementCount::getFixed(GCD), OrigElt);
}
} else {
// If the source is a vector of pointers, return a pointer element.
if (OrigElt.getSizeInBits() == TargetSize)
return OrigElt;
}

unsigned GCD = std::gcd(OrigSize, TargetSize);
// TODO: The docstring for this function says the intention is to use this
// function to build MERGE/UNMERGE instructions. It won't be the case that
// we generate a MERGE/UNMERGE between fixed and scalable vector types. We
// could implement getGCDType between the two in the future if there was a
// need, but it is not worth it now as this function should not be used in
// that way.
assert(((OrigTy.isScalableVector() && !TargetTy.isFixedVector()) ||
(OrigTy.isFixedVector() && !TargetTy.isScalableVector())) &&
"getGCDType not implemented between fixed and scalable vectors.");

unsigned GCD = std::gcd(OrigTy.getSizeInBits().getKnownMinValue(),
TargetTy.getSizeInBits().getKnownMinValue());
if (GCD == OrigElt.getSizeInBits())
return OrigElt;
return LLT::scalarOrVector(ElementCount::get(1, OrigTy.isScalable()),
OrigElt);

// If we can't produce the original element type, we have to use a smaller
// scalar.
// Cannot produce original element type, but both have vscale in common.
if (GCD < OrigElt.getSizeInBits())
return LLT::scalar(GCD);
return LLT::fixed_vector(GCD / OrigElt.getSizeInBits(), OrigElt);
}
return LLT::scalarOrVector(ElementCount::get(1, OrigTy.isScalable()),
GCD);

if (TargetTy.isVector()) {
// Try to preserve the original element type.
LLT TargetElt = TargetTy.getElementType();
if (TargetElt.getSizeInBits() == OrigSize)
return OrigTy;
return LLT::vector(
ElementCount::get(GCD / OrigElt.getSizeInBits().getFixedValue(),
OrigTy.isScalable()),
OrigElt);
}

unsigned GCD = std::gcd(OrigSize, TargetSize);
// If one type is vector and the element size matches the scalar size, then
// the gcd is the scalar type.
if (OrigTy.isVector() &&
OrigTy.getElementType().getSizeInBits() == TargetTy.getSizeInBits())
return OrigTy.getElementType();
if (TargetTy.isVector() &&
TargetTy.getElementType().getSizeInBits() == OrigTy.getSizeInBits())
return OrigTy;

// At this point, both types are either scalars of different type or one is a
// vector and one is a scalar. If both types are scalars, the GCD type is the
// GCD between the two scalar sizes. If one is vector and one is scalar, then
// the GCD type is the GCD between the scalar and the vector element size.
LLT OrigScalar = OrigTy.getScalarType();
LLT TargetScalar = TargetTy.getScalarType();
unsigned GCD = std::gcd(OrigScalar.getSizeInBits().getFixedValue(),
TargetScalar.getSizeInBits().getFixedValue());
return LLT::scalar(GCD);
}

Expand Down
11 changes: 5 additions & 6 deletions llvm/lib/CodeGen/MachineModuleInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,10 @@ bool MachineModuleInfoWrapperPass::doFinalization(Module &M) {

AnalysisKey MachineModuleAnalysis::Key;

MachineModuleInfo MachineModuleAnalysis::run(Module &M,
ModuleAnalysisManager &) {
MachineModuleInfo MMI(TM);
MachineModuleAnalysis::Result
MachineModuleAnalysis::run(Module &M, ModuleAnalysisManager &) {
MMI.TheModule = &M;
MMI.DbgInfoAvailable = !DisableDebugInfoPrinting &&
!M.debug_compile_units().empty();
return MMI;
MMI.DbgInfoAvailable =
!DisableDebugInfoPrinting && !M.debug_compile_units().empty();
return Result(MMI);
}
2 changes: 1 addition & 1 deletion llvm/lib/CodeGen/MachinePassManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Error MachineFunctionPassManager::run(Module &M,
// because we don't run any module pass in codegen pipeline. This is very
// important because the codegen state is stored in MMI which is the analysis
// result of MachineModuleAnalysis. MMI should not be recomputed.
auto &MMI = MFAM.getResult<MachineModuleAnalysis>(M);
auto &MMI = MFAM.getResult<MachineModuleAnalysis>(M).getMMI();

(void)RequireCodeGenSCCOrder;
assert(!RequireCodeGenSCCOrder && "not implemented");
Expand Down
17 changes: 15 additions & 2 deletions llvm/lib/CodeGen/MachineScheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3804,6 +3804,12 @@ ScheduleDAGMILive *llvm::createGenericSchedLive(MachineSchedContext *C) {
// data and pass it to later mutations. Have a single mutation that gathers
// the interesting nodes in one pass.
DAG->addMutation(createCopyConstrainDAGMutation(DAG->TII, DAG->TRI));

const TargetSubtargetInfo &STI = C->MF->getSubtarget();
// Add MacroFusion mutation if fusions are not empty.
const auto &MacroFusions = STI.getMacroFusions();
if (!MacroFusions.empty())
DAG->addMutation(createMacroFusionDAGMutation(MacroFusions));
return DAG;
}

Expand Down Expand Up @@ -3953,8 +3959,15 @@ void PostGenericScheduler::schedNode(SUnit *SU, bool IsTopNode) {
}

ScheduleDAGMI *llvm::createGenericSchedPostRA(MachineSchedContext *C) {
return new ScheduleDAGMI(C, std::make_unique<PostGenericScheduler>(C),
/*RemoveKillFlags=*/true);
ScheduleDAGMI *DAG =
new ScheduleDAGMI(C, std::make_unique<PostGenericScheduler>(C),
/*RemoveKillFlags=*/true);
const TargetSubtargetInfo &STI = C->MF->getSubtarget();
// Add MacroFusion mutation if fusions are not empty.
const auto &MacroFusions = STI.getMacroFusions();
if (!MacroFusions.empty())
DAG->addMutation(createMacroFusionDAGMutation(MacroFusions));
return DAG;
}

//===----------------------------------------------------------------------===//
Expand Down
15 changes: 5 additions & 10 deletions llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,16 +334,11 @@ namespace {
}

bool SimplifyDemandedBits(SDValue Op, const APInt &DemandedBits) {
TargetLowering::TargetLoweringOpt TLO(DAG, LegalTypes, LegalOperations);
KnownBits Known;
if (!TLI.SimplifyDemandedBits(Op, DemandedBits, Known, TLO, 0, false))
return false;

// Revisit the node.
AddToWorklist(Op.getNode());

CommitTargetLoweringOpt(TLO);
return true;
EVT VT = Op.getValueType();
APInt DemandedElts = VT.isFixedLengthVector()
? APInt::getAllOnes(VT.getVectorNumElements())
: APInt(1, 1);
return SimplifyDemandedBits(Op, DemandedBits, DemandedElts, false);
}

/// Check the specified vector node value to see if it can be simplified or
Expand Down
18 changes: 10 additions & 8 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2897,6 +2897,8 @@ void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, const APInt &Amt,
/// shift amount.
bool DAGTypeLegalizer::
ExpandShiftWithKnownAmountBit(SDNode *N, SDValue &Lo, SDValue &Hi) {
unsigned Opc = N->getOpcode();
SDValue In = N->getOperand(0);
SDValue Amt = N->getOperand(1);
EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
EVT ShTy = Amt.getValueType();
Expand All @@ -2907,15 +2909,15 @@ ExpandShiftWithKnownAmountBit(SDNode *N, SDValue &Lo, SDValue &Hi) {
SDLoc dl(N);

APInt HighBitMask = APInt::getHighBitsSet(ShBits, ShBits - Log2_32(NVTBits));
KnownBits Known = DAG.computeKnownBits(N->getOperand(1));
KnownBits Known = DAG.computeKnownBits(Amt);

// If we don't know anything about the high bits, exit.
if (((Known.Zero|Known.One) & HighBitMask) == 0)
if (((Known.Zero | Known.One) & HighBitMask) == 0)
return false;

// Get the incoming operand to be shifted.
SDValue InL, InH;
GetExpandedInteger(N->getOperand(0), InL, InH);
GetExpandedInteger(In, InL, InH);

// If we know that any of the high bits of the shift amount are one, then we
// can do this as a couple of simple shifts.
Expand All @@ -2924,7 +2926,7 @@ ExpandShiftWithKnownAmountBit(SDNode *N, SDValue &Lo, SDValue &Hi) {
Amt = DAG.getNode(ISD::AND, dl, ShTy, Amt,
DAG.getConstant(~HighBitMask, dl, ShTy));

switch (N->getOpcode()) {
switch (Opc) {
default: llvm_unreachable("Unknown shift");
case ISD::SHL:
Lo = DAG.getConstant(0, dl, NVT); // Low part is zero.
Expand Down Expand Up @@ -2952,15 +2954,15 @@ ExpandShiftWithKnownAmountBit(SDNode *N, SDValue &Lo, SDValue &Hi) {
DAG.getConstant(NVTBits - 1, dl, ShTy));

unsigned Op1, Op2;
switch (N->getOpcode()) {
switch (Opc) {
default: llvm_unreachable("Unknown shift");
case ISD::SHL: Op1 = ISD::SHL; Op2 = ISD::SRL; break;
case ISD::SRL:
case ISD::SRA: Op1 = ISD::SRL; Op2 = ISD::SHL; break;
}

// When shifting right the arithmetic for Lo and Hi is swapped.
if (N->getOpcode() != ISD::SHL)
if (Opc != ISD::SHL)
std::swap(InL, InH);

// Use a little trick to get the bits that move from Lo to Hi. First
Expand All @@ -2969,10 +2971,10 @@ ExpandShiftWithKnownAmountBit(SDNode *N, SDValue &Lo, SDValue &Hi) {
// Then compute the remaining shift with amount-1.
SDValue Sh2 = DAG.getNode(Op2, dl, NVT, Sh1, Amt2);

Lo = DAG.getNode(N->getOpcode(), dl, NVT, InL, Amt);
Lo = DAG.getNode(Opc, dl, NVT, InL, Amt);
Hi = DAG.getNode(ISD::OR, dl, NVT, DAG.getNode(Op1, dl, NVT, InH, Amt),Sh2);

if (N->getOpcode() != ISD::SHL)
if (Opc != ISD::SHL)
std::swap(Hi, Lo);
return true;
}
Expand Down
32 changes: 26 additions & 6 deletions llvm/lib/CodeGen/TwoAddressInstructionPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1929,21 +1929,27 @@ eliminateRegSequence(MachineBasicBlock::iterator &MBBI) {
Register DstReg = MI.getOperand(0).getReg();

SmallVector<Register, 4> OrigRegs;
VNInfo *DefVN = nullptr;
if (LIS) {
OrigRegs.push_back(MI.getOperand(0).getReg());
for (unsigned i = 1, e = MI.getNumOperands(); i < e; i += 2)
OrigRegs.push_back(MI.getOperand(i).getReg());
if (LIS->hasInterval(DstReg)) {
DefVN = LIS->getInterval(DstReg)
.Query(LIS->getInstructionIndex(MI))
.valueOut();
}
}

LaneBitmask UndefLanes = LaneBitmask::getNone();
bool DefEmitted = false;
bool DefIsPartial = false;
for (unsigned i = 1, e = MI.getNumOperands(); i < e; i += 2) {
MachineOperand &UseMO = MI.getOperand(i);
Register SrcReg = UseMO.getReg();
unsigned SubIdx = MI.getOperand(i+1).getImm();
// Nothing needs to be inserted for undef operands.
if (UseMO.isUndef()) {
DefIsPartial = true;
UndefLanes |= TRI->getSubRegIndexLaneMask(SubIdx);
continue;
}

Expand Down Expand Up @@ -1991,11 +1997,25 @@ eliminateRegSequence(MachineBasicBlock::iterator &MBBI) {
MI.removeOperand(j);
} else {
if (LIS) {
// Force interval recomputation if we moved from full definition
// of register to partial.
if (DefIsPartial && LIS->hasInterval(DstReg) &&
MRI->shouldTrackSubRegLiveness(DstReg))
// Force live interval recomputation if we moved to a partial definition
// of the register. Undef flags must be propagate to uses of undefined
// subregister for accurate interval computation.
if (UndefLanes.any() && DefVN && MRI->shouldTrackSubRegLiveness(DstReg)) {
auto &LI = LIS->getInterval(DstReg);
for (MachineOperand &UseOp : MRI->use_operands(DstReg)) {
unsigned SubReg = UseOp.getSubReg();
if (UseOp.isUndef() || !SubReg)
continue;
auto *VN =
LI.getVNInfoAt(LIS->getInstructionIndex(*UseOp.getParent()));
if (DefVN != VN)
continue;
LaneBitmask LaneMask = TRI->getSubRegIndexLaneMask(SubReg);
if ((UndefLanes & LaneMask).any())
UseOp.setIsUndef(true);
}
LIS->removeInterval(DstReg);
}
LIS->RemoveMachineInstrFromMaps(MI);
}

Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,8 @@ static RelaxAux initRelaxAux(LinkGraph &G) {
RelaxAux Aux;
Aux.Config.IsRV32 = G.getTargetTriple().isRISCV32();
const auto &Features = G.getFeatures().getFeatures();
Aux.Config.HasRVC = llvm::is_contained(Features, "+c");
Aux.Config.HasRVC = llvm::is_contained(Features, "+c") ||
llvm::is_contained(Features, "+zca");

for (auto &S : G.sections()) {
if (!shouldRelax(S))
Expand Down
Loading