385 lines · c
1//===--- Integral.h - Wrapper for numeric types for the VM ------*- C++ -*-===//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// Defines the VM types and helpers operating on types.10//11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H14#define LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H15 16#include "clang/AST/APValue.h"17#include "clang/AST/ComparisonCategories.h"18#include "llvm/ADT/APSInt.h"19#include "llvm/Support/MathExtras.h"20#include "llvm/Support/raw_ostream.h"21#include <cstddef>22#include <cstdint>23 24#include "Primitives.h"25 26namespace clang {27namespace interp {28 29using APInt = llvm::APInt;30using APSInt = llvm::APSInt;31 32/// If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.33/// It will NOT copy the memory (unless, of course, copy() is called) and it34/// won't alllocate anything. The allocation should happen via InterpState or35/// Program.36template <bool Signed> class IntegralAP final {37public:38 union {39 uint64_t *Memory = nullptr;40 uint64_t Val;41 };42 uint32_t BitWidth = 0;43 friend IntegralAP<!Signed>;44 45 template <typename T, bool InputSigned>46 static T truncateCast(const APInt &V) {47 constexpr unsigned BitSize = sizeof(T) * 8;48 if (BitSize >= V.getBitWidth()) {49 APInt Extended;50 if constexpr (InputSigned)51 Extended = V.sext(BitSize);52 else53 Extended = V.zext(BitSize);54 return std::is_signed_v<T> ? Extended.getSExtValue()55 : Extended.getZExtValue();56 }57 58 return std::is_signed_v<T> ? V.trunc(BitSize).getSExtValue()59 : V.trunc(BitSize).getZExtValue();60 }61 62 APInt getValue() const {63 if (singleWord())64 return APInt(BitWidth, Val, Signed);65 unsigned NumWords = llvm::APInt::getNumWords(BitWidth);66 return llvm::APInt(BitWidth, llvm::ArrayRef(Memory, NumWords));67 }68 69public:70 using AsUnsigned = IntegralAP<false>;71 72 void take(uint64_t *NewMemory) {73 assert(!singleWord());74 std::memcpy(NewMemory, Memory, numWords() * sizeof(uint64_t));75 Memory = NewMemory;76 }77 78 void copy(const APInt &V) {79 assert(BitWidth == V.getBitWidth());80 assert(numWords() == V.getNumWords());81 82 if (V.isSingleWord()) {83 if constexpr (Signed)84 Val = V.getSExtValue();85 else86 Val = V.getZExtValue();87 return;88 }89 assert(Memory);90 std::memcpy(Memory, V.getRawData(), V.getNumWords() * sizeof(uint64_t));91 }92 93 IntegralAP() = default;94 /// Zeroed, single-word IntegralAP of the given bitwidth.95 IntegralAP(unsigned BitWidth) : Val(0), BitWidth(BitWidth) {96 assert(singleWord());97 }98 IntegralAP(uint64_t *Memory, unsigned BitWidth)99 : Memory(Memory), BitWidth(BitWidth) {}100 IntegralAP(const APInt &V) : BitWidth(V.getBitWidth()) {101 if (V.isSingleWord()) {102 Val = Signed ? V.getSExtValue() : V.getZExtValue();103 } else {104 Memory = const_cast<uint64_t *>(V.getRawData());105 }106 }107 108 IntegralAP operator-() const { return IntegralAP(-getValue()); }109 bool operator>(const IntegralAP &RHS) const {110 if constexpr (Signed)111 return getValue().sgt(RHS.getValue());112 return getValue().ugt(RHS.getValue());113 }114 bool operator>=(unsigned RHS) const {115 if constexpr (Signed)116 return getValue().sge(RHS);117 return getValue().uge(RHS);118 }119 bool operator<(IntegralAP RHS) const {120 if constexpr (Signed)121 return getValue().slt(RHS.getValue());122 return getValue().ult(RHS.getValue());123 }124 125 template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>126 explicit operator Ty() const {127 return truncateCast<Ty, Signed>(getValue());128 }129 130 template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) {131 if (NumBits == 0)132 NumBits = sizeof(T) * 8;133 assert(NumBits > 0);134 assert(APInt::getNumWords(NumBits) == 1);135 APInt Copy = APInt(NumBits, static_cast<uint64_t>(Value), Signed);136 return IntegralAP<Signed>(Copy);137 }138 139 constexpr uint32_t bitWidth() const { return BitWidth; }140 constexpr unsigned numWords() const { return APInt::getNumWords(BitWidth); }141 constexpr bool singleWord() const { return numWords() == 1; }142 143 APSInt toAPSInt(unsigned Bits = 0) const {144 if (Bits == 0)145 Bits = bitWidth();146 147 APInt V = getValue();148 if constexpr (Signed)149 return APSInt(getValue().sext(Bits), !Signed);150 else151 return APSInt(getValue().zext(Bits), !Signed);152 }153 APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }154 155 bool isZero() const { return getValue().isZero(); }156 bool isPositive() const {157 if constexpr (Signed)158 return getValue().isNonNegative();159 return true;160 }161 bool isNegative() const {162 if constexpr (Signed)163 return !getValue().isNonNegative();164 return false;165 }166 bool isMin() const {167 if constexpr (Signed)168 return getValue().isMinSignedValue();169 return getValue().isMinValue();170 }171 bool isMax() const {172 if constexpr (Signed)173 return getValue().isMaxSignedValue();174 return getValue().isMaxValue();175 }176 static constexpr bool isSigned() { return Signed; }177 bool isMinusOne() const { return Signed && getValue().isAllOnes(); }178 179 unsigned countLeadingZeros() const { return getValue().countl_zero(); }180 181 void print(llvm::raw_ostream &OS) const { getValue().print(OS, Signed); }182 std::string toDiagnosticString(const ASTContext &Ctx) const {183 std::string NameStr;184 llvm::raw_string_ostream OS(NameStr);185 print(OS);186 return NameStr;187 }188 189 IntegralAP truncate(unsigned BitWidth) const {190 if constexpr (Signed)191 return IntegralAP(192 getValue().trunc(BitWidth).sextOrTrunc(this->bitWidth()));193 else194 return IntegralAP(195 getValue().trunc(BitWidth).zextOrTrunc(this->bitWidth()));196 }197 198 IntegralAP<false> toUnsigned() const {199 return IntegralAP<false>(Memory, BitWidth);200 }201 202 void bitcastToMemory(std::byte *Dest) const {203 llvm::StoreIntToMemory(getValue(), (uint8_t *)Dest, bitWidth() / 8);204 }205 206 static void bitcastFromMemory(const std::byte *Src, unsigned BitWidth,207 IntegralAP *Result) {208 APInt V(BitWidth, static_cast<uint64_t>(0), Signed);209 llvm::LoadIntFromMemory(V, (const uint8_t *)Src, BitWidth / 8);210 Result->copy(V);211 }212 213 ComparisonCategoryResult compare(const IntegralAP &RHS) const {214 assert(Signed == RHS.isSigned());215 assert(bitWidth() == RHS.bitWidth());216 APInt V1 = getValue();217 APInt V2 = RHS.getValue();218 if constexpr (Signed) {219 if (V1.slt(V2))220 return ComparisonCategoryResult::Less;221 if (V1.sgt(V2))222 return ComparisonCategoryResult::Greater;223 return ComparisonCategoryResult::Equal;224 }225 226 assert(!Signed);227 if (V1.ult(V2))228 return ComparisonCategoryResult::Less;229 if (V1.ugt(V2))230 return ComparisonCategoryResult::Greater;231 return ComparisonCategoryResult::Equal;232 }233 234 static bool increment(IntegralAP A, IntegralAP *R) {235 APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed);236 return add(A, IntegralAP<Signed>(One), A.bitWidth() + 1, R);237 }238 239 static bool decrement(IntegralAP A, IntegralAP *R) {240 APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed);241 return sub(A, IntegralAP<Signed>(One), A.bitWidth() + 1, R);242 }243 244 static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {245 return CheckAddSubMulUB<std::plus>(A, B, OpBits, R);246 }247 248 static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {249 return CheckAddSubMulUB<std::minus>(A, B, OpBits, R);250 }251 252 static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {253 return CheckAddSubMulUB<std::multiplies>(A, B, OpBits, R);254 }255 256 static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {257 if constexpr (Signed)258 R->copy(A.getValue().srem(B.getValue()));259 else260 R->copy(A.getValue().urem(B.getValue()));261 return false;262 }263 264 static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {265 if constexpr (Signed)266 R->copy(A.getValue().sdiv(B.getValue()));267 else268 R->copy(A.getValue().udiv(B.getValue()));269 return false;270 }271 272 static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits,273 IntegralAP *R) {274 R->copy(A.getValue() & B.getValue());275 return false;276 }277 278 static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits,279 IntegralAP *R) {280 R->copy(A.getValue() | B.getValue());281 return false;282 }283 284 static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits,285 IntegralAP *R) {286 R->copy(A.getValue() ^ B.getValue());287 return false;288 }289 290 static bool neg(const IntegralAP &A, IntegralAP *R) {291 APInt AI = A.getValue();292 AI.negate();293 R->copy(AI);294 return false;295 }296 297 static bool comp(IntegralAP A, IntegralAP *R) {298 R->copy(~A.getValue());299 return false;300 }301 302 static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits,303 IntegralAP *R) {304 *R = IntegralAP(A.getValue().shl(B.getValue().getZExtValue()));305 }306 307 static void shiftRight(const IntegralAP A, const IntegralAP B,308 unsigned OpBits, IntegralAP *R) {309 unsigned ShiftAmount = B.getValue().getZExtValue();310 if constexpr (Signed)311 R->copy(A.getValue().ashr(ShiftAmount));312 else313 R->copy(A.getValue().lshr(ShiftAmount));314 }315 316 // === Serialization support ===317 size_t bytesToSerialize() const {318 assert(BitWidth != 0);319 return sizeof(uint32_t) + (numWords() * sizeof(uint64_t));320 }321 322 void serialize(std::byte *Buff) const {323 std::memcpy(Buff, &BitWidth, sizeof(uint32_t));324 if (singleWord())325 std::memcpy(Buff + sizeof(uint32_t), &Val, sizeof(uint64_t));326 else {327 std::memcpy(Buff + sizeof(uint32_t), Memory,328 numWords() * sizeof(uint64_t));329 }330 }331 332 static uint32_t deserializeSize(const std::byte *Buff) {333 return *reinterpret_cast<const uint32_t *>(Buff);334 }335 336 static void deserialize(const std::byte *Buff, IntegralAP<Signed> *Result) {337 uint32_t BitWidth = Result->BitWidth;338 assert(BitWidth != 0);339 unsigned NumWords = llvm::APInt::getNumWords(BitWidth);340 341 if (NumWords == 1)342 std::memcpy(&Result->Val, Buff + sizeof(uint32_t), sizeof(uint64_t));343 else {344 assert(Result->Memory);345 std::memcpy(Result->Memory, Buff + sizeof(uint32_t),346 NumWords * sizeof(uint64_t));347 }348 }349 350private:351 template <template <typename T> class Op>352 static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B,353 unsigned BitWidth, IntegralAP *R) {354 if constexpr (!Signed) {355 R->copy(Op<APInt>{}(A.getValue(), B.getValue()));356 return false;357 }358 359 const APSInt &LHS = A.toAPSInt();360 const APSInt &RHS = B.toAPSInt();361 APSInt Value = Op<APSInt>{}(LHS.extend(BitWidth), RHS.extend(BitWidth));362 APSInt Result = Value.trunc(LHS.getBitWidth());363 R->copy(Result);364 365 return Result.extend(BitWidth) != Value;366 }367};368 369template <bool Signed>370inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,371 IntegralAP<Signed> I) {372 I.print(OS);373 return OS;374}375 376template <bool Signed>377IntegralAP<Signed> getSwappedBytes(IntegralAP<Signed> F) {378 return F;379}380 381} // namespace interp382} // namespace clang383 384#endif385