Skip to content

Commit 0a89825

Browse files
committed
[APSInt] Fix bug in APSInt mentioned in #59515
Also provide a `tryExtValue()` API like APInt did in D139683 Reviewed By: RKSimon, efriedma Differential Revision: https://reviews.llvm.org/D140059
1 parent b2b078a commit 0a89825

File tree

4 files changed

+49
-7
lines changed

4 files changed

+49
-7
lines changed

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5401,10 +5401,18 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) {
54015401
llvm::DIExpression *InitExpr = nullptr;
54025402
if (CGM.getContext().getTypeSize(VD->getType()) <= 64) {
54035403
// FIXME: Add a representation for integer constants wider than 64 bits.
5404-
if (Init.isInt())
5405-
InitExpr =
5406-
DBuilder.createConstantValueExpression(Init.getInt().getExtValue());
5407-
else if (Init.isFloat())
5404+
if (Init.isInt()) {
5405+
const llvm::APSInt &InitInt = Init.getInt();
5406+
std::optional<uint64_t> InitIntOpt;
5407+
if (InitInt.isUnsigned())
5408+
InitIntOpt = InitInt.tryZExtValue();
5409+
else if (auto tmp = InitInt.trySExtValue(); tmp.has_value())
5410+
// Transform a signed optional to unsigned optional. When cpp 23 comes,
5411+
// use std::optional::transform
5412+
InitIntOpt = (uint64_t)tmp.value();
5413+
if (InitIntOpt)
5414+
InitExpr = DBuilder.createConstantValueExpression(InitIntOpt.value());
5415+
} else if (Init.isFloat())
54085416
InitExpr = DBuilder.createConstantValueExpression(
54095417
Init.getFloat().bitcastToAPInt().getZExtValue());
54105418
}

llvm/include/llvm/ADT/APSInt.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,26 @@ class [[nodiscard]] APSInt : public APInt {
8585
}
8686
using APInt::toString;
8787

88+
/// If this int is representable using an int64_t.
89+
bool isRepresentableByInt64() const {
90+
// For unsigned values with 64 active bits, they technically fit into a
91+
// int64_t, but the user may get negative numbers and has to manually cast
92+
// them to unsigned. Let's not bet the user has the sanity to do that and
93+
// not give them a vague value at the first place.
94+
return isSigned() ? isSignedIntN(64) : isIntN(63);
95+
}
96+
8897
/// Get the correctly-extended \c int64_t value.
8998
int64_t getExtValue() const {
90-
assert(getMinSignedBits() <= 64 && "Too many bits for int64_t");
99+
assert(isRepresentableByInt64() && "Too many bits for int64_t");
91100
return isSigned() ? getSExtValue() : getZExtValue();
92101
}
93102

103+
std::optional<int64_t> tryExtValue() const {
104+
return isRepresentableByInt64() ? std::optional<int64_t>(getExtValue())
105+
: std::nullopt;
106+
}
107+
94108
APSInt trunc(uint32_t width) const {
95109
return APSInt(APInt::trunc(width), IsUnsigned);
96110
}

llvm/lib/CodeGen/MIRParser/MIParser.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1804,9 +1804,12 @@ bool MIParser::parseRegisterOperand(MachineOperand &Dest,
18041804
bool MIParser::parseImmediateOperand(MachineOperand &Dest) {
18051805
assert(Token.is(MIToken::IntegerLiteral));
18061806
const APSInt &Int = Token.integerValue();
1807-
if (Int.getMinSignedBits() > 64)
1807+
if (auto SImm = Int.trySExtValue(); Int.isSigned() && SImm.has_value())
1808+
Dest = MachineOperand::CreateImm(*SImm);
1809+
else if (auto UImm = Int.tryZExtValue(); !Int.isSigned() && UImm.has_value())
1810+
Dest = MachineOperand::CreateImm(*UImm);
1811+
else
18081812
return error("integer literal is too large to be an immediate operand");
1809-
Dest = MachineOperand::CreateImm(Int.getExtValue());
18101813
lex();
18111814
return false;
18121815
}

llvm/unittests/ADT/APSIntTest.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ TEST(APSIntTest, getUnsigned) {
6262
EXPECT_EQ(UINT64_C(0) - 7, APSInt::getUnsigned(-7).getZExtValue());
6363
}
6464

65+
TEST(APSIntTest, isRepresentableByInt64) {
66+
ASSERT_TRUE(APSInt(APInt(3, 7), true).isRepresentableByInt64());
67+
ASSERT_TRUE(APSInt(APInt(128, 7), true).isRepresentableByInt64());
68+
ASSERT_TRUE(APSInt(APInt(128, 7), false).isRepresentableByInt64());
69+
ASSERT_TRUE(APSInt(APInt(64, -1), false).isRepresentableByInt64());
70+
ASSERT_FALSE(APSInt(APInt(64, (uint64_t)-1), true).isRepresentableByInt64());
71+
}
6572
TEST(APSIntTest, getExtValue) {
6673
EXPECT_TRUE(APSInt(APInt(3, 7), true).isUnsigned());
6774
EXPECT_TRUE(APSInt(APInt(3, 7), false).isSigned());
@@ -76,6 +83,16 @@ TEST(APSIntTest, getExtValue) {
7683
EXPECT_EQ(9, APSInt(APInt(4, -7), true).getExtValue());
7784
EXPECT_EQ(-7, APSInt(APInt(4, -7), false).getExtValue());
7885
}
86+
TEST(APSIntTest, tryExtValue) {
87+
ASSERT_EQ(-7, APSInt(APInt(64, -7), false).tryExtValue().value_or(42));
88+
ASSERT_EQ(42, APSInt(APInt(128, -7), false).tryExtValue().value_or(42));
89+
ASSERT_EQ(-1,
90+
APSInt(APInt::getAllOnes(128), false).tryExtValue().value_or(42));
91+
ASSERT_EQ(42, APSInt(APInt(64, -7), true).tryExtValue().value_or(42));
92+
ASSERT_EQ(1, APSInt(APInt(128, 1), true).tryExtValue().value_or(42));
93+
ASSERT_EQ(42,
94+
APSInt(APInt::getAllOnes(128), true).tryExtValue().value_or(42));
95+
}
7996

8097
TEST(APSIntTest, compareValues) {
8198
auto U = [](uint64_t V) { return APSInt::getUnsigned(V); };

0 commit comments

Comments
 (0)