280 lines · cpp
1//=== - llvm/unittest/Support/Alignment.cpp - Alignment utility tests -----===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Support/Alignment.h"10#include "llvm/ADT/STLExtras.h"11#include "gtest/gtest.h"12 13#include <vector>14 15#ifdef _MSC_VER16// Disable warnings about potential divide by 0.17#pragma warning(push)18#pragma warning(disable : 4723)19#endif20 21using namespace llvm;22 23namespace {24 25TEST(AlignmentTest, AlignOfConstant) {26 EXPECT_EQ(Align::Of<uint8_t>(), Align(alignof(uint8_t)));27 EXPECT_EQ(Align::Of<uint16_t>(), Align(alignof(uint16_t)));28 EXPECT_EQ(Align::Of<uint32_t>(), Align(alignof(uint32_t)));29 EXPECT_EQ(Align::Of<uint64_t>(), Align(alignof(uint64_t)));30}31 32TEST(AlignmentTest, AlignConstant) {33 EXPECT_EQ(Align::Constant<1>(), Align(1));34 EXPECT_EQ(Align::Constant<2>(), Align(2));35 EXPECT_EQ(Align::Constant<4>(), Align(4));36 EXPECT_EQ(Align::Constant<8>(), Align(8));37 EXPECT_EQ(Align::Constant<16>(), Align(16));38 EXPECT_EQ(Align::Constant<32>(), Align(32));39 EXPECT_EQ(Align::Constant<64>(), Align(64));40}41 42TEST(AlignmentTest, AlignConstexprConstant) {43 constexpr Align kConstantAlign = Align::Of<uint64_t>();44 EXPECT_EQ(Align(alignof(uint64_t)), kConstantAlign);45}46 47TEST(AlignmentTest, ConstexprAssign) {48 constexpr auto assignAndGet = []() constexpr {49 Align A = Align::Constant<8>();50 Align B = Align::Constant<16>();51 A = B;52 return A.value();53 };54 static_assert(assignAndGet() == 16);55}56 57std::vector<uint64_t> getValidAlignments() {58 std::vector<uint64_t> Out;59 for (size_t Shift = 0; Shift < 64; ++Shift)60 Out.push_back(1ULL << Shift);61 return Out;62}63 64TEST(AlignmentTest, AlignDefaultCTor) { EXPECT_EQ(Align().value(), 1ULL); }65 66TEST(AlignmentTest, MaybeAlignDefaultCTor) { EXPECT_FALSE(MaybeAlign()); }67 68TEST(AlignmentTest, ValidCTors) {69 for (uint64_t Value : getValidAlignments()) {70 EXPECT_EQ(Align(Value).value(), Value);71 EXPECT_EQ((*MaybeAlign(Value)).value(), Value);72 }73}74 75TEST(AlignmentTest, CheckMaybeAlignHasValue) {76 EXPECT_TRUE(MaybeAlign(1));77 EXPECT_TRUE(MaybeAlign(1).has_value());78 EXPECT_FALSE(MaybeAlign(0));79 EXPECT_FALSE(MaybeAlign(0).has_value());80 EXPECT_FALSE(MaybeAlign());81 EXPECT_FALSE(MaybeAlign().has_value());82}83 84TEST(AlignmentTest, Division) {85 for (uint64_t Value : getValidAlignments()) {86 if (Value > 1) {87 EXPECT_EQ(Align(Value).previous(), Value / 2);88 }89 }90}91 92TEST(AlignmentTest, AlignTo) {93 struct {94 uint64_t alignment;95 uint64_t offset;96 uint64_t rounded;97 const void *forgedAddr() const {98 // A value of any integral or enumeration type can be converted to a99 // pointer type.100 return reinterpret_cast<const void *>(offset);101 }102 } kTests[] = {103 // Align104 {1, 0, 0}, {1, 1, 1}, {1, 5, 5}, {2, 0, 0}, {2, 1, 2}, {2, 2, 2},105 {2, 7, 8}, {2, 16, 16}, {4, 0, 0}, {4, 1, 4}, {4, 4, 4}, {4, 6, 8},106 };107 for (const auto &T : kTests) {108 Align A = Align(T.alignment);109 EXPECT_EQ(alignTo(T.offset, A), T.rounded);110 EXPECT_EQ(alignAddr(T.forgedAddr(), A), T.rounded);111 }112}113 114TEST(AlignmentTest, AlignToWithSkew) {115 EXPECT_EQ(alignTo(5, Align(8), 0), alignTo(5, Align(8)));116 EXPECT_EQ(alignTo(5, Align(8), 7), 7U);117 EXPECT_EQ(alignTo(17, Align(8), 1), 17U);118 EXPECT_EQ(alignTo(~0LL, Align(8), 3), 3U);119}120 121TEST(AlignmentTest, Log2) {122 for (uint64_t Value : getValidAlignments()) {123 EXPECT_EQ(Log2(Align(Value)), Log2_64(Value));124 }125}126 127TEST(AlignmentTest, Encode_Decode) {128 for (uint64_t Value : getValidAlignments()) {129 {130 Align Actual(Value);131 Align Expected = *decodeMaybeAlign(encode(Actual));132 EXPECT_EQ(Expected, Actual);133 }134 {135 MaybeAlign Actual(Value);136 MaybeAlign Expected = decodeMaybeAlign(encode(Actual));137 EXPECT_EQ(Expected, Actual);138 }139 }140 MaybeAlign Actual(0);141 MaybeAlign Expected = decodeMaybeAlign(encode(Actual));142 EXPECT_EQ(Expected, Actual);143}144 145TEST(AlignmentTest, isAligned_isAddrAligned) {146 struct {147 uint64_t alignment;148 uint64_t offset;149 bool isAligned;150 const void *forgedAddr() const {151 // A value of any integral or enumeration type can be converted to a152 // pointer type.153 return reinterpret_cast<const void *>(offset);154 }155 } kTests[] = {156 {1, 0, true}, {1, 1, true}, {1, 5, true}, {2, 0, true},157 {2, 1, false}, {2, 2, true}, {2, 7, false}, {2, 16, true},158 {4, 0, true}, {4, 1, false}, {4, 4, true}, {4, 6, false},159 };160 for (const auto &T : kTests) {161 MaybeAlign A(T.alignment);162 // Test Align163 if (A) {164 EXPECT_EQ(isAligned(*A, T.offset), T.isAligned);165 EXPECT_EQ(isAddrAligned(*A, T.forgedAddr()), T.isAligned);166 }167 }168}169 170TEST(AlignmentTest, offsetToAlignment) {171 struct {172 uint64_t alignment;173 uint64_t offset;174 uint64_t alignedOffset;175 const void *forgedAddr() const {176 // A value of any integral or enumeration type can be converted to a177 // pointer type.178 return reinterpret_cast<const void *>(offset);179 }180 } kTests[] = {181 {1, 0, 0}, {1, 1, 0}, {1, 5, 0}, {2, 0, 0}, {2, 1, 1}, {2, 2, 0},182 {2, 7, 1}, {2, 16, 0}, {4, 0, 0}, {4, 1, 3}, {4, 4, 0}, {4, 6, 2},183 };184 for (const auto &T : kTests) {185 const Align A(T.alignment);186 EXPECT_EQ(offsetToAlignment(T.offset, A), T.alignedOffset);187 EXPECT_EQ(offsetToAlignedAddr(T.forgedAddr(), A), T.alignedOffset);188 }189}190 191TEST(AlignmentTest, AlignComparisons) {192 std::vector<uint64_t> ValidAlignments = getValidAlignments();193 llvm::sort(ValidAlignments);194 for (size_t I = 1; I < ValidAlignments.size(); ++I) {195 assert(I >= 1);196 const Align A(ValidAlignments[I - 1]);197 const Align B(ValidAlignments[I]);198 EXPECT_EQ(A, A);199 EXPECT_NE(A, B);200 EXPECT_LT(A, B);201 EXPECT_GT(B, A);202 EXPECT_LE(A, B);203 EXPECT_GE(B, A);204 EXPECT_LE(A, A);205 EXPECT_GE(A, A);206 207 EXPECT_EQ(A, A.value());208 EXPECT_NE(A, B.value());209 EXPECT_LT(A, B.value());210 EXPECT_GT(B, A.value());211 EXPECT_LE(A, B.value());212 EXPECT_GE(B, A.value());213 EXPECT_LE(A, A.value());214 EXPECT_GE(A, A.value());215 216 EXPECT_EQ(std::max(A, B), B);217 EXPECT_EQ(std::min(A, B), A);218 219 const MaybeAlign MA(ValidAlignments[I - 1]);220 const MaybeAlign MB(ValidAlignments[I]);221 EXPECT_EQ(MA, MA);222 EXPECT_NE(MA, MB);223 224 EXPECT_EQ(std::max(A, B), B);225 EXPECT_EQ(std::min(A, B), A);226 }227}228 229TEST(AlignmentTest, AssumeAligned) {230 EXPECT_EQ(assumeAligned(0), Align(1));231 EXPECT_EQ(assumeAligned(0), Align());232 EXPECT_EQ(assumeAligned(1), Align(1));233 EXPECT_EQ(assumeAligned(1), Align());234}235 236// Death tests reply on assert which is disabled in release mode.237#ifndef NDEBUG238 239// We use a subset of valid alignments for DEATH_TESTs as they are particularly240// slow.241std::vector<uint64_t> getValidAlignmentsForDeathTest() {242 return {1, 1ULL << 31, 1ULL << 63};243}244 245std::vector<uint64_t> getNonPowerOfTwo() { return {3, 10, 15}; }246 247TEST(AlignmentDeathTest, InvalidCTors) {248 EXPECT_DEATH((Align(0)), "Value must not be 0");249 for (uint64_t Value : getNonPowerOfTwo()) {250 EXPECT_DEATH((Align(Value)), "Alignment is not a power of 2");251 EXPECT_DEATH((MaybeAlign(Value)),252 "Alignment is neither 0 nor a power of 2");253 }254}255 256TEST(AlignmentDeathTest, ComparisonsWithZero) {257 for (uint64_t Value : getValidAlignmentsForDeathTest()) {258 EXPECT_DEATH((void)(Align(Value) == 0), ".* should be defined");259 EXPECT_DEATH((void)(Align(Value) != 0), ".* should be defined");260 EXPECT_DEATH((void)(Align(Value) >= 0), ".* should be defined");261 EXPECT_DEATH((void)(Align(Value) <= 0), ".* should be defined");262 EXPECT_DEATH((void)(Align(Value) > 0), ".* should be defined");263 EXPECT_DEATH((void)(Align(Value) < 0), ".* should be defined");264 }265}266 267TEST(AlignmentDeathTest, AlignAddr) {268 const void *const unaligned_high_ptr =269 reinterpret_cast<const void *>(std::numeric_limits<uintptr_t>::max() - 1);270 EXPECT_DEATH(alignAddr(unaligned_high_ptr, Align(16)), "Overflow");271}272 273#endif // NDEBUG274 275} // end anonymous namespace276 277#ifdef _MSC_VER278#pragma warning(pop)279#endif280