From edb27188b433292536bb79543cdc39337cb52d25 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Fri, 11 Jul 2014 17:19:31 +0000 Subject: [PATCH] [PowerPC] Fix invalid displacement created by LocalStackAlloc This commit fixes a bug in PPCRegisterInfo::isFrameOffsetLegal that could result in the LocalStackAlloc pass creating an MI instruction out-of-range displacement: %vreg17 = LD 33184, %vreg31; mem:LD8[%g](align=32) %G8RC:%vreg17 G8RC_and_G8RC_NOX0:%vreg31 (In final assembler output the top bits are stripped off, resulting in a negative offset loading from below the stack pointer.) Common code expects the isFrameOffsetLegal routine to verify whether adding a given offset to the offset already present in the instruction results in a valid displacement. However, on PowerPC the routine did not take the already present instruction offset into account. This commit fixes isFrameOffsetLegal to add the instruction offset, and updates a local caller (needsFrameBaseReg) to no longer add the instruction offset itself before calling isFrameOffsetLegal. Reviewed by Hal Finkel. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@212832 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/PowerPC/PPCRegisterInfo.cpp | 20 ++++---- test/CodeGen/PowerPC/resolvefi-disp.ll | 71 ++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 10 deletions(-) create mode 100644 test/CodeGen/PowerPC/resolvefi-disp.ll diff --git a/lib/Target/PowerPC/PPCRegisterInfo.cpp b/lib/Target/PowerPC/PPCRegisterInfo.cpp index eca774ead9353..5149a8c23f144 100644 --- a/lib/Target/PowerPC/PPCRegisterInfo.cpp +++ b/lib/Target/PowerPC/PPCRegisterInfo.cpp @@ -885,16 +885,6 @@ bool PPCRegisterInfo:: needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const { assert(Offset < 0 && "Local offset must be negative"); - unsigned FIOperandNum = 0; - while (!MI->getOperand(FIOperandNum).isFI()) { - ++FIOperandNum; - assert(FIOperandNum < MI->getNumOperands() && - "Instr doesn't have FrameIndex operand!"); - } - - unsigned OffsetOperandNo = getOffsetONFromFION(*MI, FIOperandNum); - Offset += MI->getOperand(OffsetOperandNo).getImm(); - // It's the load/store FI references that cause issues, as it can be difficult // to materialize the offset if it won't fit in the literal field. Estimate // based on the size of the local frame and some conservative assumptions @@ -985,6 +975,16 @@ void PPCRegisterInfo::resolveFrameIndex(MachineInstr &MI, unsigned BaseReg, bool PPCRegisterInfo::isFrameOffsetLegal(const MachineInstr *MI, int64_t Offset) const { + unsigned FIOperandNum = 0; + while (!MI->getOperand(FIOperandNum).isFI()) { + ++FIOperandNum; + assert(FIOperandNum < MI->getNumOperands() && + "Instr doesn't have FrameIndex operand!"); + } + + unsigned OffsetOperandNo = getOffsetONFromFION(*MI, FIOperandNum); + Offset += MI->getOperand(OffsetOperandNo).getImm(); + return MI->getOpcode() == PPC::DBG_VALUE || // DBG_VALUE is always Reg+Imm (isInt<16>(Offset) && (!usesIXAddr(*MI) || (Offset & 3) == 0)); } diff --git a/test/CodeGen/PowerPC/resolvefi-disp.ll b/test/CodeGen/PowerPC/resolvefi-disp.ll new file mode 100644 index 0000000000000..ca42bcd767a09 --- /dev/null +++ b/test/CodeGen/PowerPC/resolvefi-disp.ll @@ -0,0 +1,71 @@ +; RUN: llc -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr7 -print-after=localstackalloc <%s >%t 2>&1 && FileCheck <%t %s + +; Due to a bug in isFrameOffsetLegal we ended up with resolveFrameIndex creating +; addresses with out-of-range displacements. Verify that this no longer happens. +; CHECK-NOT: LD {{3276[8-9]}} +; CHECK-NOT: LD {{327[7-9][0-9]}} +; CHECK-NOT: LD {{32[8-9][0-9][0-9]}} +; CHECK-NOT: LD {{3[3-9][0-9][0-9][0-9]}} +; CHECK-NOT: LD {{[4-9][0-9][0-9][0-9][0-9]}} +; CHECK-NOT: LD {{[1-9][0-9][0-9][0-9][0-9][0-9]+}} + +target datalayout = "e-m:e-i64:64-n32:64" +target triple = "powerpc64le-unknown-linux-gnu" + +%struct.S2760 = type { <2 x float>, %struct.anon, i32, [28 x i8] } +%struct.anon = type { [11 x %struct.anon.0], i64, [6 x { i64, i64 }], [24 x i8] } +%struct.anon.0 = type { [30 x %union.U4DI], i8, [0 x i16], [30 x i8] } +%union.U4DI = type { <4 x i64> } + +@s2760 = external global %struct.S2760 +@fails = external global i32 + +define void @check2760(%struct.S2760* noalias sret %agg.result, %struct.S2760* byval align 16, %struct.S2760* %arg1, %struct.S2760* byval align 16) { +entry: + %arg0 = alloca %struct.S2760, align 32 + %arg2 = alloca %struct.S2760, align 32 + %arg1.addr = alloca %struct.S2760*, align 8 + %ret = alloca %struct.S2760, align 32 + %b1 = alloca %struct.S2760, align 32 + %b2 = alloca %struct.S2760, align 32 + %2 = bitcast %struct.S2760* %arg0 to i8* + %3 = bitcast %struct.S2760* %0 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* %3, i64 11104, i32 16, i1 false) + %4 = bitcast %struct.S2760* %arg2 to i8* + %5 = bitcast %struct.S2760* %1 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %4, i8* %5, i64 11104, i32 16, i1 false) + store %struct.S2760* %arg1, %struct.S2760** %arg1.addr, align 8 + %6 = bitcast %struct.S2760* %ret to i8* + call void @llvm.memset.p0i8.i64(i8* %6, i8 0, i64 11104, i32 32, i1 false) + %7 = bitcast %struct.S2760* %b1 to i8* + call void @llvm.memset.p0i8.i64(i8* %7, i8 0, i64 11104, i32 32, i1 false) + %8 = bitcast %struct.S2760* %b2 to i8* + call void @llvm.memset.p0i8.i64(i8* %8, i8 0, i64 11104, i32 32, i1 false) + %b = getelementptr inbounds %struct.S2760* %arg0, i32 0, i32 1 + %g = getelementptr inbounds %struct.anon* %b, i32 0, i32 1 + %9 = load i64* %g, align 8 + %10 = load i64* getelementptr inbounds (%struct.S2760* @s2760, i32 0, i32 1, i32 1), align 8 + %cmp = icmp ne i64 %9, %10 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + %11 = load i32* @fails, align 4 + %inc = add nsw i32 %11, 1 + store i32 %inc, i32* @fails, align 4 + br label %if.end + +if.end: ; preds = %if.then, %entry + %12 = load i64* getelementptr inbounds (%struct.S2760* @s2760, i32 0, i32 1, i32 1), align 8 + %b3 = getelementptr inbounds %struct.S2760* %ret, i32 0, i32 1 + %g4 = getelementptr inbounds %struct.anon* %b3, i32 0, i32 1 + store i64 %12, i64* %g4, align 8 + %13 = bitcast %struct.S2760* %agg.result to i8* + %14 = bitcast %struct.S2760* %ret to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %13, i8* %14, i64 11104, i32 32, i1 false) + ret void +} + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) + +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) +