Skip to content

Commit 2d70a03

Browse files
committed
[NFC] Improve the interfaces for integer widths and parsing integers
1 parent 4d2b513 commit 2d70a03

File tree

7 files changed

+107
-61
lines changed

7 files changed

+107
-61
lines changed

include/swift/AST/Expr.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -789,10 +789,12 @@ class IntegerLiteralExpr : public NumberLiteralExpr {
789789
static IntegerLiteralExpr *
790790
createFromUnsigned(ASTContext &C, unsigned value);
791791

792+
/// Returns the value of the literal, appropriately constructed in the
793+
/// target type.
792794
APInt getValue() const;
793-
static APInt getValue(StringRef Text, unsigned BitWidth, bool Negative);
794795

795-
APInt getRawMagnitude() const;
796+
/// Returns the raw value of the literal without any truncation.
797+
APInt getRawValue() const;
796798

797799
static bool classof(const Expr *E) {
798800
return E->getKind() == ExprKind::IntegerLiteral;

include/swift/AST/Types.h

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,13 +1346,17 @@ END_CAN_TYPE_WRAPPER(BuiltinVectorType, BuiltinType)
13461346
class BuiltinIntegerWidth {
13471347
/// Tag values for abstract integer sizes.
13481348
enum : unsigned {
1349-
Least_SpecialValue = ~2U,
1349+
/// Inhabitants stolen for use as DenseMap special values.
1350+
DenseMapEmpty = ~0U,
1351+
DenseMapTombstone = ~1U,
1352+
1353+
/// An arbitrary-precision integer.
1354+
ArbitraryWidth = ~2U,
1355+
13501356
/// The size of a pointer on the target system.
1351-
PointerWidth = ~0U,
1357+
PointerWidth = ~3U,
13521358

1353-
/// Inhabitants stolen for use as DenseMap special values.
1354-
DenseMapEmpty = ~1U,
1355-
DenseMapTombstone = ~2U,
1359+
Least_SpecialValue = ~3U,
13561360
};
13571361

13581362
unsigned RawValue;
@@ -1372,6 +1376,10 @@ class BuiltinIntegerWidth {
13721376
static BuiltinIntegerWidth pointer() {
13731377
return BuiltinIntegerWidth(PointerWidth);
13741378
}
1379+
1380+
static BuiltinIntegerWidth arbitrary() {
1381+
return BuiltinIntegerWidth(ArbitraryWidth);
1382+
}
13751383

13761384
/// Is this a fixed width?
13771385
bool isFixedWidth() const { return RawValue < Least_SpecialValue; }
@@ -1384,6 +1392,9 @@ class BuiltinIntegerWidth {
13841392

13851393
/// Is this the abstract target pointer width?
13861394
bool isPointerWidth() const { return RawValue == PointerWidth; }
1395+
1396+
/// Is this the abstract arbitrary-width value?
1397+
bool isArbitraryWidth() const { return RawValue == ArbitraryWidth; }
13871398

13881399
/// Get the least supported value for the width.
13891400
///
@@ -1393,6 +1404,8 @@ class BuiltinIntegerWidth {
13931404
return getFixedWidth();
13941405
if (isPointerWidth())
13951406
return 32;
1407+
if (isArbitraryWidth())
1408+
return 1;
13961409
llvm_unreachable("impossible width value");
13971410
}
13981411

@@ -1404,8 +1417,16 @@ class BuiltinIntegerWidth {
14041417
return getFixedWidth();
14051418
if (isPointerWidth())
14061419
return 64;
1420+
if (isArbitraryWidth())
1421+
return ~0U;
14071422
llvm_unreachable("impossible width value");
14081423
}
1424+
1425+
/// Parse a value of this bit-width.
1426+
///
1427+
/// If the radix is 0, it is autosensed.
1428+
APInt parse(StringRef text, unsigned radix, bool negate,
1429+
bool *hadError = nullptr) const;
14091430

14101431
friend bool operator==(BuiltinIntegerWidth a, BuiltinIntegerWidth b) {
14111432
return a.RawValue == b.RawValue;
@@ -1440,7 +1461,8 @@ class BuiltinIntegerType : public BuiltinType {
14401461
return get(BuiltinIntegerWidth::pointer(), C);
14411462
}
14421463

1443-
/// Return the bit width of the integer.
1464+
/// Return the bit width of the integer. Always returns a non-arbitrary
1465+
/// width.
14441466
BuiltinIntegerWidth getWidth() const {
14451467
return Width;
14461468
}

lib/AST/ASTContext.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3032,6 +3032,7 @@ Type ErrorType::get(Type originalType) {
30323032

30333033
BuiltinIntegerType *BuiltinIntegerType::get(BuiltinIntegerWidth BitWidth,
30343034
const ASTContext &C) {
3035+
assert(!BitWidth.isArbitraryWidth());
30353036
BuiltinIntegerType *&Result = C.getImpl().IntegerTypes[BitWidth];
30363037
if (Result == nullptr)
30373038
Result = new (C, AllocationArena::Permanent) BuiltinIntegerType(BitWidth,C);

lib/AST/Expr.cpp

Lines changed: 69 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -849,46 +849,81 @@ IntegerLiteralExpr * IntegerLiteralExpr::createFromUnsigned(ASTContext &C, unsig
849849
return new (C) IntegerLiteralExpr(Text, SourceLoc(), /*implicit*/ true);
850850
}
851851

852-
/// A wrapper around LLVM::getAsInteger that can be used on Swift interger
853-
/// literals. It avoids misinterpreting decimal numbers prefixed with 0 as
854-
/// octal numbers.
855-
static bool getAsInteger(StringRef Text, llvm::APInt &Value) {
856-
// swift encodes octal differently from C
857-
bool IsCOctal = Text.size() > 1 && Text[0] == '0' && isdigit(Text[1]);
858-
return Text.getAsInteger(IsCOctal ? 10 : 0, Value);
852+
APInt IntegerLiteralExpr::getRawValue() const {
853+
return BuiltinIntegerWidth::arbitrary().parse(getDigitsText(), /*radix*/0,
854+
isNegative());
859855
}
860856

861-
static APInt getIntegerLiteralValue(bool IsNegative, StringRef Text,
862-
unsigned BitWidth) {
863-
llvm::APInt Value(BitWidth, 0);
864-
bool Error = getAsInteger(Text, Value);
865-
assert(!Error && "Invalid IntegerLiteral formed"); (void)Error;
866-
if (IsNegative)
867-
Value = -Value;
868-
if (Value.getBitWidth() != BitWidth)
869-
Value = Value.sextOrTrunc(BitWidth);
870-
return Value;
857+
APInt IntegerLiteralExpr::getValue() const {
858+
assert(!getType().isNull() && "Semantic analysis has not completed");
859+
assert(!getType()->hasError() && "Should have a valid type");
860+
auto width = getType()->castTo<BuiltinIntegerType>()->getWidth();
861+
return width.parse(getDigitsText(), /*radix*/ 0, isNegative());
871862
}
872863

873-
APInt IntegerLiteralExpr::getValue(StringRef Text, unsigned BitWidth, bool Negative) {
874-
return getIntegerLiteralValue(Negative, Text, BitWidth);
875-
}
864+
APInt BuiltinIntegerWidth::parse(StringRef text, unsigned radix, bool negate,
865+
bool *hadError) const {
866+
if (hadError) *hadError = false;
876867

877-
/// Returns the raw magnitude of the literal text without any truncation.
878-
APInt IntegerLiteralExpr::getRawMagnitude() const {
879-
llvm::APInt Value(64, 0);
880-
bool Error = getAsInteger(getDigitsText(), Value);
881-
assert(!Error && "Invalid IntegerLiteral formed");
882-
(void)Error;
883-
return Value;
884-
}
868+
// Parse an unsigned value from the string.
869+
APInt value;
885870

886-
APInt IntegerLiteralExpr::getValue() const {
887-
assert(!getType().isNull() && "Semantic analysis has not completed");
888-
assert(!getType()->hasError() && "Should have a valid type");
889-
return getIntegerLiteralValue(
890-
isNegative(), getDigitsText(),
891-
getType()->castTo<BuiltinIntegerType>()->getGreatestWidth());
871+
// Swift doesn't treat a leading zero as signifying octal, but
872+
// StringRef::getAsInteger does. Force decimal parsing in this case.
873+
if (radix == 0 && text.size() >= 2 && text[0] == '0' && isdigit(text[1]))
874+
radix = 10;
875+
876+
bool error = text.getAsInteger(radix, value);
877+
if (error) {
878+
if (hadError) *hadError = true;
879+
return value;
880+
}
881+
882+
// If we're producing an arbitrary-precision value, we don't need to do
883+
// much additional processing.
884+
if (isArbitraryWidth()) {
885+
// The parser above always produces a non-negative value, so if the sign
886+
// bit is set we need to give it some breathing room.
887+
if (value.isNegative())
888+
value = value.zext(value.getBitWidth() + 1);
889+
assert(!value.isNegative());
890+
891+
// Now we can safely negate.
892+
if (negate) {
893+
value = -value;
894+
assert(value.isNegative() || value.isNullValue());
895+
}
896+
897+
// Truncate down to the minimum number of bits required to express
898+
// this value exactly.
899+
auto requiredBits = value.getMinSignedBits();
900+
if (value.getBitWidth() > requiredBits)
901+
value = value.trunc(requiredBits);
902+
903+
// If we have a fixed-width type (including abstract ones), we need to do
904+
// fixed-width transformations, which can overflow.
905+
} else {
906+
unsigned width = getGreatestWidth();
907+
908+
// The overflow diagnostics in this case can't be fully correct because
909+
// we don't know whether we're supposed to be producing a signed number
910+
// or an unsigned one.
911+
912+
if (hadError && value.getActiveBits() > width)
913+
*hadError = true;
914+
value = value.zextOrTrunc(width);
915+
916+
if (negate) {
917+
value = -value;
918+
919+
if (hadError && !value.isNegative())
920+
*hadError = true;
921+
}
922+
923+
assert(value.getBitWidth() == width);
924+
}
925+
926+
return value;
892927
}
893928

894929
static APFloat getFloatLiteralValue(bool IsNegative, StringRef Text,

lib/IRGen/GenEnum.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,9 +1077,9 @@ namespace {
10771077
auto intExpr = cast<IntegerLiteralExpr>(target->getRawValueExpr());
10781078
auto intType = getDiscriminatorType();
10791079

1080-
APInt intValue = IntegerLiteralExpr::getValue(intExpr->getDigitsText(),
1081-
intType->getBitWidth(),
1082-
intExpr->isNegative());
1080+
APInt intValue =
1081+
BuiltinIntegerWidth::fixed(intType->getBitWidth())
1082+
.parse(intExpr->getDigitsText(), /*radix*/ 0, intExpr->isNegative());
10831083

10841084
return intValue.getZExtValue();
10851085
}

lib/Sema/CSGen.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,17 +1220,7 @@ namespace {
12201220
if (IntegerLiteralExpr *intLit = dyn_cast<IntegerLiteralExpr>(expr)) {
12211221
unsigned maxWidth =
12221222
maxIntType->castTo<BuiltinIntegerType>()->getGreatestWidth();
1223-
APInt magnitude = intLit->getRawMagnitude();
1224-
unsigned magWidth = magnitude.getActiveBits();
1225-
bool isNegative = intLit->isNegative();
1226-
1227-
// Compute the literal bit width in the signed two's complement form.
1228-
// This is generally one more than the magnitude width, but is the
1229-
// same when the literal is of the form -2^i (for some Nat `i`).
1230-
unsigned signedLitWidth =
1231-
(isNegative && (magnitude.countTrailingZeros() == magWidth - 1))
1232-
? magWidth
1233-
: (magWidth + 1);
1223+
unsigned signedLitWidth = intLit->getRawValue().getMinSignedBits();
12341224

12351225
if (signedLitWidth > maxWidth) { // overflow?
12361226
CS.TC.diagnose(expr->getLoc(),

lib/Sema/TypeCheckSwitchStmt.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -870,12 +870,8 @@ namespace {
870870
return !cacheVal.second;
871871
}
872872
case ExprKind::IntegerLiteral: {
873-
// FIXME: The magic number 128 is bad and we should actually figure out
874-
// the bitwidth. But it's too early in Sema to get it.
875873
auto *ILE = cast<IntegerLiteralExpr>(EL);
876-
auto cacheVal =
877-
IntLiteralCache.insert(
878-
{ILE->getValue(ILE->getDigitsText(), 128, ILE->isNegative()), ILE});
874+
auto cacheVal = IntLiteralCache.insert({ILE->getRawValue(), ILE});
879875
PrevPattern = (cacheVal.first != IntLiteralCache.end())
880876
? cacheVal.first->getSecond()
881877
: nullptr;

0 commit comments

Comments
 (0)