Index: llvm/trunk/lib/Target/SystemZ/SystemZISelLowering.h =================================================================== --- llvm/trunk/lib/Target/SystemZ/SystemZISelLowering.h +++ llvm/trunk/lib/Target/SystemZ/SystemZISelLowering.h @@ -426,6 +426,13 @@ return SystemZ::R7D; } + /// Override to support customized stack guard loading. + bool useLoadStackGuardNode() const override { + return true; + } + void insertSSPDeclarations(Module &M) const override { + } + MachineBasicBlock *EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *BB) const override; Index: llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.h =================================================================== --- llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.h +++ llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.h @@ -141,6 +141,7 @@ unsigned HighOpcode) const; void expandZExtPseudo(MachineInstr *MI, unsigned LowOpcode, unsigned Size) const; + void expandLoadStackGuard(MachineInstr *MI) const; void emitGRX32Move(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL, unsigned DestReg, unsigned SrcReg, unsigned LowLowOpcode, unsigned Size, bool KillSrc) const; Index: llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.cpp =================================================================== --- llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.cpp +++ llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -160,6 +160,37 @@ MI->eraseFromParent(); } +void SystemZInstrInfo::expandLoadStackGuard(MachineInstr *MI) const { + MachineBasicBlock *MBB = MI->getParent(); + MachineFunction &MF = *MBB->getParent(); + const unsigned Reg = MI->getOperand(0).getReg(); + + // Conveniently, all 4 instructions are cloned from LOAD_STACK_GUARD, + // so they already have operand 0 set to reg. + + // ear , %a0 + MachineInstr *Ear1MI = MF.CloneMachineInstr(MI); + MBB->insert(MI, Ear1MI); + Ear1MI->setDesc(get(SystemZ::EAR)); + MachineInstrBuilder(MF, Ear1MI).addImm(0); + + // sllg , , 32 + MachineInstr *SllgMI = MF.CloneMachineInstr(MI); + MBB->insert(MI, SllgMI); + SllgMI->setDesc(get(SystemZ::SLLG)); + MachineInstrBuilder(MF, SllgMI).addReg(Reg).addReg(0).addImm(32); + + // ear , %a1 + MachineInstr *Ear2MI = MF.CloneMachineInstr(MI); + MBB->insert(MI, Ear2MI); + Ear2MI->setDesc(get(SystemZ::EAR)); + MachineInstrBuilder(MF, Ear2MI).addImm(1); + + // lg , 40() + MI->setDesc(get(SystemZ::LG)); + MachineInstrBuilder(MF, MI).addReg(Reg).addImm(40).addReg(0); +} + // Emit a zero-extending move from 32-bit GPR SrcReg to 32-bit GPR // DestReg before MBBI in MBB. Use LowLowOpcode when both DestReg and SrcReg // are low registers, otherwise use RISB[LH]G. Size is the number of bits @@ -1100,6 +1131,10 @@ splitAdjDynAlloc(MI); return true; + case TargetOpcode::LOAD_STACK_GUARD: + expandLoadStackGuard(MI); + return true; + default: return false; } Index: llvm/trunk/lib/Target/SystemZ/SystemZRegisterInfo.h =================================================================== --- llvm/trunk/lib/Target/SystemZ/SystemZRegisterInfo.h +++ llvm/trunk/lib/Target/SystemZ/SystemZRegisterInfo.h @@ -33,6 +33,15 @@ public: SystemZRegisterInfo(); + /// getPointerRegClass - Return the register class to use to hold pointers. + /// This is currently only used by LOAD_STACK_GUARD, which requires a non-%r0 + /// register, hence ADDR64. + const TargetRegisterClass * + getPointerRegClass(const MachineFunction &MF, + unsigned Kind=0) const override { + return &SystemZ::ADDR64BitRegClass; + } + // Override TargetRegisterInfo.h. bool requiresRegisterScavenging(const MachineFunction &MF) const override { return true; Index: llvm/trunk/test/CodeGen/SystemZ/stack-guard.ll =================================================================== --- llvm/trunk/test/CodeGen/SystemZ/stack-guard.ll +++ llvm/trunk/test/CodeGen/SystemZ/stack-guard.ll @@ -0,0 +1,35 @@ +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +; CHECK-LABEL: @test_stack_guard +; CHECK: ear [[REG1:%r[1-9][0-9]?]], %a0 +; CHECK: sllg [[REG1]], [[REG1]], 32 +; CHECK: ear [[REG1]], %a1 +; CHECK: lg [[REG1]], 40([[REG1]]) +; CHECK: stg [[REG1]], {{[0-9]*}}(%r15) +; CHECK: brasl %r14, foo3@PLT +; CHECK: ear [[REG2:%r[1-9][0-9]?]], %a0 +; CHECK: sllg [[REG2]], [[REG2]], 32 +; CHECK: ear [[REG2]], %a1 +; CHECK: lg [[REG2]], 40([[REG2]]) +; CHECK: sg [[REG2]], {{[0-9]*}}(%r15) + +define i32 @test_stack_guard() #0 { +entry: + %a1 = alloca [256 x i32], align 4 + %0 = bitcast [256 x i32]* %a1 to i8* + call void @llvm.lifetime.start(i64 1024, i8* %0) + %arraydecay = getelementptr inbounds [256 x i32], [256 x i32]* %a1, i64 0, i64 0 + call void @foo3(i32* %arraydecay) + call void @llvm.lifetime.end(i64 1024, i8* %0) + ret i32 0 +} + +; Function Attrs: nounwind +declare void @llvm.lifetime.start(i64, i8* nocapture) + +declare void @foo3(i32*) + +; Function Attrs: nounwind +declare void @llvm.lifetime.end(i64, i8* nocapture) + +attributes #0 = { sspstrong }