-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang][Interp] Add IntegralAP for arbitrary-precision integers #65844
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
0d879e0
[clang][Interp] Add IntegralAP for arbitrary-precision integers
tbaederr 1445cfb
Address review comments
tbaederr d5894a4
Handle ::from for unsigned inputs
tbaederr 30b1577
Add more casting tests
tbaederr 2003a75
Make ::increment() actually increment.
tbaederr 3f07850
Add more assert(false)
tbaederr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,256 @@ | ||
//===--- Integral.h - Wrapper for numeric types for the VM ------*- 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Defines the VM types and helpers operating on types. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H | ||
#define LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H | ||
|
||
#include "clang/AST/APValue.h" | ||
#include "clang/AST/ComparisonCategories.h" | ||
#include "llvm/ADT/APSInt.h" | ||
#include "llvm/Support/MathExtras.h" | ||
#include "llvm/Support/raw_ostream.h" | ||
#include <cstddef> | ||
#include <cstdint> | ||
|
||
#include "Primitives.h" | ||
|
||
namespace clang { | ||
namespace interp { | ||
|
||
using APInt = llvm::APInt; | ||
using APSInt = llvm::APSInt; | ||
template <unsigned Bits, bool Signed> class Integral; | ||
class Boolean; | ||
|
||
template <bool Signed> class IntegralAP final { | ||
public: | ||
APSInt V; | ||
|
||
public: | ||
using AsUnsigned = IntegralAP<false>; | ||
|
||
template <typename T> | ||
IntegralAP(T Value) : V(APInt(sizeof(T) * 8, Value, std::is_signed_v<T>)) {} | ||
|
||
IntegralAP(APInt V) : V(V) {} | ||
IntegralAP(APSInt V) : V(V) {} | ||
/// Arbitrary value for initialized variables. | ||
IntegralAP() : V(APSInt::getMaxValue(1024, Signed)) {} | ||
|
||
IntegralAP operator-() const { return IntegralAP(-V); } | ||
bool operator>(IntegralAP RHS) const { return V > RHS.V; } | ||
bool operator>=(IntegralAP RHS) const { return V >= RHS.V; } | ||
bool operator<(IntegralAP RHS) const { return V < RHS.V; } | ||
bool operator<=(IntegralAP RHS) const { return V <= RHS.V; } | ||
|
||
explicit operator bool() const { return !V.isZero(); } | ||
explicit operator int8_t() const { return V.getSExtValue(); } | ||
explicit operator uint8_t() const { return V.getZExtValue(); } | ||
explicit operator int16_t() const { return V.getSExtValue(); } | ||
explicit operator uint16_t() const { return V.getZExtValue(); } | ||
explicit operator int32_t() const { return V.getSExtValue(); } | ||
explicit operator uint32_t() const { return V.getZExtValue(); } | ||
explicit operator int64_t() const { return V.getSExtValue(); } | ||
explicit operator uint64_t() const { return V.getZExtValue(); } | ||
|
||
template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) { | ||
assert(NumBits > 0); | ||
APSInt Copy = APSInt(APInt(NumBits, Value, Signed), !Signed); | ||
|
||
return IntegralAP<Signed>(Copy); | ||
} | ||
|
||
template <bool InputSigned> | ||
static IntegralAP from(IntegralAP<InputSigned> V, unsigned NumBits = 0) { | ||
if constexpr (Signed == InputSigned) | ||
return V; | ||
|
||
APSInt Copy = V.V; | ||
Copy.setIsSigned(Signed); | ||
|
||
return IntegralAP<Signed>(Copy); | ||
} | ||
|
||
template <unsigned Bits, bool InputSigned> | ||
static IntegralAP from(Integral<Bits, InputSigned> I) { | ||
// FIXME: Take bits parameter. | ||
APSInt Copy = | ||
APSInt(APInt(128, static_cast<int64_t>(I), InputSigned), !Signed); | ||
Copy.setIsSigned(Signed); | ||
|
||
assert(Copy.isSigned() == Signed); | ||
return IntegralAP<Signed>(Copy); | ||
} | ||
static IntegralAP from(const Boolean &B) { | ||
assert(false); | ||
return IntegralAP::zero(); | ||
} | ||
|
||
static IntegralAP zero() { | ||
assert(false); | ||
return IntegralAP(0); | ||
} | ||
|
||
// FIXME: This can't be static if the bitwidth depends on V. | ||
static constexpr unsigned bitWidth() { return 128; } | ||
|
||
APSInt toAPSInt(unsigned Bits = 0) const { return V; } | ||
APValue toAPValue() const { return APValue(V); } | ||
|
||
bool isZero() const { return V.isZero(); } | ||
bool isPositive() const { return V.isNonNegative(); } | ||
bool isNegative() const { return !V.isNonNegative(); } | ||
bool isMin() const { return V.isMinValue(); } | ||
bool isMax() const { return V.isMaxValue(); } | ||
static bool isSigned() { return Signed; } | ||
bool isMinusOne() const { return Signed && V == -1; } | ||
|
||
unsigned countLeadingZeros() const { return V.countl_zero(); } | ||
|
||
void print(llvm::raw_ostream &OS) const { OS << V; } | ||
|
||
IntegralAP truncate(unsigned bitWidth) const { | ||
assert(false); | ||
return V; | ||
} | ||
|
||
IntegralAP<false> toUnsigned() const { | ||
APSInt Copy = V; | ||
Copy.setIsSigned(false); | ||
return IntegralAP<false>(Copy); | ||
} | ||
|
||
ComparisonCategoryResult compare(const IntegralAP &RHS) const { | ||
return Compare(V, RHS.V); | ||
} | ||
|
||
static bool increment(IntegralAP A, IntegralAP *R) { | ||
assert(false); | ||
*R = IntegralAP(A.V + 1); | ||
return false; | ||
} | ||
|
||
static bool decrement(IntegralAP A, IntegralAP *R) { | ||
assert(false); | ||
*R = IntegralAP(A.V - 1); | ||
return false; | ||
} | ||
|
||
static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { | ||
return CheckAddUB(A, B, OpBits, R); | ||
} | ||
|
||
static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { | ||
/// FIXME: Gotta check if the result fits into OpBits bits. | ||
return CheckSubUB(A, B, R); | ||
} | ||
|
||
static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { | ||
assert(false); | ||
// return CheckMulUB(A.V, B.V, R->V); | ||
return false; | ||
} | ||
|
||
static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { | ||
assert(false); | ||
*R = IntegralAP(A.V % B.V); | ||
return false; | ||
} | ||
|
||
static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { | ||
assert(false); | ||
*R = IntegralAP(A.V / B.V); | ||
return false; | ||
} | ||
|
||
static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits, | ||
IntegralAP *R) { | ||
assert(false); | ||
*R = IntegralAP(A.V & B.V); | ||
return false; | ||
} | ||
|
||
static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits, | ||
IntegralAP *R) { | ||
assert(false); | ||
*R = IntegralAP(A.V | B.V); | ||
return false; | ||
} | ||
|
||
static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits, | ||
IntegralAP *R) { | ||
assert(false); | ||
*R = IntegralAP(A.V ^ B.V); | ||
return false; | ||
} | ||
|
||
static bool neg(const IntegralAP &A, IntegralAP *R) { | ||
APSInt AI = A.V; | ||
|
||
AI.setIsSigned(Signed); | ||
*R = IntegralAP(AI); | ||
return false; | ||
} | ||
|
||
static bool comp(IntegralAP A, IntegralAP *R) { | ||
assert(false); | ||
*R = IntegralAP(~A.V); | ||
return false; | ||
} | ||
|
||
static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits, | ||
IntegralAP *R) { | ||
*R = IntegralAP(A.V << B.V.getZExtValue()); | ||
} | ||
|
||
static void shiftRight(const IntegralAP A, const IntegralAP B, | ||
unsigned OpBits, IntegralAP *R) { | ||
*R = IntegralAP(A.V >> B.V.getZExtValue()); | ||
} | ||
|
||
private: | ||
static bool CheckAddUB(const IntegralAP &A, const IntegralAP &B, | ||
unsigned BitWidth, IntegralAP *R) { | ||
if (!A.isSigned()) { | ||
R->V = A.V + B.V; | ||
return false; | ||
} | ||
|
||
const APSInt &LHS = A.V; | ||
const APSInt &RHS = B.V; | ||
|
||
APSInt Value(LHS.extend(BitWidth) + RHS.extend(BitWidth), false); | ||
APSInt Result = Value.trunc(LHS.getBitWidth()); | ||
if (Result.extend(BitWidth) != Value) | ||
return true; | ||
|
||
R->V = Result; | ||
return false; | ||
} | ||
static bool CheckSubUB(const IntegralAP &A, const IntegralAP &B, | ||
IntegralAP *R) { | ||
R->V = A.V - B.V; | ||
return false; // Success! | ||
} | ||
}; | ||
|
||
template <bool Signed> | ||
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, | ||
IntegralAP<Signed> I) { | ||
I.print(OS); | ||
return OS; | ||
} | ||
|
||
} // namespace interp | ||
} // namespace clang | ||
|
||
#endif |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be an
llvm_unreachable
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the
assert(false)
in this patch are just placeholders for things I need to implement in later patches. I'm trying to keep the patches smaller so they are easier to review.