diff --git a/compiler-rt/test/asan/TestCases/alloca_vla_interact.cpp b/compiler-rt/test/asan/TestCases/alloca_vla_interact.cpp index 96ac4c7db291a..b98bb726dcebc 100644 --- a/compiler-rt/test/asan/TestCases/alloca_vla_interact.cpp +++ b/compiler-rt/test/asan/TestCases/alloca_vla_interact.cpp @@ -3,6 +3,9 @@ // // REQUIRES: stable-runtime +// See https://github.com/llvm/llvm-project/issues/110956 +// XFAIL: target=sparc{{.*}} + // This testcase checks correct interaction between VLAs and allocas. #include diff --git a/llvm/lib/Target/Sparc/SparcFrameLowering.cpp b/llvm/lib/Target/Sparc/SparcFrameLowering.cpp index 000418be9a9e3..4ff389605e944 100644 --- a/llvm/lib/Target/Sparc/SparcFrameLowering.cpp +++ b/llvm/lib/Target/Sparc/SparcFrameLowering.cpp @@ -35,7 +35,8 @@ DisableLeafProc("disable-sparc-leaf-proc", SparcFrameLowering::SparcFrameLowering(const SparcSubtarget &ST) : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, ST.is64Bit() ? Align(16) : Align(8), 0, - ST.is64Bit() ? Align(16) : Align(8)) {} + ST.is64Bit() ? Align(16) : Align(8), + /*StackRealignable=*/false) {} void SparcFrameLowering::emitSPAdjustment(MachineFunction &MF, MachineBasicBlock &MBB, @@ -97,12 +98,6 @@ void SparcFrameLowering::emitPrologue(MachineFunction &MF, // Debug location must be unknown since the first debug location is used // to determine the end of the prologue. DebugLoc dl; - bool NeedsStackRealignment = RegInfo.shouldRealignStack(MF); - - if (NeedsStackRealignment && !RegInfo.canRealignStack(MF)) - report_fatal_error("Function \"" + Twine(MF.getName()) + "\" required " - "stack re-alignment, but LLVM couldn't handle it " - "(probably because it has a dynamic alloca)."); // Get the number of bytes to allocate from the FrameInfo int NumBytes = (int) MFI.getStackSize(); @@ -168,31 +163,6 @@ void SparcFrameLowering::emitPrologue(MachineFunction &MF, MCCFIInstruction::createRegister(nullptr, regOutRA, regInRA)); BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex); - - if (NeedsStackRealignment) { - int64_t Bias = Subtarget.getStackPointerBias(); - unsigned regUnbiased; - if (Bias) { - // This clobbers G1 which we always know is available here. - regUnbiased = SP::G1; - // add %o6, BIAS, %g1 - BuildMI(MBB, MBBI, dl, TII.get(SP::ADDri), regUnbiased) - .addReg(SP::O6).addImm(Bias); - } else - regUnbiased = SP::O6; - - // andn %regUnbiased, MaxAlign-1, %regUnbiased - Align MaxAlign = MFI.getMaxAlign(); - BuildMI(MBB, MBBI, dl, TII.get(SP::ANDNri), regUnbiased) - .addReg(regUnbiased) - .addImm(MaxAlign.value() - 1U); - - if (Bias) { - // add %g1, -BIAS, %o6 - BuildMI(MBB, MBBI, dl, TII.get(SP::ADDri), SP::O6) - .addReg(regUnbiased).addImm(-Bias); - } - } } MachineBasicBlock::iterator SparcFrameLowering:: @@ -257,8 +227,7 @@ bool SparcFrameLowering::hasFP(const MachineFunction &MF) const { const MachineFrameInfo &MFI = MF.getFrameInfo(); return MF.getTarget().Options.DisableFramePointerElim(MF) || - RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() || - MFI.isFrameAddressTaken(); + MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken(); } StackOffset @@ -284,11 +253,6 @@ SparcFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, } else if (isFixed) { // Otherwise, argument access should always use %fp. UseFP = true; - } else if (RegInfo->hasStackRealignment(MF)) { - // If there is dynamic stack realignment, all local object - // references need to be via %sp, to take account of the - // re-alignment. - UseFP = false; } else { // Finally, default to using %fp. UseFP = true; diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp index 42b8248006d1f..44f083e4f70cd 100644 --- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -2762,22 +2762,16 @@ static SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) { static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG, const SparcSubtarget *Subtarget) { - SDValue Chain = Op.getOperand(0); // Legalize the chain. - SDValue Size = Op.getOperand(1); // Legalize the size. - MaybeAlign Alignment = - cast(Op.getOperand(2))->getMaybeAlignValue(); - Align StackAlign = Subtarget->getFrameLowering()->getStackAlign(); + SDValue Chain = Op.getOperand(0); + SDValue Size = Op.getOperand(1); + SDValue Alignment = Op.getOperand(2); + MaybeAlign MaybeAlignment = + cast(Alignment)->getMaybeAlignValue(); EVT VT = Size->getValueType(0); SDLoc dl(Op); - // TODO: implement over-aligned alloca. (Note: also implies - // supporting support for overaligned function frames + dynamic - // allocations, at all, which currently isn't supported) - if (Alignment && *Alignment > StackAlign) { - const MachineFunction &MF = DAG.getMachineFunction(); - report_fatal_error("Function \"" + Twine(MF.getName()) + "\": " - "over-aligned dynamic alloca not supported."); - } + unsigned SPReg = SP::O6; + SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, VT); // The resultant pointer needs to be above the register spill area // at the bottom of the stack. @@ -2811,16 +2805,29 @@ static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG, regSpillArea = 96; } - unsigned SPReg = SP::O6; - SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, VT); - SDValue NewSP = DAG.getNode(ISD::SUB, dl, VT, SP, Size); // Value - Chain = DAG.getCopyToReg(SP.getValue(1), dl, SPReg, NewSP); // Output chain - - regSpillArea += Subtarget->getStackPointerBias(); - - SDValue NewVal = DAG.getNode(ISD::ADD, dl, VT, NewSP, - DAG.getConstant(regSpillArea, dl, VT)); - SDValue Ops[2] = { NewVal, Chain }; + int64_t Bias = Subtarget->getStackPointerBias(); + + // Debias and increment SP past the reserved spill area. + // We need the SP to point to the first usable region before calculating + // anything to prevent any of the pointers from becoming out of alignment when + // we rebias the SP later on. + SDValue StartOfUsableStack = DAG.getNode( + ISD::ADD, dl, VT, SP, DAG.getConstant(regSpillArea + Bias, dl, VT)); + SDValue AllocatedPtr = + DAG.getNode(ISD::SUB, dl, VT, StartOfUsableStack, Size); + + bool IsOveraligned = MaybeAlignment.has_value(); + SDValue AlignedPtr = + IsOveraligned + ? DAG.getNode(ISD::AND, dl, VT, AllocatedPtr, + DAG.getConstant(-MaybeAlignment->value(), dl, VT)) + : AllocatedPtr; + + // Now that we are done, restore the bias and reserved spill area. + SDValue NewSP = DAG.getNode(ISD::SUB, dl, VT, AlignedPtr, + DAG.getConstant(regSpillArea + Bias, dl, VT)); + Chain = DAG.getCopyToReg(SP.getValue(1), dl, SPReg, NewSP); + SDValue Ops[2] = {AlignedPtr, Chain}; return DAG.getMergeValues(Ops, dl); } diff --git a/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp b/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp index 71a27f77d2c6b..e4db27a63076d 100644 --- a/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp +++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp @@ -226,26 +226,3 @@ SparcRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, Register SparcRegisterInfo::getFrameRegister(const MachineFunction &MF) const { return SP::I6; } - -// Sparc has no architectural need for stack realignment support, -// except that LLVM unfortunately currently implements overaligned -// stack objects by depending upon stack realignment support. -// If that ever changes, this can probably be deleted. -bool SparcRegisterInfo::canRealignStack(const MachineFunction &MF) const { - if (!TargetRegisterInfo::canRealignStack(MF)) - return false; - - // Sparc always has a fixed frame pointer register, so don't need to - // worry about needing to reserve it. [even if we don't have a frame - // pointer for our frame, it still cannot be used for other things, - // or register window traps will be SADNESS.] - - // If there's a reserved call frame, we can use SP to access locals. - if (getFrameLowering(MF)->hasReservedCallFrame(MF)) - return true; - - // Otherwise, we'd need a base pointer, but those aren't implemented - // for SPARC at the moment. - - return false; -} diff --git a/llvm/lib/Target/Sparc/SparcRegisterInfo.h b/llvm/lib/Target/Sparc/SparcRegisterInfo.h index 58c85f33635f2..eae859ce1a519 100644 --- a/llvm/lib/Target/Sparc/SparcRegisterInfo.h +++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.h @@ -40,9 +40,6 @@ struct SparcRegisterInfo : public SparcGenRegisterInfo { RegScavenger *RS = nullptr) const override; Register getFrameRegister(const MachineFunction &MF) const override; - - bool canRealignStack(const MachineFunction &MF) const override; - }; } // end namespace llvm diff --git a/llvm/test/CodeGen/Generic/ForceStackAlign.ll b/llvm/test/CodeGen/Generic/ForceStackAlign.ll index 7993b3eff65b6..811a192e752ab 100644 --- a/llvm/test/CodeGen/Generic/ForceStackAlign.ll +++ b/llvm/test/CodeGen/Generic/ForceStackAlign.ll @@ -5,9 +5,6 @@ ; CHECK-LABEL: @f ; CHECK-LABEL: @g -; Stack realignment not supported. -; XFAIL: target=sparc{{.*}} - ; NVPTX can only select dynamic_stackalloc on sm_52+ and with ptx73+ ; XFAIL: target=nvptx{{.*}} diff --git a/llvm/test/CodeGen/SPARC/2013-05-17-CallFrame.ll b/llvm/test/CodeGen/SPARC/2013-05-17-CallFrame.ll index 3f6d28385e267..9ebedfb68102f 100644 --- a/llvm/test/CodeGen/SPARC/2013-05-17-CallFrame.ll +++ b/llvm/test/CodeGen/SPARC/2013-05-17-CallFrame.ll @@ -5,14 +5,10 @@ ; (this should ideally be doing "add 4+7; and -8", instead of ; "add 7; and -8; add 8"; see comments in LowerDYNAMIC_STACKALLOC) -define void @variable_alloca_with_adj_call_stack(i32 %num) { +define void @variable_alloca_with_adj_call_stack(i32 %num) nounwind { ; V8-LABEL: variable_alloca_with_adj_call_stack: -; V8: .cfi_startproc -; V8-NEXT: ! %bb.0: ! %entry +; V8: ! %bb.0: ! %entry ; V8-NEXT: save %sp, -96, %sp -; V8-NEXT: .cfi_def_cfa_register %fp -; V8-NEXT: .cfi_window_save -; V8-NEXT: .cfi_register %o7, %i7 ; V8-NEXT: add %i0, 7, %i0 ; V8-NEXT: and %i0, -8, %i0 ; V8-NEXT: sub %sp, %i0, %i0 @@ -34,12 +30,8 @@ define void @variable_alloca_with_adj_call_stack(i32 %num) { ; V8-NEXT: restore ; ; SPARC64-LABEL: variable_alloca_with_adj_call_stack: -; SPARC64: .cfi_startproc -; SPARC64-NEXT: ! %bb.0: ! %entry +; SPARC64: ! %bb.0: ! %entry ; SPARC64-NEXT: save %sp, -128, %sp -; SPARC64-NEXT: .cfi_def_cfa_register %fp -; SPARC64-NEXT: .cfi_window_save -; SPARC64-NEXT: .cfi_register %o7, %i7 ; SPARC64-NEXT: srl %i0, 0, %i0 ; SPARC64-NEXT: add %i0, 15, %i0 ; SPARC64-NEXT: sethi 4194303, %i1 diff --git a/llvm/test/CodeGen/SPARC/alloca-align.ll b/llvm/test/CodeGen/SPARC/alloca-align.ll new file mode 100644 index 0000000000000..f6330f16df473 --- /dev/null +++ b/llvm/test/CodeGen/SPARC/alloca-align.ll @@ -0,0 +1,93 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -march=sparc < %s | FileCheck %s --check-prefixes=CHECK32 +; RUN: llc -march=sparcv9 < %s | FileCheck %s --check-prefixes=CHECK64 + +define void @variable_alloca_with_overalignment(i32 %num) nounwind { +; CHECK32-LABEL: variable_alloca_with_overalignment: +; CHECK32: ! %bb.0: +; CHECK32-NEXT: save %sp, -96, %sp +; CHECK32-NEXT: add %sp, 80, %i1 +; CHECK32-NEXT: and %i1, -64, %o0 +; CHECK32-NEXT: add %o0, -96, %sp +; CHECK32-NEXT: add %i0, 7, %i0 +; CHECK32-NEXT: and %i0, -8, %i0 +; CHECK32-NEXT: sub %sp, %i0, %i0 +; CHECK32-NEXT: add %i0, -8, %sp +; CHECK32-NEXT: call foo +; CHECK32-NEXT: add %i0, 88, %o1 +; CHECK32-NEXT: ret +; CHECK32-NEXT: restore +; +; CHECK64-LABEL: variable_alloca_with_overalignment: +; CHECK64: ! %bb.0: +; CHECK64-NEXT: save %sp, -128, %sp +; CHECK64-NEXT: add %sp, 2159, %i1 +; CHECK64-NEXT: and %i1, -64, %o0 +; CHECK64-NEXT: add %o0, -2175, %sp +; CHECK64-NEXT: srl %i0, 0, %i0 +; CHECK64-NEXT: add %i0, 15, %i0 +; CHECK64-NEXT: sethi 4194303, %i1 +; CHECK64-NEXT: or %i1, 1008, %i1 +; CHECK64-NEXT: sethi 0, %i2 +; CHECK64-NEXT: or %i2, 1, %i2 +; CHECK64-NEXT: sllx %i2, 32, %i2 +; CHECK64-NEXT: or %i2, %i1, %i1 +; CHECK64-NEXT: and %i0, %i1, %i0 +; CHECK64-NEXT: sub %sp, %i0, %i0 +; CHECK64-NEXT: add %i0, 2175, %o1 +; CHECK64-NEXT: mov %i0, %sp +; CHECK64-NEXT: call foo +; CHECK64-NEXT: add %sp, -48, %sp +; CHECK64-NEXT: add %sp, 48, %sp +; CHECK64-NEXT: ret +; CHECK64-NEXT: restore + %aligned = alloca i32, align 64 + %var_size = alloca i8, i32 %num, align 4 + call void @foo(ptr %aligned, ptr %var_size) + ret void +} + +;; Same but with the alloca itself overaligned +define void @variable_alloca_with_overalignment_2(i32 %num) nounwind { +; CHECK32-LABEL: variable_alloca_with_overalignment_2: +; CHECK32: ! %bb.0: +; CHECK32-NEXT: save %sp, -96, %sp +; CHECK32-NEXT: add %i0, 7, %i0 +; CHECK32-NEXT: and %i0, -8, %i0 +; CHECK32-NEXT: sub %sp, %i0, %i0 +; CHECK32-NEXT: add %i0, 88, %i0 +; CHECK32-NEXT: and %i0, -64, %o1 +; CHECK32-NEXT: add %o1, -96, %sp +; CHECK32-NEXT: call foo +; CHECK32-NEXT: mov %g0, %o0 +; CHECK32-NEXT: ret +; CHECK32-NEXT: restore +; +; CHECK64-LABEL: variable_alloca_with_overalignment_2: +; CHECK64: ! %bb.0: +; CHECK64-NEXT: save %sp, -128, %sp +; CHECK64-NEXT: srl %i0, 0, %i0 +; CHECK64-NEXT: add %i0, 15, %i0 +; CHECK64-NEXT: sethi 4194303, %i1 +; CHECK64-NEXT: or %i1, 1008, %i1 +; CHECK64-NEXT: sethi 0, %i2 +; CHECK64-NEXT: or %i2, 1, %i2 +; CHECK64-NEXT: sllx %i2, 32, %i2 +; CHECK64-NEXT: or %i2, %i1, %i1 +; CHECK64-NEXT: and %i0, %i1, %i0 +; CHECK64-NEXT: sub %sp, %i0, %i0 +; CHECK64-NEXT: add %i0, 2175, %i0 +; CHECK64-NEXT: and %i0, -64, %o1 +; CHECK64-NEXT: add %o1, -2175, %sp +; CHECK64-NEXT: add %sp, -48, %sp +; CHECK64-NEXT: call foo +; CHECK64-NEXT: mov %g0, %o0 +; CHECK64-NEXT: add %sp, 48, %sp +; CHECK64-NEXT: ret +; CHECK64-NEXT: restore + %var_size = alloca i8, i32 %num, align 64 + call void @foo(ptr null, ptr %var_size) + ret void +} + +declare void @foo(ptr, ptr); diff --git a/llvm/test/CodeGen/SPARC/fail-alloca-align.ll b/llvm/test/CodeGen/SPARC/fail-alloca-align.ll deleted file mode 100644 index e2dc235389b1d..0000000000000 --- a/llvm/test/CodeGen/SPARC/fail-alloca-align.ll +++ /dev/null @@ -1,23 +0,0 @@ -;; Sparc backend can't currently handle variable allocas with -;; alignment greater than the stack alignment. This code ought to -;; compile, but doesn't currently. - -;; RUN: not --crash llc -march=sparc < %s 2>&1 | FileCheck %s -;; RUN: not --crash llc -march=sparcv9 < %s 2>&1 | FileCheck %s -;; CHECK: ERROR: Function {{.*}} required stack re-alignment - -define void @variable_alloca_with_overalignment(i32 %num) { - %aligned = alloca i32, align 64 - %var_size = alloca i8, i32 %num, align 4 - call void @foo(ptr %aligned, ptr %var_size) - ret void -} - -;; Same but with the alloca itself overaligned -define void @variable_alloca_with_overalignment_2(i32 %num) { - %var_size = alloca i8, i32 %num, align 64 - call void @foo(ptr null, ptr %var_size) - ret void -} - -declare void @foo(ptr, ptr); diff --git a/llvm/test/CodeGen/SPARC/fp128.ll b/llvm/test/CodeGen/SPARC/fp128.ll index 80f3da285e053..3e43d3eb5da70 100644 --- a/llvm/test/CodeGen/SPARC/fp128.ll +++ b/llvm/test/CodeGen/SPARC/fp128.ll @@ -54,18 +54,10 @@ entry: ; CHECK-LABEL: f128_spill_large: ; CHECK: sethi 4, %g1 -; CHECK: sethi 4, %g1 -; CHECK-NEXT: add %g1, %sp, %g1 -; CHECK-NEXT: std %f{{.+}}, [%g1] -; CHECK: sethi 4, %g1 -; CHECK-NEXT: add %g1, %sp, %g1 -; CHECK-NEXT: std %f{{.+}}, [%g1+8] -; CHECK: sethi 4, %g1 -; CHECK-NEXT: add %g1, %sp, %g1 -; CHECK-NEXT: ldd [%g1], %f{{.+}} -; CHECK: sethi 4, %g1 -; CHECK-NEXT: add %g1, %sp, %g1 -; CHECK-NEXT: ldd [%g1+8], %f{{.+}} +; CHECK: std %f{{.+}}, [%fp+-16] +; CHECK-NEXT: std %f{{.+}}, [%fp+-8] +; CHECK: ldd [%fp+-16], %f{{.+}} +; CHECK-NEXT: ldd [%fp+-8], %f{{.+}} define void @f128_spill_large(ptr noalias sret(<251 x fp128>) %scalar.result, ptr byval(<251 x fp128>) %a) { entry: diff --git a/llvm/test/CodeGen/SPARC/stack-align.ll b/llvm/test/CodeGen/SPARC/stack-align.ll index 6632237f08e27..c861b2d0296f0 100644 --- a/llvm/test/CodeGen/SPARC/stack-align.ll +++ b/llvm/test/CodeGen/SPARC/stack-align.ll @@ -1,24 +1,37 @@ -; RUN: llc -march=sparc < %s | FileCheck %s --check-prefixes=CHECK,CHECK32 -; RUN: llc -march=sparcv9 < %s | FileCheck %s --check-prefixes=CHECK,CHECK64 +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -march=sparc < %s | FileCheck %s --check-prefixes=CHECK32 +; RUN: llc -march=sparcv9 < %s | FileCheck %s --check-prefixes=CHECK64 declare void @stack_realign_helper(i32 %a, ptr %b) ;; This is a function where we have a local variable of 64-byte -;; alignment. We want to see that the stack is aligned (the initial -;; andn), that the local var is accessed via stack pointer (to %o1), and that +;; alignment. We want to see that the stack is aligned (the initial add/and), +;; that the local var is accessed via stack pointer (to %o1), and that ;; the argument is accessed via frame pointer not stack pointer (to %o0). -;; CHECK-LABEL: stack_realign: -;; CHECK32: andn %sp, 63, %sp -;; CHECK32-NEXT: ld [%fp+92], %o0 -;; CHECK64: add %sp, 2047, %g1 -;; CHECK64-NEXT: andn %g1, 63, %g1 -;; CHECK64-NEXT: add %g1, -2047, %sp -;; CHECK64-NEXT: ld [%fp+2227], %o0 -;; CHECK-NEXT: call stack_realign_helper -;; CHECK32-NEXT: add %sp, 128, %o1 -;; CHECK64-NEXT: add %sp, 2239, %o1 - -define void @stack_realign(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g) { +define void @stack_realign(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g) nounwind { +; CHECK32-LABEL: stack_realign: +; CHECK32: ! %bb.0: ! %entry +; CHECK32-NEXT: save %sp, -96, %sp +; CHECK32-NEXT: ld [%fp+92], %o0 +; CHECK32-NEXT: add %sp, 80, %i0 +; CHECK32-NEXT: and %i0, -64, %o1 +; CHECK32-NEXT: call stack_realign_helper +; CHECK32-NEXT: add %o1, -96, %sp +; CHECK32-NEXT: ret +; CHECK32-NEXT: restore +; +; CHECK64-LABEL: stack_realign: +; CHECK64: ! %bb.0: ! %entry +; CHECK64-NEXT: save %sp, -128, %sp +; CHECK64-NEXT: add %sp, 2159, %i0 +; CHECK64-NEXT: and %i0, -64, %o1 +; CHECK64-NEXT: add %o1, -2175, %sp +; CHECK64-NEXT: add %sp, -48, %sp +; CHECK64-NEXT: call stack_realign_helper +; CHECK64-NEXT: ld [%fp+2227], %o0 +; CHECK64-NEXT: add %sp, 48, %sp +; CHECK64-NEXT: ret +; CHECK64-NEXT: restore entry: %aligned = alloca i32, align 64 call void @stack_realign_helper(i32 %g, ptr %aligned)