Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Support Linux on z as a Swift platform #8

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,11 @@ void RuntimeDyldELF::resolveSystemZRelocation(const SectionEntry &Section,
case ELF::R_390_64:
writeInt64BE(LocalAddress, Value + Addend);
break;
case ELF::R_390_PC64: {
int64_t Delta = (Value + Addend) - Section.getLoadAddressWithOffset(Offset);
writeInt64BE(LocalAddress, Delta);
break;
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions lib/Target/SystemZ/SystemZAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,11 @@ void SystemZAsmPrinter::EmitInstruction(const MachineInstr *MI) {
.addImm(15).addReg(SystemZ::R0D);
break;

// Emit nothing here but a comment if we can.
case SystemZ::MemBarrier:
OutStreamer->emitRawComment("MEMBARRIER");
return;

default:
Lower.lower(MI, LoweredMI);
break;
Expand Down
12 changes: 12 additions & 0 deletions lib/Target/SystemZ/SystemZCallingConv.td
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ def RetCC_SystemZ : CallingConv<[
// Promote i32 to i64 if it has an explicit extension type.
CCIfType<[i32], CCIfExtend<CCPromoteToType<i64>>>,

// A SwiftError is returned in R9.
CCIfSwiftError<CCIfType<[i64], CCAssignToReg<[R9D]>>>,

// ABI-compliant code returns 64-bit integers in R2. Make the other
// call-clobbered argument registers available for code that doesn't
// care about the ABI. (R6 is an argument register too, but is
Expand Down Expand Up @@ -65,6 +68,12 @@ def CC_SystemZ : CallingConv<[
// are smaller than 64 bits shouldn't.
CCIfType<[i32], CCIfExtend<CCPromoteToType<i64>>>,

// A SwiftSelf is passed in callee-saved R10.
CCIfSwiftSelf<CCIfType<[i64], CCAssignToReg<[R10D]>>>,

// A SwiftError is passed in callee-saved R9.
CCIfSwiftError<CCIfType<[i64], CCAssignToReg<[R9D]>>>,

// Force long double values to the stack and pass i64 pointers to them.
CCIfType<[f128], CCPassIndirect<i64>>,

Expand Down Expand Up @@ -105,3 +114,6 @@ def CC_SystemZ : CallingConv<[
//===----------------------------------------------------------------------===//
def CSR_SystemZ : CalleeSavedRegs<(add (sequence "R%dD", 6, 15),
(sequence "F%dD", 8, 15))>;

// R9 is used to return SwiftError; remove it from CSR.
def CSR_SystemZ_SwiftError : CalleeSavedRegs<(sub CSR_SystemZ, R9D)>;
92 changes: 88 additions & 4 deletions lib/Target/SystemZ/SystemZISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::ATOMIC_LOAD_UMAX, MVT::i32, Custom);
setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32, Custom);

setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom);

// z10 has instructions for signed but not unsigned FP conversion.
// Handle unsigned 32-bit types as signed 64-bit types.
if (!Subtarget.hasFPExtension()) {
Expand Down Expand Up @@ -987,9 +989,11 @@ LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
}

static bool canUseSiblingCall(const CCState &ArgCCInfo,
SmallVectorImpl<CCValAssign> &ArgLocs) {
SmallVectorImpl<CCValAssign> &ArgLocs,
SmallVectorImpl<ISD::OutputArg> &Outs) {
// Punt if there are any indirect or stack arguments, or if the call
// needs the call-saved argument register R6.
// needs the callee-saved argument register R6, or if the call uses
// the callee-saved register arguments SwiftSelf and SwiftError.
for (unsigned I = 0, E = ArgLocs.size(); I != E; ++I) {
CCValAssign &VA = ArgLocs[I];
if (VA.getLocInfo() == CCValAssign::Indirect)
Expand All @@ -999,6 +1003,8 @@ static bool canUseSiblingCall(const CCState &ArgCCInfo,
unsigned Reg = VA.getLocReg();
if (Reg == SystemZ::R6H || Reg == SystemZ::R6L || Reg == SystemZ::R6D)
return false;
if (Outs[I].Flags.isSwiftSelf() || Outs[I].Flags.isSwiftError())
return false;
}
return true;
}
Expand Down Expand Up @@ -1032,7 +1038,7 @@ SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI,

// We don't support GuaranteedTailCallOpt, only automatically-detected
// sibling calls.
if (IsTailCall && !canUseSiblingCall(ArgCCInfo, ArgLocs))
if (IsTailCall && !canUseSiblingCall(ArgCCInfo, ArgLocs, Outs))
IsTailCall = false;

// Get a count of how many bytes are to be pushed on the stack.
Expand Down Expand Up @@ -1849,7 +1855,7 @@ static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned CCMask,
if (CCMask == SystemZ::CCMASK_CMP_NE)
return SystemZ::CCMASK_TM_SOME_1;
}
if (EffectivelyUnsigned && CmpVal <= Low) {
if (EffectivelyUnsigned && CmpVal > 0 && CmpVal <= Low) {
if (CCMask == SystemZ::CCMASK_CMP_LT)
return SystemZ::CCMASK_TM_ALL_0;
if (CCMask == SystemZ::CCMASK_CMP_GE)
Expand Down Expand Up @@ -2640,6 +2646,57 @@ SDValue SystemZTargetLowering::lowerConstantPool(ConstantPoolSDNode *CP,
return DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result);
}

SDValue SystemZTargetLowering::lowerFRAMEADDR(SDValue Op,
SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo *MFI = MF.getFrameInfo();
MFI->setFrameAddressIsTaken(true);

SDLoc DL(Op);
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
EVT PtrVT = getPointerTy(DAG.getDataLayout());

// If the back chain frame index has not been allocated yet, do so.
SystemZMachineFunctionInfo *FI = MF.getInfo<SystemZMachineFunctionInfo>();
int BackChainIdx = FI->getFramePointerSaveIndex();
if (!BackChainIdx) {
// By definition, the frame address is the address of the back chain.
BackChainIdx = MFI->CreateFixedObject(8, -SystemZMC::CallFrameSize, false);
FI->setFramePointerSaveIndex(BackChainIdx);
}
SDValue BackChain = DAG.getFrameIndex(BackChainIdx, PtrVT);

// FIXME The frontend should detect this case.
if (Depth > 0) {
report_fatal_error("Unsupported stack frame traversal count");
}

return BackChain;
}

SDValue SystemZTargetLowering::lowerRETURNADDR(SDValue Op,
SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo *MFI = MF.getFrameInfo();
MFI->setReturnAddressIsTaken(true);

if (verifyReturnAddressArgumentIsConstant(Op, DAG))
return SDValue();

SDLoc DL(Op);
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
EVT PtrVT = getPointerTy(DAG.getDataLayout());

// FIXME The frontend should detect this case.
if (Depth > 0) {
report_fatal_error("Unsupported stack frame traversal count");
}

// Return R14D, which has the return address. Mark it an implicit live-in.
unsigned LinkReg = MF.addLiveIn(SystemZ::R14D, &SystemZ::GR64BitRegClass);
return DAG.getCopyFromReg(DAG.getEntryNode(), DL, LinkReg, PtrVT);
}

SDValue SystemZTargetLowering::lowerBITCAST(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
Expand Down Expand Up @@ -3031,6 +3088,25 @@ SDValue SystemZTargetLowering::lowerCTPOP(SDValue Op,
return Op;
}

SDValue SystemZTargetLowering::lowerATOMIC_FENCE(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
AtomicOrdering FenceOrdering = static_cast<AtomicOrdering>(
cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue());
SynchronizationScope FenceScope = static_cast<SynchronizationScope>(
cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue());

// The only fence that needs an instruction is a sequentially-consistent
// cross-thread fence.
if (FenceOrdering == SequentiallyConsistent && FenceScope == CrossThread) {
return SDValue(DAG.getMachineNode(SystemZ::Serialize, DL, MVT::Other,
Op.getOperand(0)), 0);
}

// MEMBARRIER is a compiler barrier; it codegens to a no-op.
return DAG.getNode(SystemZISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0));
}

// Op is an atomic load. Lower it into a normal volatile load.
SDValue SystemZTargetLowering::lowerATOMIC_LOAD(SDValue Op,
SelectionDAG &DAG) const {
Expand Down Expand Up @@ -4312,6 +4388,10 @@ SDValue SystemZTargetLowering::lowerShift(SDValue Op, SelectionDAG &DAG,
SDValue SystemZTargetLowering::LowerOperation(SDValue Op,
SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
case ISD::FRAMEADDR:
return lowerFRAMEADDR(Op, DAG);
case ISD::RETURNADDR:
return lowerRETURNADDR(Op, DAG);
case ISD::BR_CC:
return lowerBR_CC(Op, DAG);
case ISD::SELECT_CC:
Expand Down Expand Up @@ -4354,6 +4434,8 @@ SDValue SystemZTargetLowering::LowerOperation(SDValue Op,
case ISD::CTTZ_ZERO_UNDEF:
return DAG.getNode(ISD::CTTZ, SDLoc(Op),
Op.getValueType(), Op.getOperand(0));
case ISD::ATOMIC_FENCE:
return lowerATOMIC_FENCE(Op, DAG);
case ISD::ATOMIC_SWAP:
return lowerATOMIC_LOAD_OP(Op, DAG, SystemZISD::ATOMIC_SWAPW);
case ISD::ATOMIC_STORE:
Expand Down Expand Up @@ -4457,6 +4539,7 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const {
OPCODE(SEARCH_STRING);
OPCODE(IPM);
OPCODE(SERIALIZE);
OPCODE(MEMBARRIER);
OPCODE(TBEGIN);
OPCODE(TBEGIN_NOFLOAT);
OPCODE(TEND);
Expand Down Expand Up @@ -5218,6 +5301,7 @@ SystemZTargetLowering::emitAtomicLoadMinMax(MachineInstr *MI,
MachineBasicBlock *
SystemZTargetLowering::emitAtomicCmpSwapW(MachineInstr *MI,
MachineBasicBlock *MBB) const {

MachineFunction &MF = *MBB->getParent();
const SystemZInstrInfo *TII =
static_cast<const SystemZInstrInfo *>(Subtarget.getInstrInfo());
Expand Down
10 changes: 10 additions & 0 deletions lib/Target/SystemZ/SystemZISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ enum NodeType : unsigned {
// Perform a serialization operation. (BCR 15,0 or BCR 14,0.)
SERIALIZE,

// Compiler barrier only; generate a no-op.
MEMBARRIER,

// Transaction begin. The first operand is the chain, the second
// the TDB pointer, and the third the immediate control field.
// Returns chain and glue.
Expand Down Expand Up @@ -449,6 +452,10 @@ class SystemZTargetLowering : public TargetLowering {
SelectionDAG &DAG) const override;
SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override;

bool supportSwiftError() const override {
return true;
}

private:
const SystemZSubtarget &Subtarget;

Expand All @@ -467,6 +474,8 @@ class SystemZTargetLowering : public TargetLowering {
SelectionDAG &DAG) const;
SDValue lowerJumpTable(JumpTableSDNode *JT, SelectionDAG &DAG) const;
SDValue lowerConstantPool(ConstantPoolSDNode *CP, SelectionDAG &DAG) const;
SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerVACOPY(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
Expand All @@ -477,6 +486,7 @@ class SystemZTargetLowering : public TargetLowering {
SDValue lowerBITCAST(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerOR(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerCTPOP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerATOMIC_FENCE(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerATOMIC_LOAD(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerATOMIC_STORE(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerATOMIC_LOAD_OP(SDValue Op, SelectionDAG &DAG,
Expand Down
4 changes: 4 additions & 0 deletions lib/Target/SystemZ/SystemZInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,10 @@ def PFDRL : PrefetchRILPC<"pfdrl", 0xC62, z_prefetch>;
let hasSideEffects = 1 in
def Serialize : Alias<2, (outs), (ins), [(z_serialize)]>;

// A pseudo instruction that serves as a compiler barrier.
let hasSideEffects = 1 in
def MemBarrier : Pseudo<(outs), (ins), [(z_membarrier)]>;

let Predicates = [FeatureInterlockedAccess1], Defs = [CC] in {
def LAA : LoadAndOpRSY<"laa", 0xEBF8, atomic_load_add_32, GR32>;
def LAAG : LoadAndOpRSY<"laag", 0xEBE8, atomic_load_add_64, GR64>;
Expand Down
9 changes: 7 additions & 2 deletions lib/Target/SystemZ/SystemZMachineFunctionInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ class SystemZMachineFunctionInfo : public MachineFunctionInfo {
unsigned VarArgsFirstFPR;
unsigned VarArgsFrameIndex;
unsigned RegSaveFrameIndex;
int FramePointerSaveIndex;
bool ManipulatesSP;
unsigned NumLocalDynamics;

public:
explicit SystemZMachineFunctionInfo(MachineFunction &MF)
: LowSavedGPR(0), HighSavedGPR(0), VarArgsFirstGPR(0), VarArgsFirstFPR(0),
VarArgsFrameIndex(0), RegSaveFrameIndex(0), ManipulatesSP(false),
NumLocalDynamics(0) {}
VarArgsFrameIndex(0), RegSaveFrameIndex(0), FramePointerSaveIndex(0),
ManipulatesSP(false), NumLocalDynamics(0) {}

// Get and set the first call-saved GPR that should be saved and restored
// by this function. This is 0 if no GPRs need to be saved or restored.
Expand Down Expand Up @@ -59,6 +60,10 @@ class SystemZMachineFunctionInfo : public MachineFunctionInfo {
unsigned getRegSaveFrameIndex() const { return RegSaveFrameIndex; }
void setRegSaveFrameIndex(unsigned FI) { RegSaveFrameIndex = FI; }

// Get and set the frame index of where the old frame pointer is stored.
int getFramePointerSaveIndex() const { return FramePointerSaveIndex; }
void setFramePointerSaveIndex(int Idx) { FramePointerSaveIndex = Idx; }

// Get and set whether the function directly manipulates the stack pointer,
// e.g. through STACKSAVE or STACKRESTORE.
bool getManipulatesSP() const { return ManipulatesSP; }
Expand Down
2 changes: 2 additions & 0 deletions lib/Target/SystemZ/SystemZOperators.td
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ def z_udivrem64 : SDNode<"SystemZISD::UDIVREM64", SDT_ZGR128Binary64>;

def z_serialize : SDNode<"SystemZISD::SERIALIZE", SDTNone,
[SDNPHasChain, SDNPMayStore]>;
def z_membarrier : SDNode<"SystemZISD::MEMBARRIER", SDTNone,
[SDNPHasChain, SDNPSideEffect]>;

// Defined because the index is an i32 rather than a pointer.
def z_vector_insert : SDNode<"ISD::INSERT_VECTOR_ELT",
Expand Down
8 changes: 8 additions & 0 deletions lib/Target/SystemZ/SystemZRegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,20 @@ SystemZRegisterInfo::SystemZRegisterInfo()

const MCPhysReg *
SystemZRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
if (MF->getSubtarget().getTargetLowering()->supportSwiftError() &&
MF->getFunction()->getAttributes().hasAttrSomewhere(
Attribute::SwiftError))
return CSR_SystemZ_SwiftError_SaveList;
return CSR_SystemZ_SaveList;
}

const uint32_t *
SystemZRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID CC) const {
if (MF.getSubtarget().getTargetLowering()->supportSwiftError() &&
MF.getFunction()->getAttributes().hasAttrSomewhere(
Attribute::SwiftError))
return CSR_SystemZ_SwiftError_RegMask;
return CSR_SystemZ_RegMask;
}

Expand Down
16 changes: 16 additions & 0 deletions test/CodeGen/SystemZ/atomic-fence-01.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
; Test (fast) serialization.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s --check-prefix=Z10
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z196 | FileCheck %s --check-prefix=Z196
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=zEC12 | FileCheck %s --check-prefix=ZEC12
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 | FileCheck %s --check-prefix=Z13

define void @test() {
; Z10: bcr 15, %r0
; Z196: bcr 14, %r0
; ZEC12: bcr 14, %r0
; Z13: bcr 14, %r0
fence seq_cst
ret void
}

13 changes: 13 additions & 0 deletions test/CodeGen/SystemZ/atomic-fence-02.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
; Serialization is emitted only for fence seq_cst.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s

define void @test() {
; CHECK: #MEMBARRIER
fence acquire
; CHECK: #MEMBARRIER
fence release
; CHECK: #MEMBARRIER
fence acq_rel
ret void
}
28 changes: 28 additions & 0 deletions test/CodeGen/SystemZ/frameaddr-01.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s

; The current function's frame address is the address of
; the optional back chain slot.
define i8* @fp0() nounwind {
entry:
; CHECK-LABEL: fp0:
; CHECK: la %r2, 0(%r15)
; CHECK: br %r14
%0 = tail call i8* @llvm.frameaddress(i32 0)
ret i8* %0
}

; Check that the frame address is correct in a presence
; of a stack frame.
define i8* @fp0f() nounwind {
entry:
; CHECK-LABEL: fp0f:
; CHECK: aghi %r15, -168
; CHECK: la %r2, 168(%r15)
; CHECK: aghi %r15, 168
; CHECK: br %r14
%0 = alloca i64, align 8
%1 = tail call i8* @llvm.frameaddress(i32 0)
ret i8* %1
}

declare i8* @llvm.frameaddress(i32) nounwind readnone
Loading