diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 5a83ed68087..69ff3290573 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 00000000000..9a3367dab1a --- /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 00000000000..a168743859a --- /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 00000000000..96c15d4a365 --- /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 +}