David Jones via llvm-dev
2015-Dec-11 16:32 UTC
[llvm-dev] Optimization of successive constant stores
Consider the following: target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" %UodStructType = type { i8, i8, i8, i8, i32, i8* } define void @test(%UodStructType*) { %2 = getelementptr inbounds %UodStructType* %0, i32 0, i32 0 store i8 1, i8* %2, align 8 %3 = getelementptr inbounds %UodStructType* %0, i32 0, i32 1 store i8 2, i8* %3, align 1 %4 = getelementptr inbounds %UodStructType* %0, i32 0, i32 2 store i8 3, i8* %4, align 2 %5 = getelementptr inbounds %UodStructType* %0, i32 0, i32 3 store i8 4, i8* %5, align 1 ret void } If I run this through opt -O3, it passes through unchanged. However, I would think that it would be profitable to combine the stores into a single instruction, e.g.: define void @test(%UodStructType*) { %2 = bitcast %UodStructType* %0 to i32* store i32 0x04030201, i32* %2, align 8 ret void } I don't see any optimization that would do this. Interestingly, if I store the same 8-bit constant in all four bytes, then MemCpyOpt will indeed convert this to a 32-bit store. Am I doing something wrong, or is there really no optimization pass that can clean this up? -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20151211/17827054/attachment.html>
Hal Finkel via llvm-dev
2015-Dec-11 16:37 UTC
[llvm-dev] Optimization of successive constant stores
Hi David, We generally handle this (early) in the backend where we have more information about target capabilities and costs. See MergeConsecutiveStores in lib/CodeGen/SelectionDAG/DAGCombiner.cpp -Hal ----- Original Message -----> From: "David Jones via llvm-dev" <llvm-dev at lists.llvm.org> > To: llvm-dev at lists.llvm.org > Sent: Friday, December 11, 2015 10:32:50 AM > Subject: [llvm-dev] Optimization of successive constant stores > > Consider the following: > > t arget datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" > target triple = "x86_64-unknown-linux-gnu" > > %UodStructType = type { i8, i8, i8, i8, i32, i8* } > > define void @test(%UodStructType*) { > %2 = getelementptr inbounds %UodStructType* %0, i32 0, i32 0 > store i8 1, i8* %2, align 8 > %3 = getelementptr inbounds %UodStructType* %0, i32 0, i32 1 > store i8 2, i8* %3, align 1 > %4 = getelementptr inbounds %UodStructType* %0, i32 0, i32 2 > store i8 3, i8* %4, align 2 > %5 = getelementptr inbounds %UodStructType* %0, i32 0, i32 3 > store i8 4, i8* %5, align 1 > ret void > } > > If I run this through opt -O3, it passes through unchanged. > > However, I would think that it would be profitable to combine the > stores into a single instruction, e.g.: > > define void @test(%UodStructType*) { > %2 = bitcast %UodStructType* %0 to i32* > store i32 0x04030201, i32* %2, align 8 > > > ret void > } > > > I don't see any optimization that would do this. > > Interestingly, if I store the same 8-bit constant in all four bytes, > then MemCpyOpt will indeed convert this to a 32-bit store. > > > Am I doing something wrong, or is there really no optimization pass > that can clean this up? > > > _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev >-- Hal Finkel Assistant Computational Scientist Leadership Computing Facility Argonne National Laboratory
David Jones via llvm-dev
2015-Dec-11 17:07 UTC
[llvm-dev] Optimization of successive constant stores
Hmm... found an interesting issue: Given: %2 = getelementptr inbounds %UodStructType* %0, i32 0, i32 0 store i8 1, i8* %2, align 8 %3 = getelementptr inbounds %UodStructType* %0, i32 0, i32 1 store i8 2, i8* %3, align 1 %4 = getelementptr inbounds %UodStructType* %0, i32 0, i32 2 store i8 3, i8* %4, align 2 %5 = getelementptr inbounds %UodStructType* %0, i32 0, i32 3 store i8 4, i8* %5, align 1 ret void llc generates: movb $1, (%rdi) movb $2, 1(%rdi) movb $3, 2(%rdi) movb $4, 3(%rdi) retq But given: %2 = getelementptr inbounds %UodStructType* %0, i32 0, i32 0 store i8 1, i8* %2, align 1 %3 = getelementptr inbounds %UodStructType* %0, i32 0, i32 1 store i8 2, i8* %3, align 1 %4 = getelementptr inbounds %UodStructType* %0, i32 0, i32 2 store i8 3, i8* %4, align 1 %5 = getelementptr inbounds %UodStructType* %0, i32 0, i32 3 store i8 4, i8* %5, align 1 ret void We get: movl $67305985, (%rdi) # imm = 0x4030201 retq Also interesting: define void @test(i8*) { %2 = getelementptr inbounds i8* %0, i32 0 store i8 1, i8* %2, align 1 %3 = getelementptr inbounds i8* %0, i32 1 store i8 2, i8* %3, align 1 %4 = getelementptr inbounds i8* %0, i32 2 store i8 3, i8* %4, align 1 %5 = getelementptr inbounds i8* %0, i32 3 store i8 4, i8* %5, align 1 ret void This code also results in a single store. However, there is no guarantee that the input pointer is 32-bit aligned. x86_64 tolerates this, but the ABI mandates aligned loads and stores. My previous example guaranteed alignment, because I started with a pointer to a structure containing a member having 8-byte alignment, therefore we could infer the alignment of some of the stores. And checking the code in DAGCombiner.cpp indeed shows that all combined instructions have to have the same alignment. Why? On Fri, Dec 11, 2015 at 11:37 AM, Hal Finkel <hfinkel at anl.gov> wrote:> Hi David, > > We generally handle this (early) in the backend where we have more > information about target capabilities and costs. See MergeConsecutiveStores > in lib/CodeGen/SelectionDAG/DAGCombiner.cpp > > -Hal > > ----- Original Message ----- > > From: "David Jones via llvm-dev" <llvm-dev at lists.llvm.org> > > To: llvm-dev at lists.llvm.org > > Sent: Friday, December 11, 2015 10:32:50 AM > > Subject: [llvm-dev] Optimization of successive constant stores > > > > Consider the following: > > > > t arget datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" > > target triple = "x86_64-unknown-linux-gnu" > > > > %UodStructType = type { i8, i8, i8, i8, i32, i8* } > > > > define void @test(%UodStructType*) { > > %2 = getelementptr inbounds %UodStructType* %0, i32 0, i32 0 > > store i8 1, i8* %2, align 8 > > %3 = getelementptr inbounds %UodStructType* %0, i32 0, i32 1 > > store i8 2, i8* %3, align 1 > > %4 = getelementptr inbounds %UodStructType* %0, i32 0, i32 2 > > store i8 3, i8* %4, align 2 > > %5 = getelementptr inbounds %UodStructType* %0, i32 0, i32 3 > > store i8 4, i8* %5, align 1 > > ret void > > } > > > > If I run this through opt -O3, it passes through unchanged. > > > > However, I would think that it would be profitable to combine the > > stores into a single instruction, e.g.: > > > > define void @test(%UodStructType*) { > > %2 = bitcast %UodStructType* %0 to i32* > > store i32 0x04030201, i32* %2, align 8 > > > > > > ret void > > } > > > > > > I don't see any optimization that would do this. > > > > Interestingly, if I store the same 8-bit constant in all four bytes, > > then MemCpyOpt will indeed convert this to a 32-bit store. > > > > > > Am I doing something wrong, or is there really no optimization pass > > that can clean this up? > > > > > > _______________________________________________ > > LLVM Developers mailing list > > llvm-dev at lists.llvm.org > > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev > > > > -- > Hal Finkel > Assistant Computational Scientist > Leadership Computing Facility > Argonne National Laboratory >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20151211/cedd512a/attachment.html>
Apparently Analagous Threads
- Optimization of successive constant stores
- Suboptimal code generated by clang+llc in quite a common scenario (?)
- Byte-wide stores aren't coalesced if interspersed with other stores
- A code layout related side-effect introduced by rL318299
- A code layout related side-effect introduced by rL318299