Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/lib/Basic/Targets/SystemZ.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
return RegNo < 4 ? 6 + RegNo : -1;
}

bool hasSjLjLowering() const override { return true; }

std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(256, 256);
}
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4619,6 +4619,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
// Buffer is a void**.
Address Buf = EmitPointerWithAlignment(E->getArg(0));

if (getTarget().getTriple().getArch() == llvm::Triple::systemz) {
// On this target, the back end fills in the context buffer completely.
Function *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_setjmp);
return RValue::get(Builder.CreateCall(F, Buf.emitRawPointer(*this)));
}

// Store the frame pointer to the setjmp buffer.
Value *FrameAddr = Builder.CreateCall(
CGM.getIntrinsic(Intrinsic::frameaddress, AllocaInt8PtrTy),
Expand Down
25 changes: 25 additions & 0 deletions clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
// RUN: %clang --target=s390x-linux -S -emit-llvm -o - %s | FileCheck %s

void *buf[20];
// CHECK-LABEL: define dso_local void @foo(
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
// CHECK-NEXT: ret void
//
void foo()
{
__builtin_setjmp (buf);
}

// CHECK-LABEL: define dso_local void @foo1(
// CHECK-SAME: ) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: call void @llvm.eh.sjlj.longjmp(ptr @buf)
// CHECK-NEXT: unreachable
//
void foo1()
{
__builtin_longjmp (buf, 1);
}
5 changes: 5 additions & 0 deletions llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,11 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
return;
}

// EH_SjLj_Setup is a dummy terminator instruction of size 0.
// It is used to handle the clobber register for builtin setjmp.
case SystemZ::EH_SjLj_Setup:
return;

default:
Lower.lower(MI, LoweredMI);
break;
Expand Down
253 changes: 252 additions & 1 deletion llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===-- SystemZISelLowering.cpp - SystemZ DAG lowering implementation -----===//
//===-- systemzisellowering.cpp - systemz dag lowering implementation -----===//
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be some accidental change? Please remove.

//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down Expand Up @@ -751,6 +751,11 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);

// We're not using SJLJ for exception handling, but they're implemented
// solely to support use of __builtin_setjmp / __builtin_longjmp.
setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom);
setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom);

// We want to use MVC in preference to even a single load/store pair.
MaxStoresPerMemcpy = Subtarget.hasVector() ? 2 : 0;
MaxStoresPerMemcpyOptSize = 0;
Expand Down Expand Up @@ -940,6 +945,240 @@ bool SystemZTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
return SystemZVectorConstantInfo(Imm).isVectorConstantLegal(Subtarget);
}

MachineBasicBlock *
SystemZTargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const {
DebugLoc DL = MI.getDebugLoc();
const TargetInstrInfo *TII = Subtarget.getInstrInfo();
const SystemZRegisterInfo *TRI = Subtarget.getRegisterInfo();

MachineFunction *MF = MBB->getParent();
MachineRegisterInfo &MRI = MF->getRegInfo();

const BasicBlock *BB = MBB->getBasicBlock();
MachineFunction::iterator I = ++MBB->getIterator();

Register DstReg = MI.getOperand(0).getReg();
const TargetRegisterClass *RC = MRI.getRegClass(DstReg);
assert(TRI->isTypeLegalForClass(*RC, MVT::i32) && "Invalid destination!");
Register mainDstReg = MRI.createVirtualRegister(RC);
Register restoreDstReg = MRI.createVirtualRegister(RC);

MVT PVT = getPointerTy(MF->getDataLayout());
assert((PVT == MVT::i64 || PVT == MVT::i32) && "Invalid Pointer Size!");
// For v = setjmp(buf), we generate.
// Algorithm:
//
// ---------
// | thisMBB |
// ---------
// |
// ------------------------
// | |
// ---------- ---------------
// | mainMBB | | restoreMBB |
// | v = 0 | | v = 1 |
// ---------- ---------------
// | |
// -------------------------
// |
// -----------------------------
// | sinkMBB |
// | phi(v_mainMBB,v_restoreMBB) |
// -----------------------------
// thisMBB:
// buf[FPOffset] = Frame Pointer if hasFP.
// buf[LabelOffset] = restoreMBB <-- takes address of restoreMBB.
// buf[BCOffset] = Backchain value if building with -mbackchain.
// buf[SPOffset] = Stack Pointer.
// buf[LPOffset] = We never write this slot with R13, gcc stores R13 always.
// SjLjSetup restoreMBB
// mainMBB:
// v_main = 0
// sinkMBB:
// v = phi(v_main, v_restore)
// restoreMBB:
// v_restore = 1

MachineBasicBlock *thisMBB = MBB;
MachineBasicBlock *mainMBB = MF->CreateMachineBasicBlock(BB);
MachineBasicBlock *sinkMBB = MF->CreateMachineBasicBlock(BB);
MachineBasicBlock *restoreMBB = MF->CreateMachineBasicBlock(BB);

MF->insert(I, mainMBB);
MF->insert(I, sinkMBB);
MF->push_back(restoreMBB);
restoreMBB->setMachineBlockAddressTaken();

MachineInstrBuilder MIB;

// Transfer the remainder of BB and its successor edges to sinkMBB.
sinkMBB->splice(sinkMBB->begin(), MBB,
std::next(MachineBasicBlock::iterator(MI)), MBB->end());
sinkMBB->transferSuccessorsAndUpdatePHIs(MBB);

// thisMBB:
const int64_t FPOffset = 0; // Slot 1.
const int64_t LabelOffset = 1 * PVT.getStoreSize(); // Slot 2.
const int64_t BCOffset = 2 * PVT.getStoreSize(); // Slot 3.
const int64_t SPOffset = 3 * PVT.getStoreSize(); // Slot 4.

// Buf address.
Register BufReg = MI.getOperand(1).getReg();

const TargetRegisterClass *PtrRC = getRegClassFor(PVT);
unsigned LabelReg = MRI.createVirtualRegister(PtrRC);

// Prepare IP for longjmp.
BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::LARL), LabelReg)
.addMBB(restoreMBB);
// Store IP for return from jmp, slot 2, offset = 1.
BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::STG))
.addReg(LabelReg)
.addReg(BufReg)
.addImm(LabelOffset)
.addReg(0);

auto *SpecialRegs = Subtarget.getSpecialRegisters();
bool HasFP = Subtarget.getFrameLowering()->hasFP(*MF);
if (HasFP) {
BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::STG))
.addReg(SpecialRegs->getFramePointerRegister())
.addReg(BufReg)
.addImm(FPOffset)
.addReg(0);
}

// Store SP.
BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::STG))
.addReg(SpecialRegs->getStackPointerRegister())
.addReg(BufReg)
.addImm(SPOffset)
.addReg(0);

// Slot 3(Offset = 2) Backchain value (if building with -mbackchain).
bool BackChain = MF->getSubtarget<SystemZSubtarget>().hasBackChain();
if (BackChain) {
Register BCReg = MRI.createVirtualRegister(RC);
auto *TFL = Subtarget.getFrameLowering<SystemZFrameLowering>();
MIB = BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::LG), BCReg)
.addReg(SpecialRegs->getStackPointerRegister())
.addImm(TFL->getBackchainOffset(*MF))
.addReg(0);

BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::STG))
.addReg(BCReg)
.addReg(BufReg)
.addImm(BCOffset)
.addReg(0);
}

// Setup.
MIB = BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::EH_SjLj_Setup))
.addMBB(restoreMBB);

const SystemZRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
MIB.addRegMask(RegInfo->getNoPreservedMask());

thisMBB->addSuccessor(mainMBB);
thisMBB->addSuccessor(restoreMBB);

// mainMBB:
BuildMI(mainMBB, DL, TII->get(SystemZ::LHI), mainDstReg).addImm(0);
mainMBB->addSuccessor(sinkMBB);

// sinkMBB:
BuildMI(*sinkMBB, sinkMBB->begin(), DL, TII->get(SystemZ::PHI), DstReg)
.addReg(mainDstReg)
.addMBB(mainMBB)
.addReg(restoreDstReg)
.addMBB(restoreMBB);

// restoreMBB.
BuildMI(restoreMBB, DL, TII->get(SystemZ::LHI), restoreDstReg).addImm(1);
BuildMI(restoreMBB, DL, TII->get(SystemZ::J)).addMBB(sinkMBB);
restoreMBB->addSuccessor(sinkMBB);

MI.eraseFromParent();

return sinkMBB;
}

MachineBasicBlock *
SystemZTargetLowering::emitEHSjLjLongJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const {

DebugLoc DL = MI.getDebugLoc();
const TargetInstrInfo *TII = Subtarget.getInstrInfo();

MachineFunction *MF = MBB->getParent();
MachineRegisterInfo &MRI = MF->getRegInfo();

MVT PVT = getPointerTy(MF->getDataLayout());
assert((PVT == MVT::i64 || PVT == MVT::i32) && "Invalid Pointer Size!");
Register BufReg = MI.getOperand(0).getReg();
const TargetRegisterClass *RC = MRI.getRegClass(BufReg);
auto *SpecialRegs = Subtarget.getSpecialRegisters();

Register Tmp = MRI.createVirtualRegister(RC);
Register BCReg = MRI.createVirtualRegister(RC);

MachineInstrBuilder MIB;

const int64_t FPOffset = 0;
const int64_t LabelOffset = 1 * PVT.getStoreSize();
const int64_t BCOffset = 2 * PVT.getStoreSize();
const int64_t SPOffset = 3 * PVT.getStoreSize();
const int64_t LPOffset = 4 * PVT.getStoreSize();

MIB = BuildMI(*MBB, MI, DL, TII->get(SystemZ::LG), Tmp)
.addReg(BufReg)
.addImm(LabelOffset)
.addReg(0);

MIB = BuildMI(*MBB, MI, DL, TII->get(SystemZ::LG),
SpecialRegs->getFramePointerRegister())
.addReg(BufReg)
.addImm(FPOffset)
.addReg(0);

// We are restoring R13 even though we never stored in setjmp from llvm,
// as gcc always stores R13 in builtin_setjmp. We could have mixed code
// gcc setjmp and llvm longjmp.
MIB = BuildMI(*MBB, MI, DL, TII->get(SystemZ::LG), SystemZ::R13D)
.addReg(BufReg)
.addImm(LPOffset)
.addReg(0);

bool BackChain = MF->getSubtarget<SystemZSubtarget>().hasBackChain();
if (BackChain) {
MIB = BuildMI(*MBB, MI, DL, TII->get(SystemZ::LG), BCReg)
.addReg(BufReg)
.addImm(BCOffset)
.addReg(0);
}

MIB = BuildMI(*MBB, MI, DL, TII->get(SystemZ::LG),
SpecialRegs->getStackPointerRegister())
.addReg(BufReg)
.addImm(SPOffset)
.addReg(0);

if (BackChain) {
auto *TFL = Subtarget.getFrameLowering<SystemZFrameLowering>();
BuildMI(*MBB, MI, DL, TII->get(SystemZ::STG))
.addReg(BCReg)
.addReg(SpecialRegs->getStackPointerRegister())
.addImm(TFL->getBackchainOffset(*MF))
.addReg(0);
}

MIB = BuildMI(*MBB, MI, DL, TII->get(SystemZ::BR)).addReg(Tmp);

MI.eraseFromParent();
return MBB;
}

/// Returns true if stack probing through inline assembly is requested.
bool SystemZTargetLowering::hasInlineStackProbe(const MachineFunction &MF) const {
// If the function specifically requests inline stack probes, emit them.
Expand Down Expand Up @@ -6292,6 +6531,14 @@ SDValue SystemZTargetLowering::LowerOperation(SDValue Op,
return lowerGET_ROUNDING(Op, DAG);
case ISD::READCYCLECOUNTER:
return lowerREADCYCLECOUNTER(Op, DAG);
case ISD::EH_SJLJ_SETJMP:
case ISD::EH_SJLJ_LONGJMP:
// These operations are legal on our platform, but we cannot actually
// set the operation action to Legal as common code would treat this
// as equivalent to Expand. Instead, we keep the operation action to
// Custom and just leave them unchanged here.
return Op;

default:
llvm_unreachable("Unexpected node to lower");
}
Expand Down Expand Up @@ -9724,6 +9971,10 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter(

case SystemZ::PROBED_ALLOCA:
return emitProbedAlloca(MI, MBB);
case SystemZ::EH_SjLj_SetJmp:
return emitEHSjLjSetJmp(MI, MBB);
case SystemZ::EH_SjLj_LongJmp:
return emitEHSjLjLongJmp(MI, MBB);

case TargetOpcode::STACKMAP:
case TargetOpcode::PATCHPOINT:
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Target/SystemZ/SystemZISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,12 @@ class SystemZTargetLowering : public TargetLowering {
// LD, and having the full constant in memory enables reg/mem opcodes.
return VT != MVT::f64;
}
MachineBasicBlock *emitEHSjLjSetJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const;

MachineBasicBlock *emitEHSjLjLongJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const;

bool hasInlineStackProbe(const MachineFunction &MF) const override;
AtomicExpansionKind shouldCastAtomicLoadInIR(LoadInst *LI) const override;
AtomicExpansionKind shouldCastAtomicStoreInIR(StoreInst *SI) const override;
Expand Down
17 changes: 17 additions & 0 deletions llvm/lib/Target/SystemZ/SystemZInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -1871,6 +1871,23 @@ let mayLoad = 1, mayStore = 1, Defs = [CC] in {
}
}

//--------------------------------------------------------------------------
// Setjmp/Longjmp.
//--------------------------------------------------------------------------
let isBarrier = 1, hasNoSchedulingInfo = 1 in {
let hasSideEffects = 1, usesCustomInserter = 1 in {
def EH_SjLj_SetJmp : Pseudo<(outs GR32:$dst), (ins ADDR64:$R2),
[(set GR32:$dst, (z_eh_sjlj_setjmp ADDR64:$R2))]>;
let isTerminator = 1 in {
def EH_SjLj_LongJmp : Pseudo<(outs), (ins ADDR64:$R2),
[(z_eh_sjlj_longjmp ADDR64:$R2)]>;
}
}
let isTerminator = 1, isCodeGenOnly = 1, Size = 0 in {
def EH_SjLj_Setup : Pseudo<(outs), (ins brtarget32:$dst), []>;
}
}

//===----------------------------------------------------------------------===//
// Message-security assist
//===----------------------------------------------------------------------===//
Expand Down
5 changes: 4 additions & 1 deletion llvm/lib/Target/SystemZ/SystemZLongBranch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,10 @@ static unsigned getInstSizeInBytes(const MachineInstr &MI,
MI.isImplicitDef() || MI.getOpcode() == TargetOpcode::MEMBARRIER ||
// These have a size that may be zero:
MI.isInlineAsm() || MI.getOpcode() == SystemZ::STACKMAP ||
MI.getOpcode() == SystemZ::PATCHPOINT) &&
MI.getOpcode() == SystemZ::PATCHPOINT ||
// EH_SjLj_Setup is a dummy terminator instruction of size 0,
// It is used to handle the clobber register for builtin setjmp.
MI.getOpcode() == SystemZ::EH_SjLj_Setup) &&
"Missing size value for instruction.");
return Size;
}
Expand Down
Loading
Loading