Skip to content

Commit

Permalink
Clang16 supports literals for wide integers
Browse files Browse the repository at this point in the history
  • Loading branch information
frabert committed Apr 29, 2024
1 parent 07aee0c commit 8930adf
Show file tree
Hide file tree
Showing 5 changed files with 10 additions and 113 deletions.
14 changes: 4 additions & 10 deletions include/rellic/AST/ASTBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,24 @@ class ASTBuilder {
clang::QualType GetLeastIntTypeForBitWidth(unsigned size, unsigned sign);
clang::QualType GetLeastRealTypeForBitWidth(unsigned size);
// Literals
clang::Expr *CreateIntLit(llvm::APSInt val);
clang::IntegerLiteral *CreateIntLit(llvm::APSInt val);

clang::Expr *CreateIntLit(llvm::APInt val) {
clang::IntegerLiteral *CreateIntLit(llvm::APInt val) {
return CreateIntLit(llvm::APSInt(val, /*isUnsigned=*/true));
};

clang::Expr *CreateTrue() {
clang::IntegerLiteral *CreateTrue() {
return CreateIntLit(llvm::APInt(/*numBits=*/1U, /*val*/ 1U));
};

clang::Expr *CreateFalse() {
clang::IntegerLiteral *CreateFalse() {
return CreateIntLit(llvm::APInt(/*numBits=*/1U, /*val*/ 0U));
};

clang::CharacterLiteral *CreateCharLit(llvm::APInt val);
clang::CharacterLiteral *CreateCharLit(unsigned val);
clang::StringLiteral *CreateStrLit(std::string val);
clang::Expr *CreateFPLit(llvm::APFloat val);
// Casted literals
clang::Expr *CreateAdjustedIntLit(llvm::APSInt val);

clang::Expr *CreateAdjustedIntLit(llvm::APInt val) {
return CreateAdjustedIntLit(llvm::APSInt(val, /*isUnsigned=*/true));
};
// Special values
clang::Expr *CreateNull();
clang::Expr *CreateUndefPointer(clang::QualType type);
Expand Down
49 changes: 2 additions & 47 deletions lib/AST/ASTBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,46 +133,17 @@ clang::QualType ASTBuilder::GetLeastRealTypeForBitWidth(unsigned size) {
return clang::QualType();
}

clang::Expr *ASTBuilder::CreateIntLit(llvm::APSInt val) {
clang::IntegerLiteral *ASTBuilder::CreateIntLit(llvm::APSInt val) {
auto sign{val.isSigned()};
auto value_size{val.getBitWidth()};
// Infer integer type wide enough to accommodate the value,
// with `unsigned int` being the smallest type allowed.
auto llsize{ctx.getIntWidth(ctx.LongLongTy)};
clang::QualType type;
if (value_size <= ctx.getIntWidth(ctx.IntTy)) {
type = sign ? ctx.IntTy : ctx.UnsignedIntTy;
} else if (value_size > ctx.getIntWidth(ctx.LongLongTy)) {
type = sign ? ctx.LongLongTy : ctx.UnsignedLongLongTy;
} else {
type = GetLeastIntTypeForBitWidth(value_size, sign);
}

// C doesn't have a literal suffix for integers wider than a long long.
// If we encounter such a case, try to either
// a) truncate it if the number of significant bits allows it, then cast to
// an appropriate size, or
// b) split it into chunks, then cast shift and merge
// into a value.
if (val.getSignificantBits() > llsize) {
clang::Expr *res{};
for (size_t i = 0; i < value_size / llsize; ++i) {
auto part{CreateCStyleCast(type, CreateIntLit(val.extOrTrunc(llsize)))};
val = val >> llsize;
if (res) {
res = CreateOr(
res,
CreateShl(part, CreateIntLit(llvm::APInt(32, i * llsize, true))));
} else {
res = part;
}
}
return CHECK_NOTNULL(res);
} else if (value_size > llsize) {
val = val.trunc(llsize);
auto lit = CreateIntLit(val);
return CreateCStyleCast(type, lit);
}
// Extend the literal value based on it's sign if we have a
// mismatch between the bit width of the value and inferred type.
auto type_size{ctx.getIntWidth(type)};
Expand All @@ -182,26 +153,10 @@ clang::Expr *ASTBuilder::CreateIntLit(llvm::APSInt val) {
// Clang does this check in the `clang::IntegerLiteral::Create`, but
// we've had the calls with mismatched bit widths succeed before so
// just in case we have ours here too.
CHECK_EQ(val.getBitWidth(), ctx.getIntWidth(type))
<< "Produced type does not match wanted width: "
<< ClangThingToString(type);
CHECK_EQ(val.getBitWidth(), ctx.getIntWidth(type));
return clang::IntegerLiteral::Create(ctx, val, type, clang::SourceLocation());
}

clang::Expr *ASTBuilder::CreateAdjustedIntLit(llvm::APSInt val) {
auto lit{CreateIntLit(val)};
auto value_size{val.getBitWidth()};
// Cast the integer literal to a type of the smallest bit width
// that can contain `val`. Either `short` or `char`.
if (value_size <= ctx.getIntWidth(ctx.ShortTy) ||
value_size > ctx.getIntWidth(ctx.LongLongTy)) {
return CreateCStyleCast(
GetLeastIntTypeForBitWidth(value_size, val.isSigned()), lit);
} else {
return lit;
}
}

clang::CharacterLiteral *ASTBuilder::CreateCharLit(llvm::APInt val) {
CHECK(val.getBitWidth() == 8U);
return new (ctx) clang::CharacterLiteral(
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ExprCombine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ bool ExprCombine::VisitCStyleCastExpr(clang::CStyleCastExpr *cast) {

switch (result.Val.getKind()) {
case clang::APValue::ValueKind::Int: {
auto sub{dec_ctx.ast.CreateAdjustedIntLit(result.Val.getInt())};
auto sub{dec_ctx.ast.CreateIntLit(result.Val.getInt())};
if (GetHash(dec_ctx.ast_ctx, cast) != GetHash(dec_ctx.ast_ctx, sub)) {
substitutions[cast] = sub;
}
Expand Down
18 changes: 1 addition & 17 deletions lib/AST/IRToASTVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,23 +267,7 @@ clang::Expr *ExprGen::CreateLiteralExpr(llvm::Constant *constant) {
case llvm::Type::IntegerTyID: {
if (llvm::isa<llvm::ConstantInt>(constant)) {
auto val{llvm::cast<llvm::ConstantInt>(constant)->getValue()};
auto val_bitwidth{val.getBitWidth()};
auto ull_bitwidth{ast_ctx.getIntWidth(ast_ctx.LongLongTy)};
if (val_bitwidth == 1U) {
// Booleans
result = ast.CreateIntLit(val);
} else if (val.getActiveBits() <= ull_bitwidth) {
result = ast.CreateAdjustedIntLit(val);
} else {
// Values wider than `long long` will be represented as:
// (uint128_t)hi_64 << 64U | lo_64
auto lo{ast.CreateIntLit(val.extractBits(64U, 0U))};
auto hi{ast.CreateIntLit(val.extractBits(val_bitwidth - 64U, 64U))};
auto shl_val{ast.CreateIntLit(llvm::APInt(32U, 64U))};
result = ast.CreateCStyleCast(ast_ctx.UnsignedInt128Ty, hi);
result = ast.CreateShl(result, shl_val);
result = ast.CreateOr(result, lo);
}
result = ast.CreateIntLit(val);
} else if (llvm::isa<llvm::UndefValue>(constant)) {
result = ast.CreateUndefInteger(c_type);
} else {
Expand Down
40 changes: 2 additions & 38 deletions unittests/AST/ASTBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,6 @@ TEST_SUITE("ASTBuilder::CreateIntLit") {
CHECK(clang::isa<clang::IntegerLiteral>(lit));
CHECK(lit->getType() == ctx.UnsignedIntTy);
}

THEN(
"return a unsigned int typed integer literal casted to unsigned "
"char") {
auto cast{ast.CreateAdjustedIntLit(api)};
REQUIRE(cast != nullptr);
CHECK(clang::isa<clang::CStyleCastExpr>(cast));
CHECK(cast->getType() == ctx.UnsignedCharTy);
auto lit{cast->IgnoreCasts()};
CHECK(clang::isa<clang::IntegerLiteral>(lit));
CHECK(lit->getType() == ctx.UnsignedIntTy);
}
}
}
}
Expand All @@ -99,18 +87,6 @@ TEST_SUITE("ASTBuilder::CreateIntLit") {
CHECK(clang::isa<clang::IntegerLiteral>(lit));
CHECK(lit->getType() == ctx.UnsignedIntTy);
}

THEN(
"return a unsigned int typed integer literal casted to unsigned "
"short") {
auto cast{ast.CreateAdjustedIntLit(api)};
REQUIRE(cast != nullptr);
CHECK(clang::isa<clang::CStyleCastExpr>(cast));
CHECK(cast->getType() == ctx.UnsignedShortTy);
auto lit{cast->IgnoreCasts()};
CHECK(clang::isa<clang::IntegerLiteral>(lit));
CHECK(lit->getType() == ctx.UnsignedIntTy);
}
}
}
}
Expand Down Expand Up @@ -156,23 +132,11 @@ TEST_SUITE("ASTBuilder::CreateIntLit") {
rellic::ASTBuilder ast(*unit);
GIVEN("128 bits wide llvm::APInt") {
llvm::APInt api(128U, UINT64_C(42), /*isSigned=*/false);
THEN("return a unsigned long long typed integer literal") {
THEN("return a _uint128_t typed integer literal") {
auto lit{ast.CreateIntLit(api)};
REQUIRE(lit != nullptr);
CHECK(clang::isa<clang::IntegerLiteral>(lit));
CHECK(lit->getType() == ctx.UnsignedLongLongTy);
}

THEN(
"return a unsigned long long typed integer literal casted to "
"_uint128_t") {
auto cast{ast.CreateAdjustedIntLit(api)};
REQUIRE(cast != nullptr);
CHECK(clang::isa<clang::CStyleCastExpr>(cast));
CHECK(cast->getType() == ctx.UnsignedInt128Ty);
auto lit{cast->IgnoreCasts()};
CHECK(clang::isa<clang::IntegerLiteral>(lit));
CHECK(lit->getType() == ctx.UnsignedLongLongTy);
CHECK(lit->getType() == ctx.UnsignedInt128Ty);
}
}
}
Expand Down

0 comments on commit 8930adf

Please sign in to comment.