summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/CodeGen/AsmPrinter/AsmPrinter.cpp45
-rw-r--r--test/CodeGen/ARM/emit-big-cst.ll18
-rw-r--r--test/CodeGen/Mips/emit-big-cst.ll17
-rw-r--r--test/CodeGen/X86/emit-big-cst.ll17
4 files changed, 95 insertions, 2 deletions
diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 5a83ed6808..69ff329057 100644
--- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1795,16 +1795,57 @@ static void emitGlobalConstantLargeInt(const ConstantInt *CI,
unsigned AddrSpace, AsmPrinter &AP) {
const DataLayout *TD = AP.TM.getDataLayout();
unsigned BitWidth = CI->getBitWidth();
- assert((BitWidth & 63) == 0 && "only support multiples of 64-bits");
+
+ // Copy the value as we may massage the layout for constants whose bit width
+ // is not a multiple of 64-bits.
+ APInt Realigned(CI->getValue());
+ uint64_t ExtraBits = 0;
+ unsigned ExtraBitsSize = BitWidth & 63;
+
+ if (ExtraBitsSize) {
+ // The bit width of the data is not a multiple of 64-bits.
+ // The extra bits are expected to be at the end of the chunk of the memory.
+ // Little endian:
+ // * Nothing to be done, just record the extra bits to emit.
+ // Big endian:
+ // * Record the extra bits to emit.
+ // * Realign the raw data to emit the chunks of 64-bits.
+ if (TD->isBigEndian()) {
+ // Basically the structure of the raw data is a chunk of 64-bits cells:
+ // 0 1 BitWidth / 64
+ // [chunk1][chunk2] ... [chunkN].
+ // The most significant chunk is chunkN and it should be emitted first.
+ // However, due to the alignment issue chunkN contains useless bits.
+ // Realign the chunks so that they contain only useless information:
+ // ExtraBits 0 1 (BitWidth / 64) - 1
+ // chu[nk1 chu][nk2 chu] ... [nkN-1 chunkN]
+ ExtraBits = Realigned.getRawData()[0] &
+ (((uint64_t)-1) >> (64 - ExtraBitsSize));
+ Realigned = Realigned.lshr(ExtraBitsSize);
+ } else
+ ExtraBits = Realigned.getRawData()[BitWidth / 64];
+ }
// We don't expect assemblers to support integer data directives
// for more than 64 bits, so we emit the data in at most 64-bit
// quantities at a time.
- const uint64_t *RawData = CI->getValue().getRawData();
+ const uint64_t *RawData = Realigned.getRawData();
for (unsigned i = 0, e = BitWidth / 64; i != e; ++i) {
uint64_t Val = TD->isBigEndian() ? RawData[e - i - 1] : RawData[i];
AP.OutStreamer.EmitIntValue(Val, 8, AddrSpace);
}
+
+ if (ExtraBitsSize) {
+ // Emit the extra bits after the 64-bits chunks.
+
+ // Emit a directive that fills the expected size.
+ uint64_t Size = AP.TM.getDataLayout()->getTypeAllocSize(CI->getType());
+ Size -= (BitWidth / 64) * 8;
+ assert(Size && Size * 8 >= ExtraBitsSize &&
+ (ExtraBits & (((uint64_t)-1) >> (64 - ExtraBitsSize)))
+ == ExtraBits && "Directive too small for extra bits.");
+ AP.OutStreamer.EmitIntValue(ExtraBits, Size, AddrSpace);
+ }
}
static void emitGlobalConstantImpl(const Constant *CV, unsigned AddrSpace,
diff --git a/test/CodeGen/ARM/emit-big-cst.ll b/test/CodeGen/ARM/emit-big-cst.ll
new file mode 100644
index 0000000000..9a3367dab1
--- /dev/null
+++ b/test/CodeGen/ARM/emit-big-cst.ll
@@ -0,0 +1,18 @@
+; RUN: llc -mtriple=thumbv7-unknown-unknown < %s | FileCheck %s
+; Check assembly printing of odd constants.
+
+; CHECK: bigCst:
+; CHECK-NEXT: .long 1694510592
+; CHECK-NEXT: .long 2960197
+; CHECK-NEXT: .long 26220
+; CHECK-NEXT: .size bigCst, 12
+
+@bigCst = internal constant i82 483673642326615442599424
+
+define void @accessBig(i64* %storage) {
+ %addr = bitcast i64* %storage to i82*
+ %bigLoadedCst = load volatile i82* @bigCst
+ %tmp = add i82 %bigLoadedCst, 1
+ store i82 %tmp, i82* %addr
+ ret void
+}
diff --git a/test/CodeGen/Mips/emit-big-cst.ll b/test/CodeGen/Mips/emit-big-cst.ll
new file mode 100644
index 0000000000..a168743859
--- /dev/null
+++ b/test/CodeGen/Mips/emit-big-cst.ll
@@ -0,0 +1,17 @@
+; RUN: llc -march=mips < %s | FileCheck %s
+; Check assembly printing of odd constants.
+
+; CHECK: bigCst:
+; CHECK-NEXT: .8byte 1845068520838224192
+; CHECK-NEXT: .8byte 11776
+; CHECK-NEXT: .size bigCst, 16
+
+@bigCst = internal constant i82 483673642326615442599424
+
+define void @accessBig(i64* %storage) {
+ %addr = bitcast i64* %storage to i82*
+ %bigLoadedCst = load volatile i82* @bigCst
+ %tmp = add i82 %bigLoadedCst, 1
+ store i82 %tmp, i82* %addr
+ ret void
+}
diff --git a/test/CodeGen/X86/emit-big-cst.ll b/test/CodeGen/X86/emit-big-cst.ll
new file mode 100644
index 0000000000..96c15d4a36
--- /dev/null
+++ b/test/CodeGen/X86/emit-big-cst.ll
@@ -0,0 +1,17 @@
+; RUN: llc -mtriple=x86_64-unknown-unknown < %s | FileCheck %s
+; Check assembly printing of odd constants.
+
+; CHECK: bigCst:
+; CHECK-NEXT: .quad 12713950999227904
+; CHECK-NEXT: .quad 26220
+; CHECK-NEXT: .size bigCst, 16
+
+@bigCst = internal constant i82 483673642326615442599424
+
+define void @accessBig(i64* %storage) {
+ %addr = bitcast i64* %storage to i82*
+ %bigLoadedCst = load volatile i82* @bigCst
+ %tmp = add i82 %bigLoadedCst, 1
+ store i82 %tmp, i82* %addr
+ ret void
+}