Skip to content

Commit

Permalink
ADT: add <bit> header, implement C++20 bit_cast, use
Browse files Browse the repository at this point in the history
Summary: I saw a few places that were punning through a union of FP and integer, and that made me sad. Luckily, C++20 adds bit_cast for exactly that purpose. Implement our own version in ADT (without constexpr, leaving us a bit sad), and use it in the few places my grep-fu found silly union punning.

Reviewers: javed.absar

Subscribers: dexonsmith, llvm-commits

Differential Revision: https://reviews.llvm.org/D51693

llvm-svn: 341728
  • Loading branch information
jfbastien committed Sep 7, 2018
1 parent f803b23 commit 2865508
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 39 deletions.
37 changes: 37 additions & 0 deletions llvm/include/llvm/ADT/bit.h
@@ -0,0 +1,37 @@
//===-- llvm/ADT/bit.h - C++20 <bit> ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the C++20 <bit> header.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_ADT_BIT_H
#define LLVM_ADT_BIT_H

#include <cstring>
#include <type_traits>

namespace llvm {

template <
typename To, typename From,
typename = typename std::enable_if<sizeof(To) == sizeof(From)>::type,
typename =
typename std::enable_if<std::is_trivially_copyable<To>::value>::type,
typename =
typename std::enable_if<std::is_trivially_copyable<From>::value>::type>
inline To bit_cast(const From &from) noexcept {
typename std::aligned_storage<sizeof(To), alignof(To)>::type storage;
std::memcpy(&storage, &from, sizeof(To));
return reinterpret_cast<To &>(storage);
}

} // namespace llvm

#endif
21 changes: 7 additions & 14 deletions llvm/lib/Support/APInt.cpp
Expand Up @@ -19,6 +19,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/bit.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
Expand Down Expand Up @@ -712,24 +713,20 @@ APInt llvm::APIntOps::GreatestCommonDivisor(APInt A, APInt B) {
}

APInt llvm::APIntOps::RoundDoubleToAPInt(double Double, unsigned width) {
union {
double D;
uint64_t I;
} T;
T.D = Double;
uint64_t I = bit_cast<uint64_t>(Double);

// Get the sign bit from the highest order bit
bool isNeg = T.I >> 63;
bool isNeg = I >> 63;

// Get the 11-bit exponent and adjust for the 1023 bit bias
int64_t exp = ((T.I >> 52) & 0x7ff) - 1023;
int64_t exp = ((I >> 52) & 0x7ff) - 1023;

// If the exponent is negative, the value is < 0 so just return 0.
if (exp < 0)
return APInt(width, 0u);

// Extract the mantissa by clearing the top 12 bits (sign + exponent).
uint64_t mantissa = (T.I & (~0ULL >> 12)) | 1ULL << 52;
uint64_t mantissa = (I & (~0ULL >> 12)) | 1ULL << 52;

// If the exponent doesn't shift all bits out of the mantissa
if (exp < 52)
Expand Down Expand Up @@ -806,12 +803,8 @@ double APInt::roundToDouble(bool isSigned) const {

// The leading bit of mantissa is implicit, so get rid of it.
uint64_t sign = isNeg ? (1ULL << (APINT_BITS_PER_WORD - 1)) : 0;
union {
double D;
uint64_t I;
} T;
T.I = sign | (exp << 52) | mantissa;
return T.D;
uint64_t I = sign | (exp << 52) | mantissa;
return bit_cast<double>(I);
}

// Truncate to new width.
Expand Down
21 changes: 9 additions & 12 deletions llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h
Expand Up @@ -16,6 +16,7 @@

#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/bit.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include <cassert>
Expand Down Expand Up @@ -342,27 +343,23 @@ static inline bool isValidDecodeLogicalImmediate(uint64_t val,
//
static inline float getFPImmFloat(unsigned Imm) {
// We expect an 8-bit binary encoding of a floating-point number here.
union {
uint32_t I;
float F;
} FPUnion;

uint8_t Sign = (Imm >> 7) & 0x1;
uint8_t Exp = (Imm >> 4) & 0x7;
uint8_t Mantissa = Imm & 0xf;

// 8-bit FP iEEEE Float Encoding
// 8-bit FP IEEE Float Encoding
// abcd efgh aBbbbbbc defgh000 00000000 00000000
//
// where B = NOT(b);

FPUnion.I = 0;
FPUnion.I |= Sign << 31;
FPUnion.I |= ((Exp & 0x4) != 0 ? 0 : 1) << 30;
FPUnion.I |= ((Exp & 0x4) != 0 ? 0x1f : 0) << 25;
FPUnion.I |= (Exp & 0x3) << 23;
FPUnion.I |= Mantissa << 19;
return FPUnion.F;
uint32_t I = 0;
I |= Sign << 31;
I |= ((Exp & 0x4) != 0 ? 0 : 1) << 30;
I |= ((Exp & 0x4) != 0 ? 0x1f : 0) << 25;
I |= (Exp & 0x3) << 23;
I |= Mantissa << 19;
return bit_cast<float>(I);
}

/// getFP16Imm - Return an 8-bit floating-point version of the 16-bit
Expand Down
21 changes: 8 additions & 13 deletions llvm/lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h
Expand Up @@ -627,27 +627,22 @@ namespace ARM_AM {
//
inline float getFPImmFloat(unsigned Imm) {
// We expect an 8-bit binary encoding of a floating-point number here.
union {
uint32_t I;
float F;
} FPUnion;

uint8_t Sign = (Imm >> 7) & 0x1;
uint8_t Exp = (Imm >> 4) & 0x7;
uint8_t Mantissa = Imm & 0xf;

// 8-bit FP iEEEE Float Encoding
// 8-bit FP IEEE Float Encoding
// abcd efgh aBbbbbbc defgh000 00000000 00000000
//
// where B = NOT(b);

FPUnion.I = 0;
FPUnion.I |= Sign << 31;
FPUnion.I |= ((Exp & 0x4) != 0 ? 0 : 1) << 30;
FPUnion.I |= ((Exp & 0x4) != 0 ? 0x1f : 0) << 25;
FPUnion.I |= (Exp & 0x3) << 23;
FPUnion.I |= Mantissa << 19;
return FPUnion.F;
uint32_t I = 0;
I |= Sign << 31;
I |= ((Exp & 0x4) != 0 ? 0 : 1) << 30;
I |= ((Exp & 0x4) != 0 ? 0x1f : 0) << 25;
I |= (Exp & 0x3) << 23;
I |= Mantissa << 19;
return bit_cast<float>(F);
}

/// getFP16Imm - Return an 8-bit floating-point version of the 16-bit
Expand Down

0 comments on commit 2865508

Please sign in to comment.