gollvm: fix issue with integer constant creation
The recipe used for constructing integer constant expressions in the
bridge was not properly handling the case where you have a signed
mpz_val with value ((int64_t) -1) being forced into an unsigned
integer Btype with fewer bits (ex: uint16 or uint32). This triggered
an assert, since the mpz_val was being converted to a uint64 value of
18446744073709551615, then the llvm::ConstantInt::isValueValidForType
check for the smaller type failed. Fixed code converts constant
value into an llvm::APInt with the correct signed-ness and number of
bits before invoking llvm::ConstantInt::get.
Change-Id: I68741eea6833705cffe2eb06e33c3e771072aaeb
Reviewed-on: https://go-review.googlesource.com/48111
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/llvm-gofrontend/go-llvm.cpp b/llvm-gofrontend/go-llvm.cpp
index 99febaa..9b0766a 100644
--- a/llvm-gofrontend/go-llvm.cpp
+++ b/llvm-gofrontend/go-llvm.cpp
@@ -925,22 +925,20 @@
assert(btype->type()->isIntegerTy());
// Force mpz_val into either into uint64_t or int64_t depending on
- // whether btype was declared as signed or unsigned.
- //
- // Q: better to use APInt here?
+ // whether btype was declared as signed or unsigned.
Bexpression *rval;
BIntegerType *bit = btype->castToBIntegerType();
if (bit->isUnsigned()) {
uint64_t val = checked_convert_mpz_to_int<uint64_t>(mpz_val);
- assert(llvm::ConstantInt::isValueValidForType(btype->type(), val));
- llvm::Constant *lval = llvm::ConstantInt::get(btype->type(), val);
+ llvm::APInt apiv(bit->bits(), val);
+ llvm::Constant *lval = llvm::ConstantInt::get(btype->type(), apiv);
Bexpression *bconst = nbuilder_.mkConst(btype, lval);
return makeGlobalExpression(bconst, lval, btype, Location());
} else {
int64_t val = checked_convert_mpz_to_int<int64_t>(mpz_val);
- assert(llvm::ConstantInt::isValueValidForType(btype->type(), val));
- llvm::Constant *lval = llvm::ConstantInt::getSigned(btype->type(), val);
+ llvm::APInt apiv(bit->bits(), val, true);
+ llvm::Constant *lval = llvm::ConstantInt::get(btype->type(), apiv);
Bexpression *bconst = nbuilder_.mkConst(btype, lval);
return makeGlobalExpression(bconst, lval, btype, Location());
}
diff --git a/unittests/BackendCore/BackendExprTests.cpp b/unittests/BackendCore/BackendExprTests.cpp
index e3d2d5c..7b4a942 100644
--- a/unittests/BackendCore/BackendExprTests.cpp
+++ b/unittests/BackendCore/BackendExprTests.cpp
@@ -65,6 +65,20 @@
EXPECT_EQ(beval->value(), llvm::ConstantInt::get(bu64t->type(), val));
mpz_clear(mpz_val);
}
+
+ // Frontend will occasionally create create a signed -1 value with
+ // mpz_init_set_si and then hand this value off to to the bridge
+ // with a smaller unsigned type. Verify that this case works
+ // correctly.
+ mpz_t mpz_val;
+ memset(&mpz_val, '0', sizeof(mpz_val));
+ mpz_init_set_si(mpz_val, int64_t(-1));
+ Btype *bu32t = be->integer_type(true, 32);
+ Bexpression *beval = be->integer_constant_expression(bu32t, mpz_val);
+ ASSERT_TRUE(beval != nullptr);
+ uint32_t um1 = uint32_t(-1);
+ EXPECT_EQ(beval->value(), llvm::ConstantInt::get(bu32t->type(), um1));
+ mpz_clear(mpz_val);
}
TEST(BackendExprTests, MakeFloatConstExpr) {