[llvm-commits] [PATCH, PowerPC, RFC] Small structs passed in registers must be right-aligned for 64-bit SVR4 ABI

William J. Schmidt wschmidt at linux.vnet.ibm.com
Wed Sep 19 08:44:52 PDT 2012


Committed as r164228.

Small structs for PPC64 SVR4 must be passed right-justified in registers.

lib/Target/PowerPC/PPCISelLowering.{h,cpp}
 Rename LowerFormalArguments_Darwin to LowerFormalArguments_Darwin_Or_64SVR4.
 Rename LowerFormalArguments_SVR4 to LowerFormalArguments_32SVR4.
 Receive small structs right-justified in LowerFormalArguments_Darwin_Or_64SVR4.
 Rename LowerCall_Darwin to LowerCall_Darwin_Or_64SVR4.
 Rename LowerCall_SVR4 to LowerCall_32SVR4.
 Pass small structs right-justified in LowerCall_Darwin_Or_64SVR4.

test/CodeGen/PowerPC/structsinregs.ll
 New test.


On Wed, 2012-09-19 at 17:27 +0200, Roman Divacky wrote:
> Looks good to me. Please commit!
> 
> On Wed, Sep 19, 2012 at 09:21:44AM -0500, William J. Schmidt wrote:
> > One last round with a couple of commentary changes.  Ok to commit?
> > 
> > On Tue, 2012-09-18 at 09:10 -0500, William J. Schmidt wrote:
> > > Here's a new version with some minor cleanups suggested by Roman.
> > > Thanks for consideration!
> > > 
> > > Bill
> > > 
> > > On Mon, 2012-09-17 at 14:38 -0500, William J. Schmidt wrote:
> > > > Greetings,
> > > > 
> > > > The attached patch fixes an ABI incompatibility for 64-bit SVR4 PowerPC.
> > > > If an aggregate fewer than 8 bytes in size is passed in a register, it
> > > > must be passed with padding on the left, not on the right.  That is, the
> > > > aggregate must be right-justified in the register.  Note that alignment
> > > > padding may still be used on the right end of the argument; thus "struct
> > > > x { int a; char b; };" has 5 bytes of data and 3 bytes of trailing
> > > > padding since the struct requires 4-byte alignment.  With #pragma
> > > > pack(1), however, the same structure passed in a register must have 5
> > > > bytes of data and 3 bytes of leading padding.
> > > > 
> > > > The existing code for passing structs is pretty inefficient (overusing
> > > > memcpy) and I have made no effort to improve this for now.  Eventually
> > > > the poor code generation should be addressed also, but my purpose today
> > > > is just to make the generated code correct.
> > > > 
> > > > The test case verifies that aggregates of size 1 through 7 are passed
> > > > correctly by the caller and retrieved correctly by the callee.  There
> > > > are two versions of the test code:  one with aggregates using natural
> > > > alignment, and one with aggregates using #pragma pack(1).
> > > > 
> > > > I don't yet have commit authority, so I would appreciate it if someone
> > > > could commit this after the review period.
> > > > 
> > > > Thanks!
> > > > Bill
> > > 
> 
> > Index: test/CodeGen/PowerPC/structsinregs.ll
> > ===================================================================
> > --- test/CodeGen/PowerPC/structsinregs.ll	(revision 0)
> > +++ test/CodeGen/PowerPC/structsinregs.ll	(revision 0)
> > @@ -0,0 +1,204 @@
> > +; RUN: llc -O0 -disable-fp-elim < %s | FileCheck %s
> > +target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32:64"
> > +target triple = "powerpc64-unknown-linux-gnu"
> > +
> > +%struct.s1 = type { i8 }
> > +%struct.s2 = type { i16 }
> > +%struct.s4 = type { i32 }
> > +%struct.t1 = type { i8 }
> > +%struct.t3 = type <{ i16, i8 }>
> > +%struct.t5 = type <{ i32, i8 }>
> > +%struct.t6 = type <{ i32, i16 }>
> > +%struct.t7 = type <{ i32, i16, i8 }>
> > +%struct.s3 = type { i16, i8 }
> > +%struct.s5 = type { i32, i8 }
> > +%struct.s6 = type { i32, i16 }
> > +%struct.s7 = type { i32, i16, i8 }
> > +%struct.t2 = type <{ i16 }>
> > +%struct.t4 = type <{ i32 }>
> > +
> > + at caller1.p1 = private unnamed_addr constant %struct.s1 { i8 1 }, align 1
> > + at caller1.p2 = private unnamed_addr constant %struct.s2 { i16 2 }, align 2
> > + at caller1.p3 = private unnamed_addr constant { i16, i8, i8 } { i16 4, i8 8, i8 undef }, align 2
> > + at caller1.p4 = private unnamed_addr constant %struct.s4 { i32 16 }, align 4
> > + at caller1.p5 = private unnamed_addr constant { i32, i8, [3 x i8] } { i32 32, i8 64, [3 x i8] undef }, align 4
> > + at caller1.p6 = private unnamed_addr constant { i32, i16, [2 x i8] } { i32 128, i16 256, [2 x i8] undef }, align 4
> > + at caller1.p7 = private unnamed_addr constant { i32, i16, i8, i8 } { i32 512, i16 1024, i8 -3, i8 undef }, align 4
> > + at caller2.p1 = private unnamed_addr constant %struct.t1 { i8 1 }, align 1
> > + at caller2.p2 = private unnamed_addr constant { i16 } { i16 2 }, align 1
> > + at caller2.p3 = private unnamed_addr constant %struct.t3 <{ i16 4, i8 8 }>, align 1
> > + at caller2.p4 = private unnamed_addr constant { i32 } { i32 16 }, align 1
> > + at caller2.p5 = private unnamed_addr constant %struct.t5 <{ i32 32, i8 64 }>, align 1
> > + at caller2.p6 = private unnamed_addr constant %struct.t6 <{ i32 128, i16 256 }>, align 1
> > + at caller2.p7 = private unnamed_addr constant %struct.t7 <{ i32 512, i16 1024, i8 -3 }>, align 1
> > +
> > +define i32 @caller1() nounwind {
> > +entry:
> > +  %p1 = alloca %struct.s1, align 1
> > +  %p2 = alloca %struct.s2, align 2
> > +  %p3 = alloca %struct.s3, align 2
> > +  %p4 = alloca %struct.s4, align 4
> > +  %p5 = alloca %struct.s5, align 4
> > +  %p6 = alloca %struct.s6, align 4
> > +  %p7 = alloca %struct.s7, align 4
> > +  %0 = bitcast %struct.s1* %p1 to i8*
> > +  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* getelementptr inbounds (%struct.s1* @caller1.p1, i32 0, i32 0), i64 1, i32 1, i1 false)
> > +  %1 = bitcast %struct.s2* %p2 to i8*
> > +  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* bitcast (%struct.s2* @caller1.p2 to i8*), i64 2, i32 2, i1 false)
> > +  %2 = bitcast %struct.s3* %p3 to i8*
> > +  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* bitcast ({ i16, i8, i8 }* @caller1.p3 to i8*), i64 4, i32 2, i1 false)
> > +  %3 = bitcast %struct.s4* %p4 to i8*
> > +  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %3, i8* bitcast (%struct.s4* @caller1.p4 to i8*), i64 4, i32 4, i1 false)
> > +  %4 = bitcast %struct.s5* %p5 to i8*
> > +  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %4, i8* bitcast ({ i32, i8, [3 x i8] }* @caller1.p5 to i8*), i64 8, i32 4, i1 false)
> > +  %5 = bitcast %struct.s6* %p6 to i8*
> > +  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %5, i8* bitcast ({ i32, i16, [2 x i8] }* @caller1.p6 to i8*), i64 8, i32 4, i1 false)
> > +  %6 = bitcast %struct.s7* %p7 to i8*
> > +  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %6, i8* bitcast ({ i32, i16, i8, i8 }* @caller1.p7 to i8*), i64 8, i32 4, i1 false)
> > +  %call = call i32 @callee1(%struct.s1* byval %p1, %struct.s2* byval %p2, %struct.s3* byval %p3, %struct.s4* byval %p4, %struct.s5* byval %p5, %struct.s6* byval %p6, %struct.s7* byval %p7)
> > +  ret i32 %call
> > +
> > +; CHECK: ld 9, 128(31)
> > +; CHECK: ld 8, 136(31)
> > +; CHECK: ld 7, 144(31)
> > +; CHECK: lwz 6, 152(31)
> > +; CHECK: lwz 5, 160(31)
> > +; CHECK: lhz 4, 168(31)
> > +; CHECK: lbz 3, 176(31)
> > +}
> > +
> > +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind
> > +
> > +define internal i32 @callee1(%struct.s1* byval %v1, %struct.s2* byval %v2, %struct.s3* byval %v3, %struct.s4* byval %v4, %struct.s5* byval %v5, %struct.s6* byval %v6, %struct.s7* byval %v7) nounwind {
> > +entry:
> > +  %a = getelementptr inbounds %struct.s1* %v1, i32 0, i32 0
> > +  %0 = load i8* %a, align 1
> > +  %conv = zext i8 %0 to i32
> > +  %a1 = getelementptr inbounds %struct.s2* %v2, i32 0, i32 0
> > +  %1 = load i16* %a1, align 2
> > +  %conv2 = sext i16 %1 to i32
> > +  %add = add nsw i32 %conv, %conv2
> > +  %a3 = getelementptr inbounds %struct.s3* %v3, i32 0, i32 0
> > +  %2 = load i16* %a3, align 2
> > +  %conv4 = sext i16 %2 to i32
> > +  %add5 = add nsw i32 %add, %conv4
> > +  %a6 = getelementptr inbounds %struct.s4* %v4, i32 0, i32 0
> > +  %3 = load i32* %a6, align 4
> > +  %add7 = add nsw i32 %add5, %3
> > +  %a8 = getelementptr inbounds %struct.s5* %v5, i32 0, i32 0
> > +  %4 = load i32* %a8, align 4
> > +  %add9 = add nsw i32 %add7, %4
> > +  %a10 = getelementptr inbounds %struct.s6* %v6, i32 0, i32 0
> > +  %5 = load i32* %a10, align 4
> > +  %add11 = add nsw i32 %add9, %5
> > +  %a12 = getelementptr inbounds %struct.s7* %v7, i32 0, i32 0
> > +  %6 = load i32* %a12, align 4
> > +  %add13 = add nsw i32 %add11, %6
> > +  ret i32 %add13
> > +
> > +; CHECK: std 9, 96(1)
> > +; CHECK: std 8, 88(1)
> > +; CHECK: std 7, 80(1)
> > +; CHECK: stw 6, 72(1)
> > +; CHECK: stw 5, 64(1)
> > +; CHECK: sth 4, 58(1)
> > +; CHECK: stb 3, 51(1)
> > +; CHECK: lha {{[0-9]+}}, 58(1)
> > +; CHECK: lbz {{[0-9]+}}, 51(1)
> > +; CHECK: lha {{[0-9]+}}, 64(1)
> > +; CHECK: lwz {{[0-9]+}}, 72(1)
> > +; CHECK: lwz {{[0-9]+}}, 80(1)
> > +; CHECK: lwz {{[0-9]+}}, 88(1)
> > +; CHECK: lwz {{[0-9]+}}, 96(1)
> > +}
> > +
> > +define i32 @caller2() nounwind {
> > +entry:
> > +  %p1 = alloca %struct.t1, align 1
> > +  %p2 = alloca %struct.t2, align 1
> > +  %p3 = alloca %struct.t3, align 1
> > +  %p4 = alloca %struct.t4, align 1
> > +  %p5 = alloca %struct.t5, align 1
> > +  %p6 = alloca %struct.t6, align 1
> > +  %p7 = alloca %struct.t7, align 1
> > +  %0 = bitcast %struct.t1* %p1 to i8*
> > +  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* getelementptr inbounds (%struct.t1* @caller2.p1, i32 0, i32 0), i64 1, i32 1, i1 false)
> > +  %1 = bitcast %struct.t2* %p2 to i8*
> > +  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* bitcast ({ i16 }* @caller2.p2 to i8*), i64 2, i32 1, i1 false)
> > +  %2 = bitcast %struct.t3* %p3 to i8*
> > +  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* bitcast (%struct.t3* @caller2.p3 to i8*), i64 3, i32 1, i1 false)
> > +  %3 = bitcast %struct.t4* %p4 to i8*
> > +  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %3, i8* bitcast ({ i32 }* @caller2.p4 to i8*), i64 4, i32 1, i1 false)
> > +  %4 = bitcast %struct.t5* %p5 to i8*
> > +  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %4, i8* bitcast (%struct.t5* @caller2.p5 to i8*), i64 5, i32 1, i1 false)
> > +  %5 = bitcast %struct.t6* %p6 to i8*
> > +  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %5, i8* bitcast (%struct.t6* @caller2.p6 to i8*), i64 6, i32 1, i1 false)
> > +  %6 = bitcast %struct.t7* %p7 to i8*
> > +  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %6, i8* bitcast (%struct.t7* @caller2.p7 to i8*), i64 7, i32 1, i1 false)
> > +  %call = call i32 @callee2(%struct.t1* byval %p1, %struct.t2* byval %p2, %struct.t3* byval %p3, %struct.t4* byval %p4, %struct.t5* byval %p5, %struct.t6* byval %p6, %struct.t7* byval %p7)
> > +  ret i32 %call
> > +
> > +; CHECK: stb {{[0-9]+}}, 71(1)
> > +; CHECK: sth {{[0-9]+}}, 69(1)
> > +; CHECK: stb {{[0-9]+}}, 87(1)
> > +; CHECK: stw {{[0-9]+}}, 83(1)
> > +; CHECK: sth {{[0-9]+}}, 94(1)
> > +; CHECK: stw {{[0-9]+}}, 90(1)
> > +; CHECK: stb {{[0-9]+}}, 103(1)
> > +; CHECK: sth {{[0-9]+}}, 101(1)
> > +; CHECK: stw {{[0-9]+}}, 97(1)
> > +; CHECK: ld 9, 96(1)
> > +; CHECK: ld 8, 88(1)
> > +; CHECK: ld 7, 80(1)
> > +; CHECK: lwz 6, 152(31)
> > +; CHECK: ld 5, 64(1)
> > +; CHECK: lhz 4, 168(31)
> > +; CHECK: lbz 3, 176(31)
> > +}
> > +
> > +define internal i32 @callee2(%struct.t1* byval %v1, %struct.t2* byval %v2, %struct.t3* byval %v3, %struct.t4* byval %v4, %struct.t5* byval %v5, %struct.t6* byval %v6, %struct.t7* byval %v7) nounwind {
> > +entry:
> > +  %a = getelementptr inbounds %struct.t1* %v1, i32 0, i32 0
> > +  %0 = load i8* %a, align 1
> > +  %conv = zext i8 %0 to i32
> > +  %a1 = getelementptr inbounds %struct.t2* %v2, i32 0, i32 0
> > +  %1 = load i16* %a1, align 1
> > +  %conv2 = sext i16 %1 to i32
> > +  %add = add nsw i32 %conv, %conv2
> > +  %a3 = getelementptr inbounds %struct.t3* %v3, i32 0, i32 0
> > +  %2 = load i16* %a3, align 1
> > +  %conv4 = sext i16 %2 to i32
> > +  %add5 = add nsw i32 %add, %conv4
> > +  %a6 = getelementptr inbounds %struct.t4* %v4, i32 0, i32 0
> > +  %3 = load i32* %a6, align 1
> > +  %add7 = add nsw i32 %add5, %3
> > +  %a8 = getelementptr inbounds %struct.t5* %v5, i32 0, i32 0
> > +  %4 = load i32* %a8, align 1
> > +  %add9 = add nsw i32 %add7, %4
> > +  %a10 = getelementptr inbounds %struct.t6* %v6, i32 0, i32 0
> > +  %5 = load i32* %a10, align 1
> > +  %add11 = add nsw i32 %add9, %5
> > +  %a12 = getelementptr inbounds %struct.t7* %v7, i32 0, i32 0
> > +  %6 = load i32* %a12, align 1
> > +  %add13 = add nsw i32 %add11, %6
> > +  ret i32 %add13
> > +
> > +; CHECK: sldi 9, 9, 8
> > +; CHECK: sldi 8, 8, 16
> > +; CHECK: sldi 7, 7, 24
> > +; CHECK: sldi 5, 5, 40
> > +; CHECK: stw 6, 72(1)
> > +; CHECK: sth 4, 58(1)
> > +; CHECK: stb 3, 51(1)
> > +; CHECK: std 9, 96(1)
> > +; CHECK: std 8, 88(1)
> > +; CHECK: std 7, 80(1)
> > +; CHECK: std 5, 64(1)
> > +; CHECK: lha {{[0-9]+}}, 58(1)
> > +; CHECK: lbz {{[0-9]+}}, 51(1)
> > +; CHECK: lha {{[0-9]+}}, 64(1)
> > +; CHECK: lwz {{[0-9]+}}, 72(1)
> > +; CHECK: lwz {{[0-9]+}}, 80(1)
> > +; CHECK: lwz {{[0-9]+}}, 88(1)
> > +; CHECK: lwz {{[0-9]+}}, 96(1)
> > +}
> > Index: lib/Target/PowerPC/PPCISelLowering.h
> > ===================================================================
> > --- lib/Target/PowerPC/PPCISelLowering.h	(revision 163746)
> > +++ lib/Target/PowerPC/PPCISelLowering.h	(working copy)
> > @@ -467,20 +467,21 @@ namespace llvm {
> >                    DebugLoc dl, SelectionDAG &DAG) const;
> >  
> >      SDValue
> > -      LowerFormalArguments_Darwin(SDValue Chain,
> > +      LowerFormalArguments_Darwin_Or_64SVR4(SDValue Chain,
> >                                    CallingConv::ID CallConv, bool isVarArg,
> >                                    const SmallVectorImpl<ISD::InputArg> &Ins,
> >                                    DebugLoc dl, SelectionDAG &DAG,
> >                                    SmallVectorImpl<SDValue> &InVals) const;
> >      SDValue
> > -      LowerFormalArguments_SVR4(SDValue Chain,
> > -                                CallingConv::ID CallConv, bool isVarArg,
> > -                                const SmallVectorImpl<ISD::InputArg> &Ins,
> > -                                DebugLoc dl, SelectionDAG &DAG,
> > -                                SmallVectorImpl<SDValue> &InVals) const;
> > +      LowerFormalArguments_32SVR4(SDValue Chain,
> > +                                  CallingConv::ID CallConv, bool isVarArg,
> > +                                  const SmallVectorImpl<ISD::InputArg> &Ins,
> > +                                  DebugLoc dl, SelectionDAG &DAG,
> > +                                  SmallVectorImpl<SDValue> &InVals) const;
> >  
> >      SDValue
> > -      LowerCall_Darwin(SDValue Chain, SDValue Callee, CallingConv::ID CallConv,
> > +      LowerCall_Darwin_Or_64SVR4(SDValue Chain, SDValue Callee,
> > +                       CallingConv::ID CallConv,
> >                         bool isVarArg, bool isTailCall,
> >                         const SmallVectorImpl<ISD::OutputArg> &Outs,
> >                         const SmallVectorImpl<SDValue> &OutVals,
> > @@ -488,13 +489,13 @@ namespace llvm {
> >                         DebugLoc dl, SelectionDAG &DAG,
> >                         SmallVectorImpl<SDValue> &InVals) const;
> >      SDValue
> > -    LowerCall_SVR4(SDValue Chain, SDValue Callee, CallingConv::ID CallConv,
> > -                   bool isVarArg, bool isTailCall,
> > -                   const SmallVectorImpl<ISD::OutputArg> &Outs,
> > -                   const SmallVectorImpl<SDValue> &OutVals,
> > -                   const SmallVectorImpl<ISD::InputArg> &Ins,
> > -                   DebugLoc dl, SelectionDAG &DAG,
> > -                   SmallVectorImpl<SDValue> &InVals) const;
> > +    LowerCall_32SVR4(SDValue Chain, SDValue Callee, CallingConv::ID CallConv,
> > +                     bool isVarArg, bool isTailCall,
> > +                     const SmallVectorImpl<ISD::OutputArg> &Outs,
> > +                     const SmallVectorImpl<SDValue> &OutVals,
> > +                     const SmallVectorImpl<ISD::InputArg> &Ins,
> > +                     DebugLoc dl, SelectionDAG &DAG,
> > +                     SmallVectorImpl<SDValue> &InVals) const;
> >    };
> >  }
> >  
> > Index: lib/Target/PowerPC/PPCISelLowering.cpp
> > ===================================================================
> > --- lib/Target/PowerPC/PPCISelLowering.cpp	(revision 163746)
> > +++ lib/Target/PowerPC/PPCISelLowering.cpp	(working copy)
> > @@ -1717,16 +1717,16 @@ PPCTargetLowering::LowerFormalArguments(SDValue Ch
> >                                          SmallVectorImpl<SDValue> &InVals)
> >                                            const {
> >    if (PPCSubTarget.isSVR4ABI() && !PPCSubTarget.isPPC64()) {
> > -    return LowerFormalArguments_SVR4(Chain, CallConv, isVarArg, Ins,
> > -                                     dl, DAG, InVals);
> > +    return LowerFormalArguments_32SVR4(Chain, CallConv, isVarArg, Ins,
> > +                                       dl, DAG, InVals);
> >    } else {
> > -    return LowerFormalArguments_Darwin(Chain, CallConv, isVarArg, Ins,
> > -                                       dl, DAG, InVals);
> > +    return LowerFormalArguments_Darwin_Or_64SVR4(Chain, CallConv, isVarArg, Ins,
> > +                                                 dl, DAG, InVals);
> >    }
> >  }
> >  
> >  SDValue
> > -PPCTargetLowering::LowerFormalArguments_SVR4(
> > +PPCTargetLowering::LowerFormalArguments_32SVR4(
> >                                        SDValue Chain,
> >                                        CallingConv::ID CallConv, bool isVarArg,
> >                                        const SmallVectorImpl<ISD::InputArg>
> > @@ -1944,7 +1944,7 @@ SDValue
> >  }
> >  
> >  SDValue
> > -PPCTargetLowering::LowerFormalArguments_Darwin(
> > +PPCTargetLowering::LowerFormalArguments_Darwin_Or_64SVR4(
> >                                        SDValue Chain,
> >                                        CallingConv::ID CallConv, bool isVarArg,
> >                                        const SmallVectorImpl<ISD::InputArg>
> > @@ -1959,6 +1959,7 @@ SDValue
> >  
> >    EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
> >    bool isPPC64 = PtrVT == MVT::i64;
> > +  bool isSVR4ABI = PPCSubTarget.isSVR4ABI();
> >    // Potential tail calls could cause overwriting of argument stack slots.
> >    bool isImmutable = !(getTargetMachine().Options.GuaranteedTailCallOpt &&
> >                         (CallConv == CallingConv::Fast));
> > @@ -2019,10 +2020,12 @@ SDValue
> >        default: llvm_unreachable("Unhandled argument type!");
> >        case MVT::i32:
> >        case MVT::f32:
> > -        VecArgOffset += isPPC64 ? 8 : 4;
> > +        VecArgOffset += 4;
> >          break;
> >        case MVT::i64:  // PPC64
> >        case MVT::f64:
> > +        // FIXME: We are guaranteed to be !isPPC64 at this point.
> > +        // Does MVT::i64 apply?
> >          VecArgOffset += 8;
> >          break;
> >        case MVT::v4f32:
> > @@ -2076,8 +2079,11 @@ SDValue
> >        // ObjSize is the true size, ArgSize rounded up to multiple of registers.
> >        ObjSize = Flags.getByValSize();
> >        ArgSize = ((ObjSize + PtrByteSize - 1)/PtrByteSize) * PtrByteSize;
> > -      // Objects of size 1 and 2 are right justified, everything else is
> > -      // left justified.  This means the memory address is adjusted forwards.
> > +      // FOR DARWIN: Objects of size 1 and 2 are right justified, everything
> > +      // else is left justified.  This means the memory address is adjusted
> > +      // forwards.
> > +      // FOR 64-BIT SVR4: All aggregates smaller than 8 bytes must be passed
> > +      // right-justified.
> >        if (ObjSize==1 || ObjSize==2) {
> >          CurArgOffset = CurArgOffset + (4 - ObjSize);
> >        }
> > @@ -2085,7 +2091,8 @@ SDValue
> >        int FI = MFI->CreateFixedObject(ObjSize, CurArgOffset, true);
> >        SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
> >        InVals.push_back(FIN);
> > -      if (ObjSize==1 || ObjSize==2) {
> > +      if (ObjSize==1 || ObjSize==2 ||
> > +          (ObjSize==4 && isSVR4ABI)) {
> >          if (GPR_idx != Num_GPR_Regs) {
> >            unsigned VReg;
> >            if (isPPC64)
> > @@ -2093,10 +2100,11 @@ SDValue
> >            else
> >              VReg = MF.addLiveIn(GPR[GPR_idx], &PPC::GPRCRegClass);
> >            SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, PtrVT);
> > +          EVT ObjType = (ObjSize == 1 ? MVT::i8 :
> > +                         (ObjSize == 2 ? MVT::i16 : MVT::i32));
> >            SDValue Store = DAG.getTruncStore(Val.getValue(1), dl, Val, FIN,
> >                                              MachinePointerInfo(),
> > -                                            ObjSize==1 ? MVT::i8 : MVT::i16,
> > -                                            false, false, 0);
> > +                                            ObjType, false, false, 0);
> >            MemOps.push_back(Store);
> >            ++GPR_idx;
> >          }
> > @@ -2107,8 +2115,8 @@ SDValue
> >        }
> >        for (unsigned j = 0; j < ArgSize; j += PtrByteSize) {
> >          // Store whatever pieces of the object are in registers
> > -        // to memory.  ArgVal will be address of the beginning of
> > -        // the object.
> > +        // to memory.  ArgOffset will be the address of the beginning
> > +        // of the object.
> >          if (GPR_idx != Num_GPR_Regs) {
> >            unsigned VReg;
> >            if (isPPC64)
> > @@ -2118,7 +2126,16 @@ SDValue
> >            int FI = MFI->CreateFixedObject(PtrByteSize, ArgOffset, true);
> >            SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
> >            SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, PtrVT);
> > -          SDValue Store = DAG.getStore(Val.getValue(1), dl, Val, FIN,
> > +          SDValue Shifted = Val;
> > +
> > +          // For 64-bit SVR4, small structs come in right-adjusted.
> > +          // Shift them left so the following logic works as expected.
> > +          if (ObjSize < 8 && isSVR4ABI) {
> > +            SDValue ShiftAmt = DAG.getConstant(64 - 8 * ObjSize, PtrVT);
> > +            Shifted = DAG.getNode(ISD::SHL, dl, PtrVT, Val, ShiftAmt);
> > +          }
> > +
> > +          SDValue Store = DAG.getStore(Val.getValue(1), dl, Shifted, FIN,
> >                                         MachinePointerInfo(),
> >                                         false, false, 0);
> >            MemOps.push_back(Store);
> > @@ -2308,8 +2325,8 @@ SDValue
> >    return Chain;
> >  }
> >  
> > -/// CalculateParameterAndLinkageAreaSize - Get the size of the paramter plus
> > -/// linkage area for the Darwin ABI.
> > +/// CalculateParameterAndLinkageAreaSize - Get the size of the parameter plus
> > +/// linkage area for the Darwin ABI, or the 64-bit SVR4 ABI.
> >  static unsigned
> >  CalculateParameterAndLinkageAreaSize(SelectionDAG &DAG,
> >                                       bool isPPC64,
> > @@ -2718,7 +2735,7 @@ unsigned PrepareCall(SelectionDAG &DAG, SDValue &C
> >        // Thus for a call through a function pointer, the following actions need
> >        // to be performed:
> >        //   1. Save the TOC of the caller in the TOC save area of its stack
> > -      //      frame (this is done in LowerCall_Darwin()).
> > +      //      frame (this is done in LowerCall_Darwin_Or_64SVR4()).
> >        //   2. Load the address of the function entry point from the function
> >        //      descriptor.
> >        //   3. Load the TOC of the callee from the function descriptor into r2.
> > @@ -2960,25 +2977,25 @@ PPCTargetLowering::LowerCall(TargetLowering::CallL
> >                                                     Ins, DAG);
> >  
> >    if (PPCSubTarget.isSVR4ABI() && !PPCSubTarget.isPPC64())
> > -    return LowerCall_SVR4(Chain, Callee, CallConv, isVarArg,
> > -                          isTailCall, Outs, OutVals, Ins,
> > -                          dl, DAG, InVals);
> > +    return LowerCall_32SVR4(Chain, Callee, CallConv, isVarArg,
> > +                            isTailCall, Outs, OutVals, Ins,
> > +                            dl, DAG, InVals);
> >  
> > -  return LowerCall_Darwin(Chain, Callee, CallConv, isVarArg,
> > -                          isTailCall, Outs, OutVals, Ins,
> > -                          dl, DAG, InVals);
> > +  return LowerCall_Darwin_Or_64SVR4(Chain, Callee, CallConv, isVarArg,
> > +                                    isTailCall, Outs, OutVals, Ins,
> > +                                    dl, DAG, InVals);
> >  }
> >  
> >  SDValue
> > -PPCTargetLowering::LowerCall_SVR4(SDValue Chain, SDValue Callee,
> > -                                  CallingConv::ID CallConv, bool isVarArg,
> > -                                  bool isTailCall,
> > -                                  const SmallVectorImpl<ISD::OutputArg> &Outs,
> > -                                  const SmallVectorImpl<SDValue> &OutVals,
> > -                                  const SmallVectorImpl<ISD::InputArg> &Ins,
> > -                                  DebugLoc dl, SelectionDAG &DAG,
> > -                                  SmallVectorImpl<SDValue> &InVals) const {
> > -  // See PPCTargetLowering::LowerFormalArguments_SVR4() for a description
> > +PPCTargetLowering::LowerCall_32SVR4(SDValue Chain, SDValue Callee,
> > +                                    CallingConv::ID CallConv, bool isVarArg,
> > +                                    bool isTailCall,
> > +                                    const SmallVectorImpl<ISD::OutputArg> &Outs,
> > +                                    const SmallVectorImpl<SDValue> &OutVals,
> > +                                    const SmallVectorImpl<ISD::InputArg> &Ins,
> > +                                    DebugLoc dl, SelectionDAG &DAG,
> > +                                    SmallVectorImpl<SDValue> &InVals) const {
> > +  // See PPCTargetLowering::LowerFormalArguments_32SVR4() for a description
> >    // of the 32-bit SVR4 ABI stack frame layout.
> >  
> >    assert((CallConv == CallingConv::C ||
> > @@ -3183,7 +3200,7 @@ SDValue
> >  }
> >  
> >  SDValue
> > -PPCTargetLowering::LowerCall_Darwin(SDValue Chain, SDValue Callee,
> > +PPCTargetLowering::LowerCall_Darwin_Or_64SVR4(SDValue Chain, SDValue Callee,
> >                                      CallingConv::ID CallConv, bool isVarArg,
> >                                      bool isTailCall,
> >                                      const SmallVectorImpl<ISD::OutputArg> &Outs,
> > @@ -3192,6 +3209,8 @@ SDValue
> >                                      DebugLoc dl, SelectionDAG &DAG,
> >                                      SmallVectorImpl<SDValue> &InVals) const {
> >  
> > +  bool isSVR4ABI = PPCSubTarget.isSVR4ABI();
> > +
> >    unsigned NumOps  = Outs.size();
> >  
> >    EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
> > @@ -3299,12 +3318,22 @@ SDValue
> >      }
> >  
> >      // FIXME memcpy is used way more than necessary.  Correctness first.
> > +    // Note: "by value" is code for passing a structure by value, not
> > +    // basic types.
> >      if (Flags.isByVal()) {
> > +      // Note: Size includes alignment padding, so
> > +      //   struct x { short a; char b; }
> > +      // will have Size = 4.  With #pragma pack(1), it will have Size = 3.
> > +      // These are the proper values we need for right-justifying the
> > +      // aggregate in a parameter register for 64-bit SVR4.
> >        unsigned Size = Flags.getByValSize();
> > -      if (Size==1 || Size==2) {
> > -        // Very small objects are passed right-justified.
> > -        // Everything else is passed left-justified.
> > -        EVT VT = (Size==1) ? MVT::i8 : MVT::i16;
> > +      // FOR DARWIN ONLY:  Very small objects are passed right-justified.
> > +      // Everything else is passed left-justified.
> > +      // FOR 64-BIT SVR4:  All aggregates smaller than 8 bytes must
> > +      // be passed right-justified.
> > +      if (Size==1 || Size==2 ||
> > +          (Size==4 && isSVR4ABI)) {
> > +        EVT VT = (Size==1) ? MVT::i8 : ((Size==2) ? MVT::i16 : MVT::i32);
> >          if (GPR_idx != NumGPRs) {
> >            SDValue Load = DAG.getExtLoad(ISD::EXTLOAD, dl, PtrVT, Chain, Arg,
> >                                          MachinePointerInfo(), VT,
> > @@ -3332,15 +3361,67 @@ SDValue
> >        // Copy entire object into memory.  There are cases where gcc-generated
> >        // code assumes it is there, even if it could be put entirely into
> >        // registers.  (This is not what the doc says.)
> > -      SDValue MemcpyCall = CreateCopyOfByValArgument(Arg, PtrOff,
> > -                            CallSeqStart.getNode()->getOperand(0),
> > -                            Flags, DAG, dl);
> > -      // This must go outside the CALLSEQ_START..END.
> > -      SDValue NewCallSeqStart = DAG.getCALLSEQ_START(MemcpyCall,
> > -                           CallSeqStart.getNode()->getOperand(1));
> > -      DAG.ReplaceAllUsesWith(CallSeqStart.getNode(), NewCallSeqStart.getNode());
> > -      Chain = CallSeqStart = NewCallSeqStart;
> > -      // And copy the pieces of it that fit into registers.
> > +
> > +      // FIXME: The above statement is likely due to a misunderstanding of the
> > +      // documents.  At least for 64-bit SVR4, all arguments must be copied
> > +      // into the parameter area BY THE CALLEE in the event that the callee
> > +      // takes the address of any formal argument.  That has not yet been
> > +      // implemented.  However, it is reasonable to use the stack area as a
> > +      // staging area for the register load.
> > +
> > +      // Skip this for small aggregates under 64-bit SVR4, as we will use
> > +      // the same slot for a right-justified copy, below.
> > +      if (Size >= 8 || !isSVR4ABI) {
> > +        SDValue MemcpyCall = CreateCopyOfByValArgument(Arg, PtrOff,
> > +                              CallSeqStart.getNode()->getOperand(0),
> > +                              Flags, DAG, dl);
> > +        // This must go outside the CALLSEQ_START..END.
> > +        SDValue NewCallSeqStart = DAG.getCALLSEQ_START(MemcpyCall,
> > +                                   CallSeqStart.getNode()->getOperand(1));
> > +        DAG.ReplaceAllUsesWith(CallSeqStart.getNode(),
> > +                               NewCallSeqStart.getNode());
> > +        Chain = CallSeqStart = NewCallSeqStart;
> > +      }
> > +
> > +      // FOR 64-BIT SVR4:  When a register is available, pass the
> > +      // aggregate right-justified.
> > +      if (isSVR4ABI && Size < 8 && GPR_idx != NumGPRs) {
> > +        // The easiest way to get this right-justified in a register
> > +        // is to copy the structure into the rightmost portion of a
> > +        // local variable slot, then load the whole slot into the
> > +        // register.
> > +        // FIXME: The memcpy seems to produce pretty awful code for
> > +        // small aggregates, particularly for packed ones.
> > +        // FIXME: It would be preferable to use the slot in the 
> > +        // parameter save area instead of a new local variable.
> > +        SDValue Const = DAG.getConstant(8 - Size, PtrOff.getValueType());
> > +        SDValue AddPtr = DAG.getNode(ISD::ADD, dl, PtrVT, PtrOff, Const);
> > +        SDValue MemcpyCall = CreateCopyOfByValArgument(Arg, AddPtr,
> > +                              CallSeqStart.getNode()->getOperand(0),
> > +                              Flags, DAG, dl);
> > +
> > +        // Place the memcpy outside the CALLSEQ_START..END.
> > +        SDValue NewCallSeqStart = DAG.getCALLSEQ_START(MemcpyCall,
> > +                                   CallSeqStart.getNode()->getOperand(1));
> > +        DAG.ReplaceAllUsesWith(CallSeqStart.getNode(), 
> > +                               NewCallSeqStart.getNode());
> > +        Chain = CallSeqStart = NewCallSeqStart;
> > +
> > +        // Load the slot into the register.
> > +        SDValue Load = DAG.getLoad(PtrVT, dl, Chain, PtrOff,
> > +                                   MachinePointerInfo(),
> > +                                   false, false, false, 0);
> > +        MemOpChains.push_back(Load.getValue(1));
> > +        RegsToPass.push_back(std::make_pair(GPR[GPR_idx++], Load));
> > +
> > +        // Done with this argument.
> > +        ArgOffset += PtrByteSize;
> > +        continue;
> > +      }
> > +
> > +      // For small aggregates (Darwin only) and aggregates >= PtrByteSize,
> > +      // copy the pieces of the object that fit into registers from the
> > +      // parameter save area.
> >        for (unsigned j=0; j<Size; j+=PtrByteSize) {
> >          SDValue Const = DAG.getConstant(j, PtrOff.getValueType());
> >          SDValue AddArg = DAG.getNode(ISD::ADD, dl, PtrVT, Arg, Const);
> 




More information about the llvm-commits mailing list