Hi,

When doing int<->ptr coercion for big-endian architectures, the shift
amount is currently incorrectly calculated.

The shift amount is based upon DataLayout::getTypeAllocSizeInBits. This
will only work for legal types - types such as i24 that are created as part
of structs for bitfields will return "32" from that function. This patch
changes to using getTypeSizeInBits.

It turns out that AArch64 didn't run across this problem because it always
returned [1 x i64] as the type for a bitfield, whereas ARM64 returns i64 so
goes down this (better, but wrong) codepath.

I'm almost certain this change is good, but as I'm not a clang expert and
this is generic (big-endian only though) code, I'd appreciate if someone
else would also give it the once-over.

Cheers,

James
From 0626313421a376f25bc75554c7dbf4ad19760231 Mon Sep 17 00:00:00 2001
From: James Molloy <[email protected]>
Date: Thu, 1 May 2014 10:09:41 +0100
Subject: [PATCH] When doing int<->ptr coercion for big-endian, calculate the
 shift amount correctly.

Previously we calculated the shift amount based upon DataLayout::getTypeAllocSizeInBits.
This will only work for legal types - types such as i24 that are created as part of
structs for bitfields will return "32" from that function. Change to using
getTypeSizeInBits.

It turns out that AArch64 didn't run across this problem because it always returned
[1 x i64] as the type for a bitfield, whereas ARM64 returns i64 so goes down this
(better, but wrong) codepath.
---
 lib/CodeGen/CGCall.cpp           |    5 +++--
 test/CodeGen/arm64-be-bitfield.c |    9 +++++++++
 2 files changed, 12 insertions(+), 2 deletions(-)
 create mode 100644 test/CodeGen/arm64-be-bitfield.c

diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index da50473..972a7c8 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -700,8 +700,9 @@ static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val,
     if (DL.isBigEndian()) {
       // Preserve the high bits on big-endian targets.
       // That is what memory coercion does.
-      uint64_t SrcSize = DL.getTypeAllocSizeInBits(Val->getType());
-      uint64_t DstSize = DL.getTypeAllocSizeInBits(DestIntTy);
+      uint64_t SrcSize = DL.getTypeSizeInBits(Val->getType());
+      uint64_t DstSize = DL.getTypeSizeInBits(DestIntTy);
+
       if (SrcSize > DstSize) {
         Val = CGF.Builder.CreateLShr(Val, SrcSize - DstSize, "coerce.highbits");
         Val = CGF.Builder.CreateTrunc(Val, DestIntTy, "coerce.val.ii");
diff --git a/test/CodeGen/arm64-be-bitfield.c b/test/CodeGen/arm64-be-bitfield.c
new file mode 100644
index 0000000..f01e4cb
--- /dev/null
+++ b/test/CodeGen/arm64-be-bitfield.c
@@ -0,0 +1,9 @@
+// RUN:  %clang_cc1 -triple arm64_be-linux-gnu -ffreestanding -emit-llvm -O0 -o - %s | FileCheck %s
+
+struct bt3 { signed b2:10; signed b3:10; } b16;
+
+// The correct right-shift amount is 40 bits for big endian.
+signed callee_b0f(struct bt3 bp11) {
+// CHECK: %coerce.highbits = lshr i64 %bp11.coerce, 40
+  return bp11.b2;
+}
-- 
1.7.10.4

_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to