Author: Ting Wang Date: 2022-10-16T22:01:47-04:00 New Revision: ee703b5cb134d182c2b589360714feab97f6a1cc
URL: https://github.com/llvm/llvm-project/commit/ee703b5cb134d182c2b589360714feab97f6a1cc DIFF: https://github.com/llvm/llvm-project/commit/ee703b5cb134d182c2b589360714feab97f6a1cc.diff LOG: [clang][PowerPC] PPC64 VAArg fix right-alignment for aggregates fit in register PPC64 ABI pass aggregates smaller than a register into the least significant bits of the register. In the case of variadic functions, they will end up right-aligned in their argument slots in the argument area on big-endian targets. Apply right-alignment for these aggregates. Fixes #55900. Reviewed By: rjmccall Differential Revision: https://reviews.llvm.org/D133338 Added: Modified: clang/lib/CodeGen/TargetInfo.cpp clang/test/CodeGen/PowerPC/ppc64-align-struct.c Removed: ################################################################################ diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index bfe0fbec2ad5..8253d15c26df 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -322,13 +322,17 @@ static llvm::Value *emitRoundPointerUpToAlignment(CodeGenFunction &CGF, /// leaving one or more empty slots behind as padding. If this /// is false, the returned address might be less-aligned than /// DirectAlign. +/// \param ForceRightAdjust - Default is false. On big-endian platform and +/// if the argument is smaller than a slot, set this flag will force +/// right-adjust the argument in its slot irrespective of the type. static Address emitVoidPtrDirectVAArg(CodeGenFunction &CGF, Address VAListAddr, llvm::Type *DirectTy, CharUnits DirectSize, CharUnits DirectAlign, CharUnits SlotSize, - bool AllowHigherAlign) { + bool AllowHigherAlign, + bool ForceRightAdjust = false) { // Cast the element type to i8* if necessary. Some platforms define // va_list as a struct containing an i8* instead of just an i8*. if (VAListAddr.getElementType() != CGF.Int8PtrTy) @@ -354,7 +358,7 @@ static Address emitVoidPtrDirectVAArg(CodeGenFunction &CGF, // If the argument is smaller than a slot, and this is a big-endian // target, the argument will be right-adjusted in its slot. if (DirectSize < SlotSize && CGF.CGM.getDataLayout().isBigEndian() && - !DirectTy->isStructTy()) { + (!DirectTy->isStructTy() || ForceRightAdjust)) { Addr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, SlotSize - DirectSize); } @@ -375,11 +379,15 @@ static Address emitVoidPtrDirectVAArg(CodeGenFunction &CGF, /// an argument type with an alignment greater than the slot size /// will be emitted on a higher-alignment address, potentially /// leaving one or more empty slots behind as padding. +/// \param ForceRightAdjust - Default is false. On big-endian platform and +/// if the argument is smaller than a slot, set this flag will force +/// right-adjust the argument in its slot irrespective of the type. static Address emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType ValueTy, bool IsIndirect, TypeInfoChars ValueInfo, CharUnits SlotSizeAndAlign, - bool AllowHigherAlign) { + bool AllowHigherAlign, + bool ForceRightAdjust = false) { // The size and alignment of the value that was passed directly. CharUnits DirectSize, DirectAlign; if (IsIndirect) { @@ -395,9 +403,9 @@ static Address emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr, if (IsIndirect) DirectTy = DirectTy->getPointerTo(0); - Address Addr = - emitVoidPtrDirectVAArg(CGF, VAListAddr, DirectTy, DirectSize, DirectAlign, - SlotSizeAndAlign, AllowHigherAlign); + Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, DirectTy, DirectSize, + DirectAlign, SlotSizeAndAlign, + AllowHigherAlign, ForceRightAdjust); if (IsIndirect) { Addr = Address(CGF.Builder.CreateLoad(Addr), ElementTy, ValueInfo.Align); @@ -5451,8 +5459,21 @@ Address PPC64_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, } // Otherwise, just use the general rule. - return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*Indirect*/ false, - TypeInfo, SlotSize, /*AllowHigher*/ true); + // + // The PPC64 ABI passes some arguments in integer registers, even to variadic + // functions. To allow va_list to use the simple "void*" representation, + // variadic calls allocate space in the argument area for the integer argument + // registers, and variadic functions spill their integer argument registers to + // this area in their prologues. When aggregates smaller than a register are + // passed this way, they are passed in the least significant bits of the + // register, which means that after spilling on big-endian targets they will + // be right-aligned in their argument slot. This is uncommon; for a variety of + // reasons, other big-endian targets don't end up right-aligning aggregate + // types this way, and so right-alignment only applies to fundamental types. + // So on PPC64, we must force the use of right-alignment even for aggregates. + return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*Indirect*/ false, TypeInfo, + SlotSize, /*AllowHigher*/ true, + /*ForceRightAdjust*/ true); } bool diff --git a/clang/test/CodeGen/PowerPC/ppc64-align-struct.c b/clang/test/CodeGen/PowerPC/ppc64-align-struct.c index 273b187483bd..b0d14546566c 100644 --- a/clang/test/CodeGen/PowerPC/ppc64-align-struct.c +++ b/clang/test/CodeGen/PowerPC/ppc64-align-struct.c @@ -128,12 +128,12 @@ struct test4 test4va (int x, ...) return y; } -// Error pattern will be fixed in https://reviews.llvm.org/D133338 // CHECK: define{{.*}} void @test8va(ptr noalias sret(%struct.test8) align 1 %[[AGG_RESULT:.*]], i32 noundef signext %x, ...) // CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %ap // CHECK: %[[NEXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 8 // CHECK: store ptr %[[NEXT]], ptr %ap -// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[AGG_RESULT]], ptr align 8 %[[CUR]], i64 1, i1 false) +// CHECK: [[T0:%.*]] = getelementptr inbounds i8, ptr %[[CUR]], i64 7 +// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[AGG_RESULT]], ptr align 1 [[T0]], i64 1, i1 false) struct test8 test8va (int x, ...) { struct test8 y; @@ -144,12 +144,12 @@ struct test8 test8va (int x, ...) return y; } -// Error pattern will be fixed in https://reviews.llvm.org/D133338 // CHECK: define{{.*}} void @test9va(ptr noalias sret(%struct.test9) align 1 %[[AGG_RESULT:.*]], i32 noundef signext %x, ...) // CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %ap // CHECK: %[[NEXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 8 // CHECK: store ptr %[[NEXT]], ptr %ap -// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[AGG_RESULT]], ptr align 8 %[[CUR]], i64 2, i1 false) +// CHECK: [[T0:%.*]] = getelementptr inbounds i8, ptr %[[CUR]], i64 6 +// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[AGG_RESULT]], ptr align 2 [[T0]], i64 2, i1 false) struct test9 test9va (int x, ...) { struct test9 y; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits