diff options
Diffstat (limited to 'contrib/llvm/lib/Target/SystemZ')
31 files changed, 6163 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp new file mode 100644 index 0000000..8540546 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp @@ -0,0 +1,32 @@ +//===-- SystemZMCAsmInfo.cpp - SystemZ asm properties ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations of the SystemZMCAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "SystemZMCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/Support/ELF.h" +using namespace llvm; + +SystemZMCAsmInfo::SystemZMCAsmInfo(const Target &T, StringRef TT) { + IsLittleEndian = false; + PointerSize = 8; + PrivateGlobalPrefix = ".L"; + WeakRefDirective = "\t.weak\t"; + PCSymbol = "."; +} + +const MCSection *SystemZMCAsmInfo:: +getNonexecutableStackSection(MCContext &Ctx) const{ + return Ctx.getELFSection(".note.GNU-stack", ELF::SHT_PROGBITS, + 0, SectionKind::getMetadata()); +} diff --git a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h new file mode 100644 index 0000000..a6a27e2 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h @@ -0,0 +1,30 @@ +//====-- SystemZMCAsmInfo.h - SystemZ asm properties -----------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the SystemZMCAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef SystemZTARGETASMINFO_H +#define SystemZTARGETASMINFO_H + +#include "llvm/MC/MCAsmInfo.h" + +namespace llvm { + class Target; + class StringRef; + + struct SystemZMCAsmInfo : public MCAsmInfo { + explicit SystemZMCAsmInfo(const Target &T, StringRef TT); + virtual const MCSection *getNonexecutableStackSection(MCContext &Ctx) const; + }; + +} // namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp new file mode 100644 index 0000000..23fb1e0 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp @@ -0,0 +1,81 @@ +//===-- SystemZMCTargetDesc.cpp - SystemZ Target Descriptions ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides SystemZ specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#include "SystemZMCTargetDesc.h" +#include "SystemZMCAsmInfo.h" +#include "llvm/MC/MCCodeGenInfo.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/TargetRegistry.h" + +#define GET_INSTRINFO_MC_DESC +#include "SystemZGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_MC_DESC +#include "SystemZGenSubtargetInfo.inc" + +#define GET_REGINFO_MC_DESC +#include "SystemZGenRegisterInfo.inc" + +using namespace llvm; + +static MCInstrInfo *createSystemZMCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitSystemZMCInstrInfo(X); + return X; +} + +static MCRegisterInfo *createSystemZMCRegisterInfo(StringRef TT) { + MCRegisterInfo *X = new MCRegisterInfo(); + InitSystemZMCRegisterInfo(X, 0); + return X; +} + +static MCSubtargetInfo *createSystemZMCSubtargetInfo(StringRef TT, + StringRef CPU, + StringRef FS) { + MCSubtargetInfo *X = new MCSubtargetInfo(); + InitSystemZMCSubtargetInfo(X, TT, CPU, FS); + return X; +} + +static MCCodeGenInfo *createSystemZMCCodeGenInfo(StringRef TT, Reloc::Model RM, + CodeModel::Model CM) { + MCCodeGenInfo *X = new MCCodeGenInfo(); + if (RM == Reloc::Default) + RM = Reloc::Static; + X->InitMCCodeGenInfo(RM, CM); + return X; +} + +extern "C" void LLVMInitializeSystemZTargetMC() { + // Register the MC asm info. + RegisterMCAsmInfo<SystemZMCAsmInfo> X(TheSystemZTarget); + + // Register the MC codegen info. + TargetRegistry::RegisterMCCodeGenInfo(TheSystemZTarget, + createSystemZMCCodeGenInfo); + + // Register the MC instruction info. + TargetRegistry::RegisterMCInstrInfo(TheSystemZTarget, + createSystemZMCInstrInfo); + + // Register the MC register info. + TargetRegistry::RegisterMCRegInfo(TheSystemZTarget, + createSystemZMCRegisterInfo); + + // Register the MC subtarget info. + TargetRegistry::RegisterMCSubtargetInfo(TheSystemZTarget, + createSystemZMCSubtargetInfo); +} diff --git a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h new file mode 100644 index 0000000..e2ad5af --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h @@ -0,0 +1,38 @@ +//===-- SystemZMCTargetDesc.h - SystemZ Target Descriptions -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides SystemZ specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#ifndef SYSTEMZMCTARGETDESC_H +#define SYSTEMZMCTARGETDESC_H + +namespace llvm { +class MCSubtargetInfo; +class Target; +class StringRef; + +extern Target TheSystemZTarget; + +} // End llvm namespace + +// Defines symbolic names for SystemZ registers. +// This defines a mapping from register name to register number. +#define GET_REGINFO_ENUM +#include "SystemZGenRegisterInfo.inc" + +// Defines symbolic names for the SystemZ instructions. +#define GET_INSTRINFO_ENUM +#include "SystemZGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_ENUM +#include "SystemZGenSubtargetInfo.inc" + +#endif diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZ.h b/contrib/llvm/lib/Target/SystemZ/SystemZ.h new file mode 100644 index 0000000..88960b9 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZ.h @@ -0,0 +1,52 @@ +//=-- SystemZ.h - Top-level interface for SystemZ representation -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the entry points for global functions defined in +// the LLVM SystemZ backend. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_SystemZ_H +#define LLVM_TARGET_SystemZ_H + +#include "MCTargetDesc/SystemZMCTargetDesc.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + class SystemZTargetMachine; + class FunctionPass; + class formatted_raw_ostream; + + namespace SystemZCC { + // SystemZ specific condition code. These correspond to SYSTEMZ_*_COND in + // SystemZInstrInfo.td. They must be kept in synch. + enum CondCodes { + O = 0, + H = 1, + NLE = 2, + L = 3, + NHE = 4, + LH = 5, + NE = 6, + E = 7, + NLH = 8, + HE = 9, + NL = 10, + LE = 11, + NH = 12, + NO = 13, + INVALID = -1 + }; + } + + FunctionPass *createSystemZISelDag(SystemZTargetMachine &TM, + CodeGenOpt::Level OptLevel); + +} // end namespace llvm; +#endif diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZ.td b/contrib/llvm/lib/Target/SystemZ/SystemZ.td new file mode 100644 index 0000000..4c08c08 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZ.td @@ -0,0 +1,61 @@ +//===- SystemZ.td - Describe the SystemZ Target Machine ------*- tblgen -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This is the top level entry point for the SystemZ target. +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Target-independent interfaces +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + +//===----------------------------------------------------------------------===// +// Subtarget Features. +//===----------------------------------------------------------------------===// +def FeatureZ10 : SubtargetFeature<"z10", "HasZ10Insts", "true", + "Support Z10 instructions">; + +//===----------------------------------------------------------------------===// +// SystemZ supported processors. +//===----------------------------------------------------------------------===// +class Proc<string Name, list<SubtargetFeature> Features> + : Processor<Name, NoItineraries, Features>; + +def : Proc<"z9", []>; +def : Proc<"z10", [FeatureZ10]>; + +//===----------------------------------------------------------------------===// +// Register File Description +//===----------------------------------------------------------------------===// + +include "SystemZRegisterInfo.td" + +//===----------------------------------------------------------------------===// +// Calling Convention Description +//===----------------------------------------------------------------------===// + +include "SystemZCallingConv.td" + +//===----------------------------------------------------------------------===// +// Instruction Descriptions +//===----------------------------------------------------------------------===// + +include "SystemZInstrInfo.td" +include "SystemZInstrFP.td" + +def SystemZInstrInfo : InstrInfo {} + +//===----------------------------------------------------------------------===// +// Target Declaration +//===----------------------------------------------------------------------===// + +def SystemZ : Target { + let InstructionSet = SystemZInstrInfo; +} + diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp new file mode 100644 index 0000000..43dcdfc --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -0,0 +1,221 @@ +//===-- SystemZAsmPrinter.cpp - SystemZ LLVM assembly writer ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to the SystemZ assembly language. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "SystemZ.h" +#include "SystemZInstrInfo.h" +#include "SystemZTargetMachine.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Module.h" +#include "llvm/Assembly/Writer.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +namespace { + class SystemZAsmPrinter : public AsmPrinter { + public: + SystemZAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) + : AsmPrinter(TM, Streamer) {} + + virtual const char *getPassName() const { + return "SystemZ Assembly Printer"; + } + + void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O, + const char* Modifier = 0); + void printPCRelImmOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); + void printRIAddrOperand(const MachineInstr *MI, int OpNum, raw_ostream &O, + const char* Modifier = 0); + void printRRIAddrOperand(const MachineInstr *MI, int OpNum, raw_ostream &O, + const char* Modifier = 0); + void printS16ImmOperand(const MachineInstr *MI, int OpNum, raw_ostream &O) { + O << (int16_t)MI->getOperand(OpNum).getImm(); + } + void printU16ImmOperand(const MachineInstr *MI, int OpNum, raw_ostream &O) { + O << (uint16_t)MI->getOperand(OpNum).getImm(); + } + void printS32ImmOperand(const MachineInstr *MI, int OpNum, raw_ostream &O) { + O << (int32_t)MI->getOperand(OpNum).getImm(); + } + void printU32ImmOperand(const MachineInstr *MI, int OpNum, raw_ostream &O) { + O << (uint32_t)MI->getOperand(OpNum).getImm(); + } + + void printInstruction(const MachineInstr *MI, raw_ostream &O); + static const char *getRegisterName(unsigned RegNo); + + void EmitInstruction(const MachineInstr *MI); + }; +} // end of anonymous namespace + +#include "SystemZGenAsmWriter.inc" + +void SystemZAsmPrinter::EmitInstruction(const MachineInstr *MI) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + printInstruction(MI, OS); + OutStreamer.EmitRawText(OS.str()); +} + +void SystemZAsmPrinter::printPCRelImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(OpNum); + switch (MO.getType()) { + case MachineOperand::MO_Immediate: + O << MO.getImm(); + return; + case MachineOperand::MO_MachineBasicBlock: + O << *MO.getMBB()->getSymbol(); + return; + case MachineOperand::MO_GlobalAddress: { + const GlobalValue *GV = MO.getGlobal(); + O << *Mang->getSymbol(GV); + + // Assemble calls via PLT for externally visible symbols if PIC. + if (TM.getRelocationModel() == Reloc::PIC_ && + !GV->hasHiddenVisibility() && !GV->hasProtectedVisibility() && + !GV->hasLocalLinkage()) + O << "@PLT"; + + printOffset(MO.getOffset(), O); + return; + } + case MachineOperand::MO_ExternalSymbol: { + std::string Name(MAI->getGlobalPrefix()); + Name += MO.getSymbolName(); + O << Name; + + if (TM.getRelocationModel() == Reloc::PIC_) + O << "@PLT"; + + return; + } + default: + assert(0 && "Not implemented yet!"); + } +} + + +void SystemZAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O, const char *Modifier) { + const MachineOperand &MO = MI->getOperand(OpNum); + switch (MO.getType()) { + case MachineOperand::MO_Register: { + assert (TargetRegisterInfo::isPhysicalRegister(MO.getReg()) && + "Virtual registers should be already mapped!"); + unsigned Reg = MO.getReg(); + if (Modifier && strncmp(Modifier, "subreg", 6) == 0) { + if (strncmp(Modifier + 7, "even", 4) == 0) + Reg = TM.getRegisterInfo()->getSubReg(Reg, SystemZ::subreg_32bit); + else if (strncmp(Modifier + 7, "odd", 3) == 0) + Reg = TM.getRegisterInfo()->getSubReg(Reg, SystemZ::subreg_odd32); + else + assert(0 && "Invalid subreg modifier"); + } + + O << '%' << getRegisterName(Reg); + return; + } + case MachineOperand::MO_Immediate: + O << MO.getImm(); + return; + case MachineOperand::MO_MachineBasicBlock: + O << *MO.getMBB()->getSymbol(); + return; + case MachineOperand::MO_JumpTableIndex: + O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() << '_' + << MO.getIndex(); + + return; + case MachineOperand::MO_ConstantPoolIndex: + O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_' + << MO.getIndex(); + + printOffset(MO.getOffset(), O); + break; + case MachineOperand::MO_GlobalAddress: + O << *Mang->getSymbol(MO.getGlobal()); + break; + case MachineOperand::MO_ExternalSymbol: { + O << *GetExternalSymbolSymbol(MO.getSymbolName()); + break; + } + default: + assert(0 && "Not implemented yet!"); + } + + switch (MO.getTargetFlags()) { + default: assert(0 && "Unknown target flag on GV operand"); + case SystemZII::MO_NO_FLAG: + break; + case SystemZII::MO_GOTENT: O << "@GOTENT"; break; + case SystemZII::MO_PLT: O << "@PLT"; break; + } + + printOffset(MO.getOffset(), O); +} + +void SystemZAsmPrinter::printRIAddrOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O, + const char *Modifier) { + const MachineOperand &Base = MI->getOperand(OpNum); + + // Print displacement operand. + printOperand(MI, OpNum+1, O); + + // Print base operand (if any) + if (Base.getReg()) { + O << '('; + printOperand(MI, OpNum, O); + O << ')'; + } +} + +void SystemZAsmPrinter::printRRIAddrOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O, + const char *Modifier) { + const MachineOperand &Base = MI->getOperand(OpNum); + const MachineOperand &Index = MI->getOperand(OpNum+2); + + // Print displacement operand. + printOperand(MI, OpNum+1, O); + + // Print base operand (if any) + if (Base.getReg()) { + O << '('; + printOperand(MI, OpNum, O); + if (Index.getReg()) { + O << ','; + printOperand(MI, OpNum+2, O); + } + O << ')'; + } else + assert(!Index.getReg() && "Should allocate base register first!"); +} + +// Force static initialization. +extern "C" void LLVMInitializeSystemZAsmPrinter() { + RegisterAsmPrinter<SystemZAsmPrinter> X(TheSystemZTarget); +} diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZCallingConv.td b/contrib/llvm/lib/Target/SystemZ/SystemZCallingConv.td new file mode 100644 index 0000000..c799a9e --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZCallingConv.td @@ -0,0 +1,46 @@ +//=- SystemZCallingConv.td - Calling Conventions for SystemZ -*- tablegen -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This describes the calling conventions for SystemZ architecture. +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// SystemZ Return Value Calling Convention +//===----------------------------------------------------------------------===// +def RetCC_SystemZ : CallingConv<[ + // Promote i8/i16/i32 arguments to i64. + CCIfType<[i8, i16, i32], CCPromoteToType<i64>>, + + // i64 is returned in register R2 + CCIfType<[i64], CCAssignToReg<[R2D, R3D, R4D, R5D]>>, + + // f32 / f64 are returned in F0 + CCIfType<[f32], CCAssignToReg<[F0S, F2S, F4S, F6S]>>, + CCIfType<[f64], CCAssignToReg<[F0L, F2L, F4L, F6L]>> +]>; + +//===----------------------------------------------------------------------===// +// SystemZ Argument Calling Conventions +//===----------------------------------------------------------------------===// +def CC_SystemZ : CallingConv<[ + // Promote i8/i16/i32 arguments to i64. + CCIfType<[i8, i16, i32], CCPromoteToType<i64>>, + + // The first 5 integer arguments of non-varargs functions are passed in + // integer registers. + CCIfType<[i64], CCAssignToReg<[R2D, R3D, R4D, R5D, R6D]>>, + + // The first 4 floating point arguments of non-varargs functions are passed + // in FP registers. + CCIfType<[f32], CCAssignToReg<[F0S, F2S, F4S, F6S]>>, + CCIfType<[f64], CCAssignToReg<[F0L, F2L, F4L, F6L]>>, + + // Integer values get stored in stack slots that are 8 bytes in + // size and 8-byte aligned. + CCIfType<[i64, f32, f64], CCAssignToStack<8, 8>> +]>; diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp new file mode 100644 index 0000000..2ad84a2 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp @@ -0,0 +1,386 @@ +//=====- SystemZFrameLowering.cpp - SystemZ Frame Information ------*- C++ -*-====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the SystemZ implementation of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#include "SystemZFrameLowering.h" +#include "SystemZInstrBuilder.h" +#include "SystemZInstrInfo.h" +#include "SystemZMachineFunctionInfo.h" +#include "llvm/Function.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Support/CommandLine.h" + +using namespace llvm; + +SystemZFrameLowering::SystemZFrameLowering(const SystemZSubtarget &sti) + : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 8, -160), STI(sti) { + // Fill the spill offsets map + static const unsigned SpillOffsTab[][2] = { + { SystemZ::R2D, 0x10 }, + { SystemZ::R3D, 0x18 }, + { SystemZ::R4D, 0x20 }, + { SystemZ::R5D, 0x28 }, + { SystemZ::R6D, 0x30 }, + { SystemZ::R7D, 0x38 }, + { SystemZ::R8D, 0x40 }, + { SystemZ::R9D, 0x48 }, + { SystemZ::R10D, 0x50 }, + { SystemZ::R11D, 0x58 }, + { SystemZ::R12D, 0x60 }, + { SystemZ::R13D, 0x68 }, + { SystemZ::R14D, 0x70 }, + { SystemZ::R15D, 0x78 } + }; + + RegSpillOffsets.grow(SystemZ::NUM_TARGET_REGS); + + for (unsigned i = 0, e = array_lengthof(SpillOffsTab); i != e; ++i) + RegSpillOffsets[SpillOffsTab[i][0]] = SpillOffsTab[i][1]; +} + +/// needsFP - Return true if the specified function should have a dedicated +/// frame pointer register. This is true if the function has variable sized +/// allocas or if frame pointer elimination is disabled. +bool SystemZFrameLowering::hasFP(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + return DisableFramePointerElim(MF) || MFI->hasVarSizedObjects(); +} + +/// emitSPUpdate - Emit a series of instructions to increment / decrement the +/// stack pointer by a constant value. +static +void emitSPUpdate(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, + int64_t NumBytes, const TargetInstrInfo &TII) { + unsigned Opc; uint64_t Chunk; + bool isSub = NumBytes < 0; + uint64_t Offset = isSub ? -NumBytes : NumBytes; + + if (Offset >= (1LL << 15) - 1) { + Opc = SystemZ::ADD64ri32; + Chunk = (1LL << 31) - 1; + } else { + Opc = SystemZ::ADD64ri16; + Chunk = (1LL << 15) - 1; + } + + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + + while (Offset) { + uint64_t ThisVal = (Offset > Chunk) ? Chunk : Offset; + MachineInstr *MI = + BuildMI(MBB, MBBI, DL, TII.get(Opc), SystemZ::R15D) + .addReg(SystemZ::R15D).addImm(isSub ? -ThisVal : ThisVal); + // The PSW implicit def is dead. + MI->getOperand(3).setIsDead(); + Offset -= ThisVal; + } +} + +void SystemZFrameLowering::emitPrologue(MachineFunction &MF) const { + MachineBasicBlock &MBB = MF.front(); // Prolog goes in entry BB + MachineFrameInfo *MFI = MF.getFrameInfo(); + const SystemZInstrInfo &TII = + *static_cast<const SystemZInstrInfo*>(MF.getTarget().getInstrInfo()); + SystemZMachineFunctionInfo *SystemZMFI = + MF.getInfo<SystemZMachineFunctionInfo>(); + MachineBasicBlock::iterator MBBI = MBB.begin(); + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + + // Get the number of bytes to allocate from the FrameInfo. + // Note that area for callee-saved stuff is already allocated, thus we need to + // 'undo' the stack movement. + uint64_t StackSize = MFI->getStackSize(); + StackSize -= SystemZMFI->getCalleeSavedFrameSize(); + + uint64_t NumBytes = StackSize - getOffsetOfLocalArea(); + + // Skip the callee-saved push instructions. + while (MBBI != MBB.end() && + (MBBI->getOpcode() == SystemZ::MOV64mr || + MBBI->getOpcode() == SystemZ::MOV64mrm)) + ++MBBI; + + if (MBBI != MBB.end()) + DL = MBBI->getDebugLoc(); + + // adjust stack pointer: R15 -= numbytes + if (StackSize || MFI->hasCalls()) { + assert(MF.getRegInfo().isPhysRegUsed(SystemZ::R15D) && + "Invalid stack frame calculation!"); + emitSPUpdate(MBB, MBBI, -(int64_t)NumBytes, TII); + } + + if (hasFP(MF)) { + // Update R11 with the new base value... + BuildMI(MBB, MBBI, DL, TII.get(SystemZ::MOV64rr), SystemZ::R11D) + .addReg(SystemZ::R15D); + + // Mark the FramePtr as live-in in every block except the entry. + for (MachineFunction::iterator I = llvm::next(MF.begin()), E = MF.end(); + I != E; ++I) + I->addLiveIn(SystemZ::R11D); + + } +} + +void SystemZFrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); + const SystemZInstrInfo &TII = + *static_cast<const SystemZInstrInfo*>(MF.getTarget().getInstrInfo()); + SystemZMachineFunctionInfo *SystemZMFI = + MF.getInfo<SystemZMachineFunctionInfo>(); + unsigned RetOpcode = MBBI->getOpcode(); + + switch (RetOpcode) { + case SystemZ::RET: break; // These are ok + default: + assert(0 && "Can only insert epilog into returning blocks"); + } + + // Get the number of bytes to allocate from the FrameInfo + // Note that area for callee-saved stuff is already allocated, thus we need to + // 'undo' the stack movement. + uint64_t StackSize = + MFI->getStackSize() - SystemZMFI->getCalleeSavedFrameSize(); + uint64_t NumBytes = StackSize - getOffsetOfLocalArea(); + + // Skip the final terminator instruction. + while (MBBI != MBB.begin()) { + MachineBasicBlock::iterator PI = prior(MBBI); + --MBBI; + if (!PI->getDesc().isTerminator()) + break; + } + + // During callee-saved restores emission stack frame was not yet finialized + // (and thus - the stack size was unknown). Tune the offset having full stack + // size in hands. + if (StackSize || MFI->hasCalls()) { + assert((MBBI->getOpcode() == SystemZ::MOV64rmm || + MBBI->getOpcode() == SystemZ::MOV64rm) && + "Expected to see callee-save register restore code"); + assert(MF.getRegInfo().isPhysRegUsed(SystemZ::R15D) && + "Invalid stack frame calculation!"); + + unsigned i = 0; + MachineInstr &MI = *MBBI; + while (!MI.getOperand(i).isImm()) { + ++i; + assert(i < MI.getNumOperands() && "Unexpected restore code!"); + } + + uint64_t Offset = NumBytes + MI.getOperand(i).getImm(); + // If Offset does not fit into 20-bit signed displacement field we need to + // emit some additional code... + if (Offset > 524287) { + // Fold the displacement into load instruction as much as possible. + NumBytes = Offset - 524287; + Offset = 524287; + emitSPUpdate(MBB, MBBI, NumBytes, TII); + } + + MI.getOperand(i).ChangeToImmediate(Offset); + } +} + +int SystemZFrameLowering::getFrameIndexOffset(const MachineFunction &MF, + int FI) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + const SystemZMachineFunctionInfo *SystemZMFI = + MF.getInfo<SystemZMachineFunctionInfo>(); + int Offset = MFI->getObjectOffset(FI) + MFI->getOffsetAdjustment(); + uint64_t StackSize = MFI->getStackSize(); + + // Fixed objects are really located in the "previous" frame. + if (FI < 0) + StackSize -= SystemZMFI->getCalleeSavedFrameSize(); + + Offset += StackSize - getOffsetOfLocalArea(); + + // Skip the register save area if we generated the stack frame. + if (StackSize || MFI->hasCalls()) + Offset -= getOffsetOfLocalArea(); + + return Offset; +} + +bool +SystemZFrameLowering::spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const { + if (CSI.empty()) + return false; + + DebugLoc DL; + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + MachineFunction &MF = *MBB.getParent(); + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + SystemZMachineFunctionInfo *MFI = MF.getInfo<SystemZMachineFunctionInfo>(); + unsigned CalleeFrameSize = 0; + + // Scan the callee-saved and find the bounds of register spill area. + unsigned LowReg = 0, HighReg = 0, StartOffset = -1U, EndOffset = 0; + for (unsigned i = 0, e = CSI.size(); i != e; ++i) { + unsigned Reg = CSI[i].getReg(); + if (!SystemZ::FP64RegClass.contains(Reg)) { + unsigned Offset = RegSpillOffsets[Reg]; + CalleeFrameSize += 8; + if (StartOffset > Offset) { + LowReg = Reg; StartOffset = Offset; + } + if (EndOffset < Offset) { + HighReg = Reg; EndOffset = RegSpillOffsets[Reg]; + } + } + } + + // Save information for epilogue inserter. + MFI->setCalleeSavedFrameSize(CalleeFrameSize); + MFI->setLowReg(LowReg); MFI->setHighReg(HighReg); + + // Save GPRs + if (StartOffset) { + // Build a store instruction. Use STORE MULTIPLE instruction if there are many + // registers to store, otherwise - just STORE. + MachineInstrBuilder MIB = + BuildMI(MBB, MI, DL, TII.get((LowReg == HighReg ? + SystemZ::MOV64mr : SystemZ::MOV64mrm))); + + // Add store operands. + MIB.addReg(SystemZ::R15D).addImm(StartOffset); + if (LowReg == HighReg) + MIB.addReg(0); + MIB.addReg(LowReg, RegState::Kill); + if (LowReg != HighReg) + MIB.addReg(HighReg, RegState::Kill); + + // Do a second scan adding regs as being killed by instruction + for (unsigned i = 0, e = CSI.size(); i != e; ++i) { + unsigned Reg = CSI[i].getReg(); + // Add the callee-saved register as live-in. It's killed at the spill. + MBB.addLiveIn(Reg); + if (Reg != LowReg && Reg != HighReg) + MIB.addReg(Reg, RegState::ImplicitKill); + } + } + + // Save FPRs + for (unsigned i = 0, e = CSI.size(); i != e; ++i) { + unsigned Reg = CSI[i].getReg(); + if (SystemZ::FP64RegClass.contains(Reg)) { + MBB.addLiveIn(Reg); + TII.storeRegToStackSlot(MBB, MI, Reg, true, CSI[i].getFrameIdx(), + &SystemZ::FP64RegClass, TRI); + } + } + + return true; +} + +bool +SystemZFrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const { + if (CSI.empty()) + return false; + + DebugLoc DL; + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + MachineFunction &MF = *MBB.getParent(); + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + SystemZMachineFunctionInfo *MFI = MF.getInfo<SystemZMachineFunctionInfo>(); + + // Restore FP registers + for (unsigned i = 0, e = CSI.size(); i != e; ++i) { + unsigned Reg = CSI[i].getReg(); + if (SystemZ::FP64RegClass.contains(Reg)) + TII.loadRegFromStackSlot(MBB, MI, Reg, CSI[i].getFrameIdx(), + &SystemZ::FP64RegClass, TRI); + } + + // Restore GP registers + unsigned LowReg = MFI->getLowReg(), HighReg = MFI->getHighReg(); + unsigned StartOffset = RegSpillOffsets[LowReg]; + + if (StartOffset) { + // Build a load instruction. Use LOAD MULTIPLE instruction if there are many + // registers to load, otherwise - just LOAD. + MachineInstrBuilder MIB = + BuildMI(MBB, MI, DL, TII.get((LowReg == HighReg ? + SystemZ::MOV64rm : SystemZ::MOV64rmm))); + // Add store operands. + MIB.addReg(LowReg, RegState::Define); + if (LowReg != HighReg) + MIB.addReg(HighReg, RegState::Define); + + MIB.addReg(hasFP(MF) ? SystemZ::R11D : SystemZ::R15D); + MIB.addImm(StartOffset); + if (LowReg == HighReg) + MIB.addReg(0); + + // Do a second scan adding regs as being defined by instruction + for (unsigned i = 0, e = CSI.size(); i != e; ++i) { + unsigned Reg = CSI[i].getReg(); + if (Reg != LowReg && Reg != HighReg) + MIB.addReg(Reg, RegState::ImplicitDefine); + } + } + + return true; +} + +void +SystemZFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS) const { + // Determine whether R15/R14 will ever be clobbered inside the function. And + // if yes - mark it as 'callee' saved. + MachineFrameInfo *FFI = MF.getFrameInfo(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + + // Check whether high FPRs are ever used, if yes - we need to save R15 as + // well. + static const unsigned HighFPRs[] = { + SystemZ::F8L, SystemZ::F9L, SystemZ::F10L, SystemZ::F11L, + SystemZ::F12L, SystemZ::F13L, SystemZ::F14L, SystemZ::F15L, + SystemZ::F8S, SystemZ::F9S, SystemZ::F10S, SystemZ::F11S, + SystemZ::F12S, SystemZ::F13S, SystemZ::F14S, SystemZ::F15S, + }; + + bool HighFPRsUsed = false; + for (unsigned i = 0, e = array_lengthof(HighFPRs); i != e; ++i) + HighFPRsUsed |= MRI.isPhysRegUsed(HighFPRs[i]); + + if (FFI->hasCalls()) + /* FIXME: function is varargs */ + /* FIXME: function grabs RA */ + /* FIXME: function calls eh_return */ + MRI.setPhysRegUsed(SystemZ::R14D); + + if (HighFPRsUsed || + FFI->hasCalls() || + FFI->getObjectIndexEnd() != 0 || // Contains automatic variables + FFI->hasVarSizedObjects() // Function calls dynamic alloca's + /* FIXME: function is varargs */) + MRI.setPhysRegUsed(SystemZ::R15D); +} diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZFrameLowering.h b/contrib/llvm/lib/Target/SystemZ/SystemZFrameLowering.h new file mode 100644 index 0000000..1284b68 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZFrameLowering.h @@ -0,0 +1,57 @@ +//=- SystemZFrameLowering.h - Define frame lowering for z/System -*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// +//===----------------------------------------------------------------------===// + +#ifndef SYSTEMZ_FRAMEINFO_H +#define SYSTEMZ_FRAMEINFO_H + +#include "SystemZ.h" +#include "SystemZSubtarget.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/ADT/IndexedMap.h" + +namespace llvm { + class SystemZSubtarget; + +class SystemZFrameLowering : public TargetFrameLowering { + IndexedMap<unsigned> RegSpillOffsets; +protected: + const SystemZSubtarget &STI; + +public: + explicit SystemZFrameLowering(const SystemZSubtarget &sti); + + /// emitProlog/emitEpilog - These methods insert prolog and epilog code into + /// the function. + void emitPrologue(MachineFunction &MF) const; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + + bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const; + bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const; + + void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS) const; + + bool hasReservedCallFrame(const MachineFunction &MF) const { return true; } + bool hasFP(const MachineFunction &MF) const; + int getFrameIndexOffset(const MachineFunction &MF, int FI) const; +}; + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp new file mode 100644 index 0000000..2186ff1 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp @@ -0,0 +1,779 @@ +//==-- SystemZISelDAGToDAG.cpp - A dag to dag inst selector for SystemZ ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an instruction selector for the SystemZ target. +// +//===----------------------------------------------------------------------===// + +#include "SystemZ.h" +#include "SystemZTargetMachine.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/Intrinsics.h" +#include "llvm/CallingConv.h" +#include "llvm/Constants.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Target/TargetLowering.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +namespace { + /// SystemZRRIAddressMode - This corresponds to rriaddr, but uses SDValue's + /// instead of register numbers for the leaves of the matched tree. + struct SystemZRRIAddressMode { + enum { + RegBase, + FrameIndexBase + } BaseType; + + struct { // This is really a union, discriminated by BaseType! + SDValue Reg; + int FrameIndex; + } Base; + + SDValue IndexReg; + int64_t Disp; + bool isRI; + + SystemZRRIAddressMode(bool RI = false) + : BaseType(RegBase), IndexReg(), Disp(0), isRI(RI) { + } + + void dump() { + errs() << "SystemZRRIAddressMode " << this << '\n'; + if (BaseType == RegBase) { + errs() << "Base.Reg "; + if (Base.Reg.getNode() != 0) + Base.Reg.getNode()->dump(); + else + errs() << "nul"; + errs() << '\n'; + } else { + errs() << " Base.FrameIndex " << Base.FrameIndex << '\n'; + } + if (!isRI) { + errs() << "IndexReg "; + if (IndexReg.getNode() != 0) IndexReg.getNode()->dump(); + else errs() << "nul"; + } + errs() << " Disp " << Disp << '\n'; + } + }; +} + +/// SystemZDAGToDAGISel - SystemZ specific code to select SystemZ machine +/// instructions for SelectionDAG operations. +/// +namespace { + class SystemZDAGToDAGISel : public SelectionDAGISel { + const SystemZTargetLowering &Lowering; + const SystemZSubtarget &Subtarget; + + void getAddressOperandsRI(const SystemZRRIAddressMode &AM, + SDValue &Base, SDValue &Disp); + void getAddressOperands(const SystemZRRIAddressMode &AM, + SDValue &Base, SDValue &Disp, + SDValue &Index); + + public: + SystemZDAGToDAGISel(SystemZTargetMachine &TM, CodeGenOpt::Level OptLevel) + : SelectionDAGISel(TM, OptLevel), + Lowering(*TM.getTargetLowering()), + Subtarget(*TM.getSubtargetImpl()) { } + + virtual const char *getPassName() const { + return "SystemZ DAG->DAG Pattern Instruction Selection"; + } + + /// getI8Imm - Return a target constant with the specified value, of type + /// i8. + inline SDValue getI8Imm(uint64_t Imm) { + return CurDAG->getTargetConstant(Imm, MVT::i8); + } + + /// getI16Imm - Return a target constant with the specified value, of type + /// i16. + inline SDValue getI16Imm(uint64_t Imm) { + return CurDAG->getTargetConstant(Imm, MVT::i16); + } + + /// getI32Imm - Return a target constant with the specified value, of type + /// i32. + inline SDValue getI32Imm(uint64_t Imm) { + return CurDAG->getTargetConstant(Imm, MVT::i32); + } + + // Include the pieces autogenerated from the target description. + #include "SystemZGenDAGISel.inc" + + private: + bool SelectAddrRI12Only(SDValue& Addr, + SDValue &Base, SDValue &Disp); + bool SelectAddrRI12(SDValue& Addr, + SDValue &Base, SDValue &Disp, + bool is12BitOnly = false); + bool SelectAddrRI(SDValue& Addr, SDValue &Base, SDValue &Disp); + bool SelectAddrRRI12(SDValue Addr, + SDValue &Base, SDValue &Disp, SDValue &Index); + bool SelectAddrRRI20(SDValue Addr, + SDValue &Base, SDValue &Disp, SDValue &Index); + bool SelectLAAddr(SDValue Addr, + SDValue &Base, SDValue &Disp, SDValue &Index); + + SDNode *Select(SDNode *Node); + + bool TryFoldLoad(SDNode *P, SDValue N, + SDValue &Base, SDValue &Disp, SDValue &Index); + + bool MatchAddress(SDValue N, SystemZRRIAddressMode &AM, + bool is12Bit, unsigned Depth = 0); + bool MatchAddressBase(SDValue N, SystemZRRIAddressMode &AM); + }; +} // end anonymous namespace + +/// createSystemZISelDag - This pass converts a legalized DAG into a +/// SystemZ-specific DAG, ready for instruction scheduling. +/// +FunctionPass *llvm::createSystemZISelDag(SystemZTargetMachine &TM, + CodeGenOpt::Level OptLevel) { + return new SystemZDAGToDAGISel(TM, OptLevel); +} + +/// isImmSExt20 - This method tests to see if the node is either a 32-bit +/// or 64-bit immediate, and if the value can be accurately represented as a +/// sign extension from a 20-bit value. If so, this returns true and the +/// immediate. +static bool isImmSExt20(int64_t Val, int64_t &Imm) { + if (Val >= -524288 && Val <= 524287) { + Imm = Val; + return true; + } + return false; +} + +/// isImmZExt12 - This method tests to see if the node is either a 32-bit +/// or 64-bit immediate, and if the value can be accurately represented as a +/// zero extension from a 12-bit value. If so, this returns true and the +/// immediate. +static bool isImmZExt12(int64_t Val, int64_t &Imm) { + if (Val >= 0 && Val <= 0xFFF) { + Imm = Val; + return true; + } + return false; +} + +/// MatchAddress - Add the specified node to the specified addressing mode, +/// returning true if it cannot be done. This just pattern matches for the +/// addressing mode. +bool SystemZDAGToDAGISel::MatchAddress(SDValue N, SystemZRRIAddressMode &AM, + bool is12Bit, unsigned Depth) { + DebugLoc dl = N.getDebugLoc(); + DEBUG(errs() << "MatchAddress: "; AM.dump()); + // Limit recursion. + if (Depth > 5) + return MatchAddressBase(N, AM); + + // FIXME: We can perform better here. If we have something like + // (shift (add A, imm), N), we can try to reassociate stuff and fold shift of + // imm into addressing mode. + switch (N.getOpcode()) { + default: break; + case ISD::Constant: { + int64_t Val = cast<ConstantSDNode>(N)->getSExtValue(); + int64_t Imm = 0; + bool Match = (is12Bit ? + isImmZExt12(AM.Disp + Val, Imm) : + isImmSExt20(AM.Disp + Val, Imm)); + if (Match) { + AM.Disp = Imm; + return false; + } + break; + } + + case ISD::FrameIndex: + if (AM.BaseType == SystemZRRIAddressMode::RegBase && + AM.Base.Reg.getNode() == 0) { + AM.BaseType = SystemZRRIAddressMode::FrameIndexBase; + AM.Base.FrameIndex = cast<FrameIndexSDNode>(N)->getIndex(); + return false; + } + break; + + case ISD::SUB: { + // Given A-B, if A can be completely folded into the address and + // the index field with the index field unused, use -B as the index. + // This is a win if a has multiple parts that can be folded into + // the address. Also, this saves a mov if the base register has + // other uses, since it avoids a two-address sub instruction, however + // it costs an additional mov if the index register has other uses. + + // Test if the LHS of the sub can be folded. + SystemZRRIAddressMode Backup = AM; + if (MatchAddress(N.getNode()->getOperand(0), AM, is12Bit, Depth+1)) { + AM = Backup; + break; + } + // Test if the index field is free for use. + if (AM.IndexReg.getNode() || AM.isRI) { + AM = Backup; + break; + } + + // If the base is a register with multiple uses, this transformation may + // save a mov. Otherwise it's probably better not to do it. + if (AM.BaseType == SystemZRRIAddressMode::RegBase && + (!AM.Base.Reg.getNode() || AM.Base.Reg.getNode()->hasOneUse())) { + AM = Backup; + break; + } + + // Ok, the transformation is legal and appears profitable. Go for it. + SDValue RHS = N.getNode()->getOperand(1); + SDValue Zero = CurDAG->getConstant(0, N.getValueType()); + SDValue Neg = CurDAG->getNode(ISD::SUB, dl, N.getValueType(), Zero, RHS); + AM.IndexReg = Neg; + + // Insert the new nodes into the topological ordering. + if (Zero.getNode()->getNodeId() == -1 || + Zero.getNode()->getNodeId() > N.getNode()->getNodeId()) { + CurDAG->RepositionNode(N.getNode(), Zero.getNode()); + Zero.getNode()->setNodeId(N.getNode()->getNodeId()); + } + if (Neg.getNode()->getNodeId() == -1 || + Neg.getNode()->getNodeId() > N.getNode()->getNodeId()) { + CurDAG->RepositionNode(N.getNode(), Neg.getNode()); + Neg.getNode()->setNodeId(N.getNode()->getNodeId()); + } + return false; + } + + case ISD::ADD: { + SystemZRRIAddressMode Backup = AM; + if (!MatchAddress(N.getNode()->getOperand(0), AM, is12Bit, Depth+1) && + !MatchAddress(N.getNode()->getOperand(1), AM, is12Bit, Depth+1)) + return false; + AM = Backup; + if (!MatchAddress(N.getNode()->getOperand(1), AM, is12Bit, Depth+1) && + !MatchAddress(N.getNode()->getOperand(0), AM, is12Bit, Depth+1)) + return false; + AM = Backup; + + // If we couldn't fold both operands into the address at the same time, + // see if we can just put each operand into a register and fold at least + // the add. + if (!AM.isRI && + AM.BaseType == SystemZRRIAddressMode::RegBase && + !AM.Base.Reg.getNode() && !AM.IndexReg.getNode()) { + AM.Base.Reg = N.getNode()->getOperand(0); + AM.IndexReg = N.getNode()->getOperand(1); + return false; + } + break; + } + + case ISD::OR: + // Handle "X | C" as "X + C" iff X is known to have C bits clear. + if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.getOperand(1))) { + SystemZRRIAddressMode Backup = AM; + int64_t Offset = CN->getSExtValue(); + int64_t Imm = 0; + bool MatchOffset = (is12Bit ? + isImmZExt12(AM.Disp + Offset, Imm) : + isImmSExt20(AM.Disp + Offset, Imm)); + // The resultant disp must fit in 12 or 20-bits. + if (MatchOffset && + // LHS should be an addr mode. + !MatchAddress(N.getOperand(0), AM, is12Bit, Depth+1) && + // Check to see if the LHS & C is zero. + CurDAG->MaskedValueIsZero(N.getOperand(0), CN->getAPIntValue())) { + AM.Disp = Imm; + return false; + } + AM = Backup; + } + break; + } + + return MatchAddressBase(N, AM); +} + +/// MatchAddressBase - Helper for MatchAddress. Add the specified node to the +/// specified addressing mode without any further recursion. +bool SystemZDAGToDAGISel::MatchAddressBase(SDValue N, + SystemZRRIAddressMode &AM) { + // Is the base register already occupied? + if (AM.BaseType != SystemZRRIAddressMode::RegBase || AM.Base.Reg.getNode()) { + // If so, check to see if the index register is set. + if (AM.IndexReg.getNode() == 0 && !AM.isRI) { + AM.IndexReg = N; + return false; + } + + // Otherwise, we cannot select it. + return true; + } + + // Default, generate it as a register. + AM.BaseType = SystemZRRIAddressMode::RegBase; + AM.Base.Reg = N; + return false; +} + +void SystemZDAGToDAGISel::getAddressOperandsRI(const SystemZRRIAddressMode &AM, + SDValue &Base, SDValue &Disp) { + if (AM.BaseType == SystemZRRIAddressMode::RegBase) + Base = AM.Base.Reg; + else + Base = CurDAG->getTargetFrameIndex(AM.Base.FrameIndex, TLI.getPointerTy()); + Disp = CurDAG->getTargetConstant(AM.Disp, MVT::i64); +} + +void SystemZDAGToDAGISel::getAddressOperands(const SystemZRRIAddressMode &AM, + SDValue &Base, SDValue &Disp, + SDValue &Index) { + getAddressOperandsRI(AM, Base, Disp); + Index = AM.IndexReg; +} + +/// Returns true if the address can be represented by a base register plus +/// an unsigned 12-bit displacement [r+imm]. +bool SystemZDAGToDAGISel::SelectAddrRI12Only(SDValue &Addr, + SDValue &Base, SDValue &Disp) { + return SelectAddrRI12(Addr, Base, Disp, /*is12BitOnly*/true); +} + +bool SystemZDAGToDAGISel::SelectAddrRI12(SDValue &Addr, + SDValue &Base, SDValue &Disp, + bool is12BitOnly) { + SystemZRRIAddressMode AM20(/*isRI*/true), AM12(/*isRI*/true); + bool Done = false; + + if (!Addr.hasOneUse()) { + unsigned Opcode = Addr.getOpcode(); + if (Opcode != ISD::Constant && Opcode != ISD::FrameIndex) { + // If we are able to fold N into addressing mode, then we'll allow it even + // if N has multiple uses. In general, addressing computation is used as + // addresses by all of its uses. But watch out for CopyToReg uses, that + // means the address computation is liveout. It will be computed by a LA + // so we want to avoid computing the address twice. + for (SDNode::use_iterator UI = Addr.getNode()->use_begin(), + UE = Addr.getNode()->use_end(); UI != UE; ++UI) { + if (UI->getOpcode() == ISD::CopyToReg) { + MatchAddressBase(Addr, AM12); + Done = true; + break; + } + } + } + } + if (!Done && MatchAddress(Addr, AM12, /* is12Bit */ true)) + return false; + + // Check, whether we can match stuff using 20-bit displacements + if (!Done && !is12BitOnly && + !MatchAddress(Addr, AM20, /* is12Bit */ false)) + if (AM12.Disp == 0 && AM20.Disp != 0) + return false; + + DEBUG(errs() << "MatchAddress (final): "; AM12.dump()); + + EVT VT = Addr.getValueType(); + if (AM12.BaseType == SystemZRRIAddressMode::RegBase) { + if (!AM12.Base.Reg.getNode()) + AM12.Base.Reg = CurDAG->getRegister(0, VT); + } + + assert(AM12.IndexReg.getNode() == 0 && "Invalid reg-imm address mode!"); + + getAddressOperandsRI(AM12, Base, Disp); + + return true; +} + +/// Returns true if the address can be represented by a base register plus +/// a signed 20-bit displacement [r+imm]. +bool SystemZDAGToDAGISel::SelectAddrRI(SDValue& Addr, + SDValue &Base, SDValue &Disp) { + SystemZRRIAddressMode AM(/*isRI*/true); + bool Done = false; + + if (!Addr.hasOneUse()) { + unsigned Opcode = Addr.getOpcode(); + if (Opcode != ISD::Constant && Opcode != ISD::FrameIndex) { + // If we are able to fold N into addressing mode, then we'll allow it even + // if N has multiple uses. In general, addressing computation is used as + // addresses by all of its uses. But watch out for CopyToReg uses, that + // means the address computation is liveout. It will be computed by a LA + // so we want to avoid computing the address twice. + for (SDNode::use_iterator UI = Addr.getNode()->use_begin(), + UE = Addr.getNode()->use_end(); UI != UE; ++UI) { + if (UI->getOpcode() == ISD::CopyToReg) { + MatchAddressBase(Addr, AM); + Done = true; + break; + } + } + } + } + if (!Done && MatchAddress(Addr, AM, /* is12Bit */ false)) + return false; + + DEBUG(errs() << "MatchAddress (final): "; AM.dump()); + + EVT VT = Addr.getValueType(); + if (AM.BaseType == SystemZRRIAddressMode::RegBase) { + if (!AM.Base.Reg.getNode()) + AM.Base.Reg = CurDAG->getRegister(0, VT); + } + + assert(AM.IndexReg.getNode() == 0 && "Invalid reg-imm address mode!"); + + getAddressOperandsRI(AM, Base, Disp); + + return true; +} + +/// Returns true if the address can be represented by a base register plus +/// index register plus an unsigned 12-bit displacement [base + idx + imm]. +bool SystemZDAGToDAGISel::SelectAddrRRI12(SDValue Addr, + SDValue &Base, SDValue &Disp, SDValue &Index) { + SystemZRRIAddressMode AM20, AM12; + bool Done = false; + + if (!Addr.hasOneUse()) { + unsigned Opcode = Addr.getOpcode(); + if (Opcode != ISD::Constant && Opcode != ISD::FrameIndex) { + // If we are able to fold N into addressing mode, then we'll allow it even + // if N has multiple uses. In general, addressing computation is used as + // addresses by all of its uses. But watch out for CopyToReg uses, that + // means the address computation is liveout. It will be computed by a LA + // so we want to avoid computing the address twice. + for (SDNode::use_iterator UI = Addr.getNode()->use_begin(), + UE = Addr.getNode()->use_end(); UI != UE; ++UI) { + if (UI->getOpcode() == ISD::CopyToReg) { + MatchAddressBase(Addr, AM12); + Done = true; + break; + } + } + } + } + if (!Done && MatchAddress(Addr, AM12, /* is12Bit */ true)) + return false; + + // Check, whether we can match stuff using 20-bit displacements + if (!Done && !MatchAddress(Addr, AM20, /* is12Bit */ false)) + if (AM12.Disp == 0 && AM20.Disp != 0) + return false; + + DEBUG(errs() << "MatchAddress (final): "; AM12.dump()); + + EVT VT = Addr.getValueType(); + if (AM12.BaseType == SystemZRRIAddressMode::RegBase) { + if (!AM12.Base.Reg.getNode()) + AM12.Base.Reg = CurDAG->getRegister(0, VT); + } + + if (!AM12.IndexReg.getNode()) + AM12.IndexReg = CurDAG->getRegister(0, VT); + + getAddressOperands(AM12, Base, Disp, Index); + + return true; +} + +/// Returns true if the address can be represented by a base register plus +/// index register plus a signed 20-bit displacement [base + idx + imm]. +bool SystemZDAGToDAGISel::SelectAddrRRI20(SDValue Addr, + SDValue &Base, SDValue &Disp, SDValue &Index) { + SystemZRRIAddressMode AM; + bool Done = false; + + if (!Addr.hasOneUse()) { + unsigned Opcode = Addr.getOpcode(); + if (Opcode != ISD::Constant && Opcode != ISD::FrameIndex) { + // If we are able to fold N into addressing mode, then we'll allow it even + // if N has multiple uses. In general, addressing computation is used as + // addresses by all of its uses. But watch out for CopyToReg uses, that + // means the address computation is liveout. It will be computed by a LA + // so we want to avoid computing the address twice. + for (SDNode::use_iterator UI = Addr.getNode()->use_begin(), + UE = Addr.getNode()->use_end(); UI != UE; ++UI) { + if (UI->getOpcode() == ISD::CopyToReg) { + MatchAddressBase(Addr, AM); + Done = true; + break; + } + } + } + } + if (!Done && MatchAddress(Addr, AM, /* is12Bit */ false)) + return false; + + DEBUG(errs() << "MatchAddress (final): "; AM.dump()); + + EVT VT = Addr.getValueType(); + if (AM.BaseType == SystemZRRIAddressMode::RegBase) { + if (!AM.Base.Reg.getNode()) + AM.Base.Reg = CurDAG->getRegister(0, VT); + } + + if (!AM.IndexReg.getNode()) + AM.IndexReg = CurDAG->getRegister(0, VT); + + getAddressOperands(AM, Base, Disp, Index); + + return true; +} + +/// SelectLAAddr - it calls SelectAddr and determines if the maximal addressing +/// mode it matches can be cost effectively emitted as an LA/LAY instruction. +bool SystemZDAGToDAGISel::SelectLAAddr(SDValue Addr, + SDValue &Base, SDValue &Disp, SDValue &Index) { + SystemZRRIAddressMode AM; + + if (MatchAddress(Addr, AM, false)) + return false; + + EVT VT = Addr.getValueType(); + unsigned Complexity = 0; + if (AM.BaseType == SystemZRRIAddressMode::RegBase) + if (AM.Base.Reg.getNode()) + Complexity = 1; + else + AM.Base.Reg = CurDAG->getRegister(0, VT); + else if (AM.BaseType == SystemZRRIAddressMode::FrameIndexBase) + Complexity = 4; + + if (AM.IndexReg.getNode()) + Complexity += 1; + else + AM.IndexReg = CurDAG->getRegister(0, VT); + + if (AM.Disp && (AM.Base.Reg.getNode() || AM.IndexReg.getNode())) + Complexity += 1; + + if (Complexity > 2) { + getAddressOperands(AM, Base, Disp, Index); + return true; + } + + return false; +} + +bool SystemZDAGToDAGISel::TryFoldLoad(SDNode *P, SDValue N, + SDValue &Base, SDValue &Disp, SDValue &Index) { + if (ISD::isNON_EXTLoad(N.getNode()) && + IsLegalToFold(N, P, P, OptLevel)) + return SelectAddrRRI20(N.getOperand(1), Base, Disp, Index); + return false; +} + +SDNode *SystemZDAGToDAGISel::Select(SDNode *Node) { + EVT NVT = Node->getValueType(0); + DebugLoc dl = Node->getDebugLoc(); + unsigned Opcode = Node->getOpcode(); + + // Dump information about the Node being selected + DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n"); + + // If we have a custom node, we already have selected! + if (Node->isMachineOpcode()) { + DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); + return NULL; // Already selected. + } + + switch (Opcode) { + default: break; + case ISD::SDIVREM: { + unsigned Opc, MOpc; + SDValue N0 = Node->getOperand(0); + SDValue N1 = Node->getOperand(1); + + EVT ResVT; + bool is32Bit = false; + switch (NVT.getSimpleVT().SimpleTy) { + default: assert(0 && "Unsupported VT!"); + case MVT::i32: + Opc = SystemZ::SDIVREM32r; MOpc = SystemZ::SDIVREM32m; + ResVT = MVT::v2i64; + is32Bit = true; + break; + case MVT::i64: + Opc = SystemZ::SDIVREM64r; MOpc = SystemZ::SDIVREM64m; + ResVT = MVT::v2i64; + break; + } + + SDValue Tmp0, Tmp1, Tmp2; + bool foldedLoad = TryFoldLoad(Node, N1, Tmp0, Tmp1, Tmp2); + + // Prepare the dividend + SDNode *Dividend; + if (is32Bit) + Dividend = CurDAG->getMachineNode(SystemZ::MOVSX64rr32, dl, MVT::i64, N0); + else + Dividend = N0.getNode(); + + // Insert prepared dividend into suitable 'subreg' + SDNode *Tmp = CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, + dl, ResVT); + Dividend = + CurDAG->getMachineNode(TargetOpcode::INSERT_SUBREG, dl, ResVT, + SDValue(Tmp, 0), SDValue(Dividend, 0), + CurDAG->getTargetConstant(SystemZ::subreg_odd, MVT::i32)); + + SDNode *Result; + SDValue DivVal = SDValue(Dividend, 0); + if (foldedLoad) { + SDValue Ops[] = { DivVal, Tmp0, Tmp1, Tmp2, N1.getOperand(0) }; + Result = CurDAG->getMachineNode(MOpc, dl, ResVT, MVT::Other, + Ops, array_lengthof(Ops)); + // Update the chain. + ReplaceUses(N1.getValue(1), SDValue(Result, 1)); + } else { + Result = CurDAG->getMachineNode(Opc, dl, ResVT, SDValue(Dividend, 0), N1); + } + + // Copy the division (odd subreg) result, if it is needed. + if (!SDValue(Node, 0).use_empty()) { + unsigned SubRegIdx = (is32Bit ? + SystemZ::subreg_odd32 : SystemZ::subreg_odd); + SDNode *Div = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, + dl, NVT, + SDValue(Result, 0), + CurDAG->getTargetConstant(SubRegIdx, + MVT::i32)); + + ReplaceUses(SDValue(Node, 0), SDValue(Div, 0)); + DEBUG(errs() << "=> "; Result->dump(CurDAG); errs() << "\n"); + } + + // Copy the remainder (even subreg) result, if it is needed. + if (!SDValue(Node, 1).use_empty()) { + unsigned SubRegIdx = (is32Bit ? + SystemZ::subreg_32bit : SystemZ::subreg_even); + SDNode *Rem = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, + dl, NVT, + SDValue(Result, 0), + CurDAG->getTargetConstant(SubRegIdx, + MVT::i32)); + + ReplaceUses(SDValue(Node, 1), SDValue(Rem, 0)); + DEBUG(errs() << "=> "; Result->dump(CurDAG); errs() << "\n"); + } + + return NULL; + } + case ISD::UDIVREM: { + unsigned Opc, MOpc, ClrOpc; + SDValue N0 = Node->getOperand(0); + SDValue N1 = Node->getOperand(1); + EVT ResVT; + + bool is32Bit = false; + switch (NVT.getSimpleVT().SimpleTy) { + default: assert(0 && "Unsupported VT!"); + case MVT::i32: + Opc = SystemZ::UDIVREM32r; MOpc = SystemZ::UDIVREM32m; + ClrOpc = SystemZ::MOV64Pr0_even; + ResVT = MVT::v2i32; + is32Bit = true; + break; + case MVT::i64: + Opc = SystemZ::UDIVREM64r; MOpc = SystemZ::UDIVREM64m; + ClrOpc = SystemZ::MOV128r0_even; + ResVT = MVT::v2i64; + break; + } + + SDValue Tmp0, Tmp1, Tmp2; + bool foldedLoad = TryFoldLoad(Node, N1, Tmp0, Tmp1, Tmp2); + + // Prepare the dividend + SDNode *Dividend = N0.getNode(); + + // Insert prepared dividend into suitable 'subreg' + SDNode *Tmp = CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, + dl, ResVT); + { + unsigned SubRegIdx = (is32Bit ? + SystemZ::subreg_odd32 : SystemZ::subreg_odd); + Dividend = + CurDAG->getMachineNode(TargetOpcode::INSERT_SUBREG, dl, ResVT, + SDValue(Tmp, 0), SDValue(Dividend, 0), + CurDAG->getTargetConstant(SubRegIdx, MVT::i32)); + } + + // Zero out even subreg + Dividend = CurDAG->getMachineNode(ClrOpc, dl, ResVT, SDValue(Dividend, 0)); + + SDValue DivVal = SDValue(Dividend, 0); + SDNode *Result; + if (foldedLoad) { + SDValue Ops[] = { DivVal, Tmp0, Tmp1, Tmp2, N1.getOperand(0) }; + Result = CurDAG->getMachineNode(MOpc, dl, ResVT, MVT::Other, + Ops, array_lengthof(Ops)); + // Update the chain. + ReplaceUses(N1.getValue(1), SDValue(Result, 1)); + } else { + Result = CurDAG->getMachineNode(Opc, dl, ResVT, DivVal, N1); + } + + // Copy the division (odd subreg) result, if it is needed. + if (!SDValue(Node, 0).use_empty()) { + unsigned SubRegIdx = (is32Bit ? + SystemZ::subreg_odd32 : SystemZ::subreg_odd); + SDNode *Div = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, + dl, NVT, + SDValue(Result, 0), + CurDAG->getTargetConstant(SubRegIdx, + MVT::i32)); + ReplaceUses(SDValue(Node, 0), SDValue(Div, 0)); + DEBUG(errs() << "=> "; Result->dump(CurDAG); errs() << "\n"); + } + + // Copy the remainder (even subreg) result, if it is needed. + if (!SDValue(Node, 1).use_empty()) { + unsigned SubRegIdx = (is32Bit ? + SystemZ::subreg_32bit : SystemZ::subreg_even); + SDNode *Rem = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, + dl, NVT, + SDValue(Result, 0), + CurDAG->getTargetConstant(SubRegIdx, + MVT::i32)); + ReplaceUses(SDValue(Node, 1), SDValue(Rem, 0)); + DEBUG(errs() << "=> "; Result->dump(CurDAG); errs() << "\n"); + } + + return NULL; + } + } + + // Select the default instruction + SDNode *ResNode = SelectCode(Node); + + DEBUG(errs() << "=> "; + if (ResNode == NULL || ResNode == Node) + Node->dump(CurDAG); + else + ResNode->dump(CurDAG); + errs() << "\n"; + ); + return ResNode; +} diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp new file mode 100644 index 0000000..48ca99f --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -0,0 +1,868 @@ +//===-- SystemZISelLowering.cpp - SystemZ DAG Lowering Implementation -----==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SystemZTargetLowering class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "systemz-lower" + +#include "SystemZISelLowering.h" +#include "SystemZ.h" +#include "SystemZTargetMachine.h" +#include "SystemZSubtarget.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/Intrinsics.h" +#include "llvm/CallingConv.h" +#include "llvm/GlobalVariable.h" +#include "llvm/GlobalAlias.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/PseudoSourceValue.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/VectorExtras.h" +using namespace llvm; + +SystemZTargetLowering::SystemZTargetLowering(SystemZTargetMachine &tm) : + TargetLowering(tm, new TargetLoweringObjectFileELF()), + Subtarget(*tm.getSubtargetImpl()), TM(tm) { + + RegInfo = TM.getRegisterInfo(); + + // Set up the register classes. + addRegisterClass(MVT::i32, SystemZ::GR32RegisterClass); + addRegisterClass(MVT::i64, SystemZ::GR64RegisterClass); + addRegisterClass(MVT::v2i32,SystemZ::GR64PRegisterClass); + addRegisterClass(MVT::v2i64,SystemZ::GR128RegisterClass); + + if (!UseSoftFloat) { + addRegisterClass(MVT::f32, SystemZ::FP32RegisterClass); + addRegisterClass(MVT::f64, SystemZ::FP64RegisterClass); + } + + // Compute derived properties from the register classes + computeRegisterProperties(); + + // Provide all sorts of operation actions + setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::EXTLOAD, MVT::i1, Promote); + + setLoadExtAction(ISD::SEXTLOAD, MVT::f32, Expand); + setLoadExtAction(ISD::ZEXTLOAD, MVT::f32, Expand); + setLoadExtAction(ISD::EXTLOAD, MVT::f32, Expand); + + setLoadExtAction(ISD::SEXTLOAD, MVT::f64, Expand); + setLoadExtAction(ISD::ZEXTLOAD, MVT::f64, Expand); + setLoadExtAction(ISD::EXTLOAD, MVT::f64, Expand); + + setStackPointerRegisterToSaveRestore(SystemZ::R15D); + + // TODO: It may be better to default to latency-oriented scheduling, however + // LLVM's current latency-oriented scheduler can't handle physreg definitions + // such as SystemZ has with PSW, so set this to the register-pressure + // scheduler, because it can. + setSchedulingPreference(Sched::RegPressure); + + setBooleanContents(ZeroOrOneBooleanContent); + setBooleanVectorContents(ZeroOrOneBooleanContent); // FIXME: Is this correct? + + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + setOperationAction(ISD::BRCOND, MVT::Other, Expand); + setOperationAction(ISD::BR_CC, MVT::i32, Custom); + setOperationAction(ISD::BR_CC, MVT::i64, Custom); + setOperationAction(ISD::BR_CC, MVT::f32, Custom); + setOperationAction(ISD::BR_CC, MVT::f64, Custom); + setOperationAction(ISD::ConstantPool, MVT::i32, Custom); + setOperationAction(ISD::ConstantPool, MVT::i64, Custom); + setOperationAction(ISD::GlobalAddress, MVT::i64, Custom); + setOperationAction(ISD::JumpTable, MVT::i64, Custom); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Expand); + + setOperationAction(ISD::SDIV, MVT::i32, Expand); + setOperationAction(ISD::UDIV, MVT::i32, Expand); + setOperationAction(ISD::SDIV, MVT::i64, Expand); + setOperationAction(ISD::UDIV, MVT::i64, Expand); + setOperationAction(ISD::SREM, MVT::i32, Expand); + setOperationAction(ISD::UREM, MVT::i32, Expand); + setOperationAction(ISD::SREM, MVT::i64, Expand); + setOperationAction(ISD::UREM, MVT::i64, Expand); + + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + + setOperationAction(ISD::CTPOP, MVT::i32, Expand); + setOperationAction(ISD::CTPOP, MVT::i64, Expand); + setOperationAction(ISD::CTTZ, MVT::i32, Expand); + setOperationAction(ISD::CTTZ, MVT::i64, Expand); + setOperationAction(ISD::CTLZ, MVT::i32, Promote); + setOperationAction(ISD::CTLZ, MVT::i64, Legal); + + // FIXME: Can we lower these 2 efficiently? + setOperationAction(ISD::SETCC, MVT::i32, Expand); + setOperationAction(ISD::SETCC, MVT::i64, Expand); + setOperationAction(ISD::SETCC, MVT::f32, Expand); + setOperationAction(ISD::SETCC, MVT::f64, Expand); + setOperationAction(ISD::SELECT, MVT::i32, Expand); + setOperationAction(ISD::SELECT, MVT::i64, Expand); + setOperationAction(ISD::SELECT, MVT::f32, Expand); + setOperationAction(ISD::SELECT, MVT::f64, Expand); + setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::i64, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f64, Custom); + + setOperationAction(ISD::MULHS, MVT::i64, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand); + + // FIXME: Can we support these natively? + setOperationAction(ISD::UMUL_LOHI, MVT::i64, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i64, Expand); + setOperationAction(ISD::SHL_PARTS, MVT::i64, Expand); + setOperationAction(ISD::SRA_PARTS, MVT::i64, Expand); + + // Lower some FP stuff + setOperationAction(ISD::FSIN, MVT::f32, Expand); + setOperationAction(ISD::FSIN, MVT::f64, Expand); + setOperationAction(ISD::FCOS, MVT::f32, Expand); + setOperationAction(ISD::FCOS, MVT::f64, Expand); + setOperationAction(ISD::FREM, MVT::f32, Expand); + setOperationAction(ISD::FREM, MVT::f64, Expand); + setOperationAction(ISD::FMA, MVT::f32, Expand); + setOperationAction(ISD::FMA, MVT::f64, Expand); + + // We have only 64-bit bitconverts + setOperationAction(ISD::BITCAST, MVT::f32, Expand); + setOperationAction(ISD::BITCAST, MVT::i32, Expand); + + setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand); + setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand); + setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand); + setOperationAction(ISD::FP_TO_UINT, MVT::i64, Expand); + + setTruncStoreAction(MVT::f64, MVT::f32, Expand); + + setMinFunctionAlignment(1); +} + +SDValue SystemZTargetLowering::LowerOperation(SDValue Op, + SelectionDAG &DAG) const { + switch (Op.getOpcode()) { + case ISD::BR_CC: return LowerBR_CC(Op, DAG); + case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG); + case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); + case ISD::JumpTable: return LowerJumpTable(Op, DAG); + case ISD::ConstantPool: return LowerConstantPool(Op, DAG); + default: + llvm_unreachable("Should not custom lower this!"); + return SDValue(); + } +} + +bool SystemZTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { + if (UseSoftFloat || (VT != MVT::f32 && VT != MVT::f64)) + return false; + + // +0.0 lzer + // +0.0f lzdr + // -0.0 lzer + lner + // -0.0f lzdr + lndr + return Imm.isZero() || Imm.isNegZero(); +} + +//===----------------------------------------------------------------------===// +// SystemZ Inline Assembly Support +//===----------------------------------------------------------------------===// + +/// getConstraintType - Given a constraint letter, return the type of +/// constraint it is for this target. +TargetLowering::ConstraintType +SystemZTargetLowering::getConstraintType(const std::string &Constraint) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + case 'r': + return C_RegisterClass; + default: + break; + } + } + return TargetLowering::getConstraintType(Constraint); +} + +std::pair<unsigned, const TargetRegisterClass*> +SystemZTargetLowering:: +getRegForInlineAsmConstraint(const std::string &Constraint, + EVT VT) const { + if (Constraint.size() == 1) { + // GCC Constraint Letters + switch (Constraint[0]) { + default: break; + case 'r': // GENERAL_REGS + if (VT == MVT::i32) + return std::make_pair(0U, SystemZ::GR32RegisterClass); + else if (VT == MVT::i128) + return std::make_pair(0U, SystemZ::GR128RegisterClass); + + return std::make_pair(0U, SystemZ::GR64RegisterClass); + } + } + + return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); +} + +//===----------------------------------------------------------------------===// +// Calling Convention Implementation +//===----------------------------------------------------------------------===// + +#include "SystemZGenCallingConv.inc" + +SDValue +SystemZTargetLowering::LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl<ISD::InputArg> + &Ins, + DebugLoc dl, + SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) + const { + + switch (CallConv) { + default: + llvm_unreachable("Unsupported calling convention"); + case CallingConv::C: + case CallingConv::Fast: + return LowerCCCArguments(Chain, CallConv, isVarArg, Ins, dl, DAG, InVals); + } +} + +SDValue +SystemZTargetLowering::LowerCall(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool isVarArg, + bool &isTailCall, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + // SystemZ target does not yet support tail call optimization. + isTailCall = false; + + switch (CallConv) { + default: + llvm_unreachable("Unsupported calling convention"); + case CallingConv::Fast: + case CallingConv::C: + return LowerCCCCallTo(Chain, Callee, CallConv, isVarArg, isTailCall, + Outs, OutVals, Ins, dl, DAG, InVals); + } +} + +/// LowerCCCArguments - transform physical registers into virtual registers and +/// generate load operations for arguments places on the stack. +// FIXME: struct return stuff +// FIXME: varargs +SDValue +SystemZTargetLowering::LowerCCCArguments(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl<ISD::InputArg> + &Ins, + DebugLoc dl, + SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) + const { + + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + + // Assign locations to all of the incoming arguments. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), + getTargetMachine(), ArgLocs, *DAG.getContext()); + CCInfo.AnalyzeFormalArguments(Ins, CC_SystemZ); + + if (isVarArg) + report_fatal_error("Varargs not supported yet"); + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + SDValue ArgValue; + CCValAssign &VA = ArgLocs[i]; + EVT LocVT = VA.getLocVT(); + if (VA.isRegLoc()) { + // Arguments passed in registers + TargetRegisterClass *RC; + switch (LocVT.getSimpleVT().SimpleTy) { + default: +#ifndef NDEBUG + errs() << "LowerFormalArguments Unhandled argument type: " + << LocVT.getSimpleVT().SimpleTy + << "\n"; +#endif + llvm_unreachable(0); + case MVT::i64: + RC = SystemZ::GR64RegisterClass; + break; + case MVT::f32: + RC = SystemZ::FP32RegisterClass; + break; + case MVT::f64: + RC = SystemZ::FP64RegisterClass; + break; + } + + unsigned VReg = RegInfo.createVirtualRegister(RC); + RegInfo.addLiveIn(VA.getLocReg(), VReg); + ArgValue = DAG.getCopyFromReg(Chain, dl, VReg, LocVT); + } else { + // Sanity check + assert(VA.isMemLoc()); + + // Create the nodes corresponding to a load from this parameter slot. + // Create the frame index object for this incoming parameter... + int FI = MFI->CreateFixedObject(LocVT.getSizeInBits()/8, + VA.getLocMemOffset(), true); + + // Create the SelectionDAG nodes corresponding to a load + // from this parameter + SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); + ArgValue = DAG.getLoad(LocVT, dl, Chain, FIN, + MachinePointerInfo::getFixedStack(FI), + false, false, 0); + } + + // If this is an 8/16/32-bit value, it is really passed promoted to 64 + // bits. Insert an assert[sz]ext to capture this, then truncate to the + // right size. + if (VA.getLocInfo() == CCValAssign::SExt) + ArgValue = DAG.getNode(ISD::AssertSext, dl, LocVT, ArgValue, + DAG.getValueType(VA.getValVT())); + else if (VA.getLocInfo() == CCValAssign::ZExt) + ArgValue = DAG.getNode(ISD::AssertZext, dl, LocVT, ArgValue, + DAG.getValueType(VA.getValVT())); + + if (VA.getLocInfo() != CCValAssign::Full) + ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); + + InVals.push_back(ArgValue); + } + + return Chain; +} + +/// LowerCCCCallTo - functions arguments are copied from virtual regs to +/// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. +/// TODO: sret. +SDValue +SystemZTargetLowering::LowerCCCCallTo(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool isVarArg, + bool isTailCall, + const SmallVectorImpl<ISD::OutputArg> + &Outs, + const SmallVectorImpl<SDValue> &OutVals, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + MachineFunction &MF = DAG.getMachineFunction(); + const TargetFrameLowering *TFI = TM.getFrameLowering(); + + // Offset to first argument stack slot. + const unsigned FirstArgOffset = 160; + + // Analyze operands of the call, assigning locations to each operand. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), + getTargetMachine(), ArgLocs, *DAG.getContext()); + + CCInfo.AnalyzeCallOperands(Outs, CC_SystemZ); + + // Get a count of how many bytes are to be pushed on the stack. + unsigned NumBytes = CCInfo.getNextStackOffset(); + + Chain = DAG.getCALLSEQ_START(Chain ,DAG.getConstant(NumBytes, + getPointerTy(), true)); + + SmallVector<std::pair<unsigned, SDValue>, 4> RegsToPass; + SmallVector<SDValue, 12> MemOpChains; + SDValue StackPtr; + + // Walk the register/memloc assignments, inserting copies/loads. + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + + SDValue Arg = OutVals[i]; + + // Promote the value if needed. + switch (VA.getLocInfo()) { + default: assert(0 && "Unknown loc info!"); + case CCValAssign::Full: break; + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg); + break; + case CCValAssign::AExt: + Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg); + break; + } + + // Arguments that can be passed on register must be kept at RegsToPass + // vector + if (VA.isRegLoc()) { + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); + } else { + assert(VA.isMemLoc()); + + if (StackPtr.getNode() == 0) + StackPtr = + DAG.getCopyFromReg(Chain, dl, + (TFI->hasFP(MF) ? + SystemZ::R11D : SystemZ::R15D), + getPointerTy()); + + unsigned Offset = FirstArgOffset + VA.getLocMemOffset(); + SDValue PtrOff = DAG.getNode(ISD::ADD, dl, getPointerTy(), + StackPtr, + DAG.getIntPtrConstant(Offset)); + + MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, + MachinePointerInfo(), + false, false, 0)); + } + } + + // Transform all store nodes into one single node because all store nodes are + // independent of each other. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + &MemOpChains[0], MemOpChains.size()); + + // Build a sequence of copy-to-reg nodes chained together with token chain and + // flag operands which copy the outgoing args into registers. The InFlag in + // necessary since all emitted instructions must be stuck together. + SDValue InFlag; + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { + Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first, + RegsToPass[i].second, InFlag); + InFlag = Chain.getValue(1); + } + + // If the callee is a GlobalAddress node (quite common, every direct call is) + // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. + // Likewise ExternalSymbol -> TargetExternalSymbol. + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, getPointerTy()); + else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) + Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy()); + + // Returns a chain & a flag for retval copy to use. + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + SmallVector<SDValue, 8> Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + + // Add argument registers to the end of the list so that they are + // known live into the call. + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) + Ops.push_back(DAG.getRegister(RegsToPass[i].first, + RegsToPass[i].second.getValueType())); + + if (InFlag.getNode()) + Ops.push_back(InFlag); + + Chain = DAG.getNode(SystemZISD::CALL, dl, NodeTys, &Ops[0], Ops.size()); + InFlag = Chain.getValue(1); + + // Create the CALLSEQ_END node. + Chain = DAG.getCALLSEQ_END(Chain, + DAG.getConstant(NumBytes, getPointerTy(), true), + DAG.getConstant(0, getPointerTy(), true), + InFlag); + InFlag = Chain.getValue(1); + + // Handle result values, copying them out of physregs into vregs that we + // return. + return LowerCallResult(Chain, InFlag, CallConv, isVarArg, Ins, dl, + DAG, InVals); +} + +/// LowerCallResult - Lower the result values of a call into the +/// appropriate copies out of appropriate physical registers. +/// +SDValue +SystemZTargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> + &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + + // Assign locations to each value returned by this call. + SmallVector<CCValAssign, 16> RVLocs; + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), + getTargetMachine(), RVLocs, *DAG.getContext()); + + CCInfo.AnalyzeCallResult(Ins, RetCC_SystemZ); + + // Copy all of the result registers out of their specified physreg. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + CCValAssign &VA = RVLocs[i]; + + Chain = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), + VA.getLocVT(), InFlag).getValue(1); + SDValue RetValue = Chain.getValue(0); + InFlag = Chain.getValue(2); + + // If this is an 8/16/32-bit value, it is really passed promoted to 64 + // bits. Insert an assert[sz]ext to capture this, then truncate to the + // right size. + if (VA.getLocInfo() == CCValAssign::SExt) + RetValue = DAG.getNode(ISD::AssertSext, dl, VA.getLocVT(), RetValue, + DAG.getValueType(VA.getValVT())); + else if (VA.getLocInfo() == CCValAssign::ZExt) + RetValue = DAG.getNode(ISD::AssertZext, dl, VA.getLocVT(), RetValue, + DAG.getValueType(VA.getValVT())); + + if (VA.getLocInfo() != CCValAssign::Full) + RetValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), RetValue); + + InVals.push_back(RetValue); + } + + return Chain; +} + + +SDValue +SystemZTargetLowering::LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + DebugLoc dl, SelectionDAG &DAG) const { + + // CCValAssign - represent the assignment of the return value to a location + SmallVector<CCValAssign, 16> RVLocs; + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), + getTargetMachine(), RVLocs, *DAG.getContext()); + + // Analize return values. + CCInfo.AnalyzeReturn(Outs, RetCC_SystemZ); + + // If this is the first return lowered for this function, add the regs to the + // liveout set for the function. + if (DAG.getMachineFunction().getRegInfo().liveout_empty()) { + for (unsigned i = 0; i != RVLocs.size(); ++i) + if (RVLocs[i].isRegLoc()) + DAG.getMachineFunction().getRegInfo().addLiveOut(RVLocs[i].getLocReg()); + } + + SDValue Flag; + + // Copy the result values into the output registers. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + CCValAssign &VA = RVLocs[i]; + SDValue ResValue = OutVals[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + + // If this is an 8/16/32-bit value, it is really should be passed promoted + // to 64 bits. + if (VA.getLocInfo() == CCValAssign::SExt) + ResValue = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), ResValue); + else if (VA.getLocInfo() == CCValAssign::ZExt) + ResValue = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), ResValue); + else if (VA.getLocInfo() == CCValAssign::AExt) + ResValue = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), ResValue); + + Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), ResValue, Flag); + + // Guarantee that all emitted copies are stuck together, + // avoiding something bad. + Flag = Chain.getValue(1); + } + + if (Flag.getNode()) + return DAG.getNode(SystemZISD::RET_FLAG, dl, MVT::Other, Chain, Flag); + + // Return Void + return DAG.getNode(SystemZISD::RET_FLAG, dl, MVT::Other, Chain); +} + +SDValue SystemZTargetLowering::EmitCmp(SDValue LHS, SDValue RHS, + ISD::CondCode CC, SDValue &SystemZCC, + SelectionDAG &DAG) const { + // FIXME: Emit a test if RHS is zero + + bool isUnsigned = false; + SystemZCC::CondCodes TCC; + switch (CC) { + default: + llvm_unreachable("Invalid integer condition!"); + case ISD::SETEQ: + case ISD::SETOEQ: + TCC = SystemZCC::E; + break; + case ISD::SETUEQ: + TCC = SystemZCC::NLH; + break; + case ISD::SETNE: + case ISD::SETONE: + TCC = SystemZCC::NE; + break; + case ISD::SETUNE: + TCC = SystemZCC::LH; + break; + case ISD::SETO: + TCC = SystemZCC::O; + break; + case ISD::SETUO: + TCC = SystemZCC::NO; + break; + case ISD::SETULE: + if (LHS.getValueType().isFloatingPoint()) { + TCC = SystemZCC::NH; + break; + } + isUnsigned = true; // FALLTHROUGH + case ISD::SETLE: + case ISD::SETOLE: + TCC = SystemZCC::LE; + break; + case ISD::SETUGE: + if (LHS.getValueType().isFloatingPoint()) { + TCC = SystemZCC::NL; + break; + } + isUnsigned = true; // FALLTHROUGH + case ISD::SETGE: + case ISD::SETOGE: + TCC = SystemZCC::HE; + break; + case ISD::SETUGT: + if (LHS.getValueType().isFloatingPoint()) { + TCC = SystemZCC::NLE; + break; + } + isUnsigned = true; // FALLTHROUGH + case ISD::SETGT: + case ISD::SETOGT: + TCC = SystemZCC::H; + break; + case ISD::SETULT: + if (LHS.getValueType().isFloatingPoint()) { + TCC = SystemZCC::NHE; + break; + } + isUnsigned = true; // FALLTHROUGH + case ISD::SETLT: + case ISD::SETOLT: + TCC = SystemZCC::L; + break; + } + + SystemZCC = DAG.getConstant(TCC, MVT::i32); + + DebugLoc dl = LHS.getDebugLoc(); + return DAG.getNode((isUnsigned ? SystemZISD::UCMP : SystemZISD::CMP), + dl, MVT::i64, LHS, RHS); +} + + +SDValue SystemZTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get(); + SDValue LHS = Op.getOperand(2); + SDValue RHS = Op.getOperand(3); + SDValue Dest = Op.getOperand(4); + DebugLoc dl = Op.getDebugLoc(); + + SDValue SystemZCC; + SDValue Flag = EmitCmp(LHS, RHS, CC, SystemZCC, DAG); + return DAG.getNode(SystemZISD::BRCOND, dl, Op.getValueType(), + Chain, Dest, SystemZCC, Flag); +} + +SDValue SystemZTargetLowering::LowerSELECT_CC(SDValue Op, + SelectionDAG &DAG) const { + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + SDValue TrueV = Op.getOperand(2); + SDValue FalseV = Op.getOperand(3); + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get(); + DebugLoc dl = Op.getDebugLoc(); + + SDValue SystemZCC; + SDValue Flag = EmitCmp(LHS, RHS, CC, SystemZCC, DAG); + + SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue); + SmallVector<SDValue, 4> Ops; + Ops.push_back(TrueV); + Ops.push_back(FalseV); + Ops.push_back(SystemZCC); + Ops.push_back(Flag); + + return DAG.getNode(SystemZISD::SELECT, dl, VTs, &Ops[0], Ops.size()); +} + +SDValue SystemZTargetLowering::LowerGlobalAddress(SDValue Op, + SelectionDAG &DAG) const { + DebugLoc dl = Op.getDebugLoc(); + const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); + int64_t Offset = cast<GlobalAddressSDNode>(Op)->getOffset(); + + bool IsPic = getTargetMachine().getRelocationModel() == Reloc::PIC_; + bool ExtraLoadRequired = + Subtarget.GVRequiresExtraLoad(GV, getTargetMachine(), false); + + SDValue Result; + if (!IsPic && !ExtraLoadRequired) { + Result = DAG.getTargetGlobalAddress(GV, dl, getPointerTy(), Offset); + Offset = 0; + } else { + unsigned char OpFlags = 0; + if (ExtraLoadRequired) + OpFlags = SystemZII::MO_GOTENT; + + Result = DAG.getTargetGlobalAddress(GV, dl, getPointerTy(), 0, OpFlags); + } + + Result = DAG.getNode(SystemZISD::PCRelativeWrapper, dl, + getPointerTy(), Result); + + if (ExtraLoadRequired) + Result = DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), Result, + MachinePointerInfo::getGOT(), false, false, 0); + + // If there was a non-zero offset that we didn't fold, create an explicit + // addition for it. + if (Offset != 0) + Result = DAG.getNode(ISD::ADD, dl, getPointerTy(), Result, + DAG.getConstant(Offset, getPointerTy())); + + return Result; +} + +// FIXME: PIC here +SDValue SystemZTargetLowering::LowerJumpTable(SDValue Op, + SelectionDAG &DAG) const { + DebugLoc dl = Op.getDebugLoc(); + JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); + SDValue Result = DAG.getTargetJumpTable(JT->getIndex(), getPointerTy()); + + return DAG.getNode(SystemZISD::PCRelativeWrapper, dl, getPointerTy(), Result); +} + + +// FIXME: PIC here +// FIXME: This is just dirty hack. We need to lower cpool properly +SDValue SystemZTargetLowering::LowerConstantPool(SDValue Op, + SelectionDAG &DAG) const { + DebugLoc dl = Op.getDebugLoc(); + ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op); + + SDValue Result = DAG.getTargetConstantPool(CP->getConstVal(), getPointerTy(), + CP->getAlignment(), + CP->getOffset()); + + return DAG.getNode(SystemZISD::PCRelativeWrapper, dl, getPointerTy(), Result); +} + +const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + case SystemZISD::RET_FLAG: return "SystemZISD::RET_FLAG"; + case SystemZISD::CALL: return "SystemZISD::CALL"; + case SystemZISD::BRCOND: return "SystemZISD::BRCOND"; + case SystemZISD::CMP: return "SystemZISD::CMP"; + case SystemZISD::UCMP: return "SystemZISD::UCMP"; + case SystemZISD::SELECT: return "SystemZISD::SELECT"; + case SystemZISD::PCRelativeWrapper: return "SystemZISD::PCRelativeWrapper"; + default: return NULL; + } +} + +//===----------------------------------------------------------------------===// +// Other Lowering Code +//===----------------------------------------------------------------------===// + +MachineBasicBlock* +SystemZTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const { + const SystemZInstrInfo &TII = *TM.getInstrInfo(); + DebugLoc dl = MI->getDebugLoc(); + assert((MI->getOpcode() == SystemZ::Select32 || + MI->getOpcode() == SystemZ::SelectF32 || + MI->getOpcode() == SystemZ::Select64 || + MI->getOpcode() == SystemZ::SelectF64) && + "Unexpected instr type to insert"); + + // To "insert" a SELECT instruction, we actually have to insert the diamond + // control-flow pattern. The incoming instruction knows the destination vreg + // to set, the condition code register to branch on, the true/false values to + // select between, and a branch opcode to use. + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator I = BB; + ++I; + + // thisMBB: + // ... + // TrueVal = ... + // cmpTY ccX, r1, r2 + // jCC copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *copy1MBB = F->CreateMachineBasicBlock(LLVM_BB); + SystemZCC::CondCodes CC = (SystemZCC::CondCodes)MI->getOperand(3).getImm(); + F->insert(I, copy0MBB); + F->insert(I, copy1MBB); + // Update machine-CFG edges by transferring all successors of the current + // block to the new block which will contain the Phi node for the select. + copy1MBB->splice(copy1MBB->begin(), BB, + llvm::next(MachineBasicBlock::iterator(MI)), + BB->end()); + copy1MBB->transferSuccessorsAndUpdatePHIs(BB); + // Next, add the true and fallthrough blocks as its successors. + BB->addSuccessor(copy0MBB); + BB->addSuccessor(copy1MBB); + + BuildMI(BB, dl, TII.getBrCond(CC)).addMBB(copy1MBB); + + // copy0MBB: + // %FalseValue = ... + // # fallthrough to copy1MBB + BB = copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(copy1MBB); + + // copy1MBB: + // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] + // ... + BB = copy1MBB; + BuildMI(*BB, BB->begin(), dl, TII.get(SystemZ::PHI), + MI->getOperand(0).getReg()) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB) + .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.h new file mode 100644 index 0000000..bab3dc2 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -0,0 +1,145 @@ +//==-- SystemZISelLowering.h - SystemZ DAG Lowering Interface ----*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that SystemZ uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_SystemZ_ISELLOWERING_H +#define LLVM_TARGET_SystemZ_ISELLOWERING_H + +#include "SystemZ.h" +#include "SystemZRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/Target/TargetLowering.h" + +namespace llvm { + namespace SystemZISD { + enum { + FIRST_NUMBER = ISD::BUILTIN_OP_END, + + /// Return with a flag operand. Operand 0 is the chain operand. + RET_FLAG, + + /// CALL - These operations represent an abstract call + /// instruction, which includes a bunch of information. + CALL, + + /// PCRelativeWrapper - PC relative address + PCRelativeWrapper, + + /// CMP, UCMP - Compare instruction + CMP, + UCMP, + + /// BRCOND - Conditional branch. Operand 0 is chain operand, operand 1 is + /// the block to branch if condition is true, operand 2 is condition code + /// and operand 3 is the flag operand produced by a CMP instruction. + BRCOND, + + /// SELECT - Operands 0 and 1 are selection variables, operand 2 is + /// condition code and operand 3 is the flag operand. + SELECT + }; + } + + class SystemZSubtarget; + class SystemZTargetMachine; + + class SystemZTargetLowering : public TargetLowering { + public: + explicit SystemZTargetLowering(SystemZTargetMachine &TM); + + virtual MVT getShiftAmountTy(EVT LHSTy) const { return MVT::i64; } + + /// LowerOperation - Provide custom lowering hooks for some operations. + virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const; + + /// getTargetNodeName - This method returns the name of a target specific + /// DAG node. + virtual const char *getTargetNodeName(unsigned Opcode) const; + + std::pair<unsigned, const TargetRegisterClass*> + getRegForInlineAsmConstraint(const std::string &Constraint, EVT VT) const; + TargetLowering::ConstraintType + getConstraintType(const std::string &Constraint) const; + + SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const; + + SDValue EmitCmp(SDValue LHS, SDValue RHS, + ISD::CondCode CC, SDValue &SystemZCC, + SelectionDAG &DAG) const; + + + MachineBasicBlock* EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const; + + /// isFPImmLegal - Returns true if the target can instruction select the + /// specified FP immediate natively. If false, the legalizer will + /// materialize the FP immediate as a load from a constant pool. + virtual bool isFPImmLegal(const APFloat &Imm, EVT VT) const; + + private: + SDValue LowerCCCCallTo(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool isVarArg, + bool isTailCall, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + SDValue LowerCCCArguments(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, + SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + SDValue LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + virtual SDValue + LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + virtual SDValue + LowerCall(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool isVarArg, bool &isTailCall, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + virtual SDValue + LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + DebugLoc dl, SelectionDAG &DAG) const; + + const SystemZSubtarget &Subtarget; + const SystemZTargetMachine &TM; + const SystemZRegisterInfo *RegInfo; + }; +} // namespace llvm + +#endif // LLVM_TARGET_SystemZ_ISELLOWERING_H diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZInstrBuilder.h b/contrib/llvm/lib/Target/SystemZ/SystemZInstrBuilder.h new file mode 100644 index 0000000..ab45ec5 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZInstrBuilder.h @@ -0,0 +1,128 @@ +//===- SystemZInstrBuilder.h - Functions to aid building insts -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file exposes functions that may be used with BuildMI from the +// MachineInstrBuilder.h file to handle SystemZ'isms in a clean way. +// +// The BuildMem function may be used with the BuildMI function to add entire +// memory references in a single, typed, function call. +// +// For reference, the order of operands for memory references is: +// (Operand), Base, Displacement, Index. +// +//===----------------------------------------------------------------------===// + +#ifndef SYSTEMZINSTRBUILDER_H +#define SYSTEMZINSTRBUILDER_H + +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/CodeGen/PseudoSourceValue.h" + +namespace llvm { + +/// SystemZAddressMode - This struct holds a generalized full x86 address mode. +/// The base register can be a frame index, which will eventually be replaced +/// with R15 or R11 and Disp being offsetted accordingly. +struct SystemZAddressMode { + enum { + RegBase, + FrameIndexBase + } BaseType; + + union { + unsigned Reg; + int FrameIndex; + } Base; + + unsigned IndexReg; + int32_t Disp; + const GlobalValue *GV; + + SystemZAddressMode() : BaseType(RegBase), IndexReg(0), Disp(0) { + Base.Reg = 0; + } +}; + +/// addDirectMem - This function is used to add a direct memory reference to the +/// current instruction -- that is, a dereference of an address in a register, +/// with no index or displacement. +/// +static inline const MachineInstrBuilder & +addDirectMem(const MachineInstrBuilder &MIB, unsigned Reg) { + // Because memory references are always represented with 3 + // values, this adds: Reg, [0, NoReg] to the instruction. + return MIB.addReg(Reg).addImm(0).addReg(0); +} + +static inline const MachineInstrBuilder & +addOffset(const MachineInstrBuilder &MIB, int Offset) { + return MIB.addImm(Offset).addReg(0); +} + +/// addRegOffset - This function is used to add a memory reference of the form +/// [Reg + Offset], i.e., one with no or index, but with a +/// displacement. An example is: 10(%r15). +/// +static inline const MachineInstrBuilder & +addRegOffset(const MachineInstrBuilder &MIB, + unsigned Reg, bool isKill, int Offset) { + return addOffset(MIB.addReg(Reg, getKillRegState(isKill)), Offset); +} + +/// addRegReg - This function is used to add a memory reference of the form: +/// [Reg + Reg]. +static inline const MachineInstrBuilder & +addRegReg(const MachineInstrBuilder &MIB, + unsigned Reg1, bool isKill1, unsigned Reg2, bool isKill2) { + return MIB.addReg(Reg1, getKillRegState(isKill1)).addImm(0) + .addReg(Reg2, getKillRegState(isKill2)); +} + +static inline const MachineInstrBuilder & +addFullAddress(const MachineInstrBuilder &MIB, const SystemZAddressMode &AM) { + if (AM.BaseType == SystemZAddressMode::RegBase) + MIB.addReg(AM.Base.Reg); + else if (AM.BaseType == SystemZAddressMode::FrameIndexBase) + MIB.addFrameIndex(AM.Base.FrameIndex); + else + assert(0); + + return MIB.addImm(AM.Disp).addReg(AM.IndexReg); +} + +/// addFrameReference - This function is used to add a reference to the base of +/// an abstract object on the stack frame of the current function. This +/// reference has base register as the FrameIndex offset until it is resolved. +/// This allows a constant offset to be specified as well... +/// +static inline const MachineInstrBuilder & +addFrameReference(const MachineInstrBuilder &MIB, int FI, int Offset = 0) { + MachineInstr *MI = MIB; + MachineFunction &MF = *MI->getParent()->getParent(); + MachineFrameInfo &MFI = *MF.getFrameInfo(); + const MCInstrDesc &MCID = MI->getDesc(); + unsigned Flags = 0; + if (MCID.mayLoad()) + Flags |= MachineMemOperand::MOLoad; + if (MCID.mayStore()) + Flags |= MachineMemOperand::MOStore; + MachineMemOperand *MMO = + MF.getMachineMemOperand(MachinePointerInfo( + PseudoSourceValue::getFixedStack(FI), Offset), + Flags, MFI.getObjectSize(FI), + MFI.getObjectAlignment(FI)); + return addOffset(MIB.addFrameIndex(FI), Offset) + .addMemOperand(MMO); +} + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZInstrFP.td b/contrib/llvm/lib/Target/SystemZ/SystemZInstrFP.td new file mode 100644 index 0000000..a658280 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZInstrFP.td @@ -0,0 +1,340 @@ +//===- SystemZInstrFP.td - SystemZ FP Instruction defs --------*- tblgen-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the SystemZ (binary) floating point instructions in +// TableGen format. +// +//===----------------------------------------------------------------------===// + +// FIXME: multiclassify! + +//===----------------------------------------------------------------------===// +// FP Pattern fragments + +def fpimm0 : PatLeaf<(fpimm), [{ + return N->isExactlyValue(+0.0); +}]>; + +def fpimmneg0 : PatLeaf<(fpimm), [{ + return N->isExactlyValue(-0.0); +}]>; + +let Uses = [PSW], usesCustomInserter = 1 in { + def SelectF32 : Pseudo<(outs FP32:$dst), (ins FP32:$src1, FP32:$src2, i8imm:$cc), + "# SelectF32 PSEUDO", + [(set FP32:$dst, + (SystemZselect FP32:$src1, FP32:$src2, imm:$cc, PSW))]>; + def SelectF64 : Pseudo<(outs FP64:$dst), (ins FP64:$src1, FP64:$src2, i8imm:$cc), + "# SelectF64 PSEUDO", + [(set FP64:$dst, + (SystemZselect FP64:$src1, FP64:$src2, imm:$cc, PSW))]>; +} + +//===----------------------------------------------------------------------===// +// Move Instructions + +// Floating point constant loads. +let isReMaterializable = 1, isAsCheapAsAMove = 1 in { +def LD_Fp032 : Pseudo<(outs FP32:$dst), (ins), + "lzer\t{$dst}", + [(set FP32:$dst, fpimm0)]>; +def LD_Fp064 : Pseudo<(outs FP64:$dst), (ins), + "lzdr\t{$dst}", + [(set FP64:$dst, fpimm0)]>; +} + +let neverHasSideEffects = 1 in { +def FMOV32rr : Pseudo<(outs FP32:$dst), (ins FP32:$src), + "ler\t{$dst, $src}", + []>; +def FMOV64rr : Pseudo<(outs FP64:$dst), (ins FP64:$src), + "ldr\t{$dst, $src}", + []>; +} + +let canFoldAsLoad = 1, isReMaterializable = 1 in { +def FMOV32rm : Pseudo<(outs FP32:$dst), (ins rriaddr12:$src), + "le\t{$dst, $src}", + [(set FP32:$dst, (load rriaddr12:$src))]>; +def FMOV32rmy : Pseudo<(outs FP32:$dst), (ins rriaddr:$src), + "ley\t{$dst, $src}", + [(set FP32:$dst, (load rriaddr:$src))]>; +def FMOV64rm : Pseudo<(outs FP64:$dst), (ins rriaddr12:$src), + "ld\t{$dst, $src}", + [(set FP64:$dst, (load rriaddr12:$src))]>; +def FMOV64rmy : Pseudo<(outs FP64:$dst), (ins rriaddr:$src), + "ldy\t{$dst, $src}", + [(set FP64:$dst, (load rriaddr:$src))]>; +} + +def FMOV32mr : Pseudo<(outs), (ins rriaddr12:$dst, FP32:$src), + "ste\t{$src, $dst}", + [(store FP32:$src, rriaddr12:$dst)]>; +def FMOV32mry : Pseudo<(outs), (ins rriaddr:$dst, FP32:$src), + "stey\t{$src, $dst}", + [(store FP32:$src, rriaddr:$dst)]>; +def FMOV64mr : Pseudo<(outs), (ins rriaddr12:$dst, FP64:$src), + "std\t{$src, $dst}", + [(store FP64:$src, rriaddr12:$dst)]>; +def FMOV64mry : Pseudo<(outs), (ins rriaddr:$dst, FP64:$src), + "stdy\t{$src, $dst}", + [(store FP64:$src, rriaddr:$dst)]>; + +def FCOPYSIGN32 : Pseudo<(outs FP32:$dst), (ins FP32:$src1, FP32:$src2), + "cpsdr\t{$dst, $src2, $src1}", + [(set FP32:$dst, (fcopysign FP32:$src1, FP32:$src2))]>; +def FCOPYSIGN64 : Pseudo<(outs FP64:$dst), (ins FP64:$src1, FP64:$src2), + "cpsdr\t{$dst, $src2, $src1}", + [(set FP64:$dst, (fcopysign FP64:$src1, FP64:$src2))]>; + +//===----------------------------------------------------------------------===// +// Arithmetic Instructions + + +let Defs = [PSW] in { +def FNEG32rr : Pseudo<(outs FP32:$dst), (ins FP32:$src), + "lcebr\t{$dst, $src}", + [(set FP32:$dst, (fneg FP32:$src)), + (implicit PSW)]>; +def FNEG64rr : Pseudo<(outs FP64:$dst), (ins FP64:$src), + "lcdbr\t{$dst, $src}", + [(set FP64:$dst, (fneg FP64:$src)), + (implicit PSW)]>; + +def FABS32rr : Pseudo<(outs FP32:$dst), (ins FP32:$src), + "lpebr\t{$dst, $src}", + [(set FP32:$dst, (fabs FP32:$src)), + (implicit PSW)]>; +def FABS64rr : Pseudo<(outs FP64:$dst), (ins FP64:$src), + "lpdbr\t{$dst, $src}", + [(set FP64:$dst, (fabs FP64:$src)), + (implicit PSW)]>; + +def FNABS32rr : Pseudo<(outs FP32:$dst), (ins FP32:$src), + "lnebr\t{$dst, $src}", + [(set FP32:$dst, (fneg(fabs FP32:$src))), + (implicit PSW)]>; +def FNABS64rr : Pseudo<(outs FP64:$dst), (ins FP64:$src), + "lndbr\t{$dst, $src}", + [(set FP64:$dst, (fneg(fabs FP64:$src))), + (implicit PSW)]>; +} + +let Constraints = "$src1 = $dst" in { +let Defs = [PSW] in { +let isCommutable = 1 in { // X = ADD Y, Z == X = ADD Z, Y +def FADD32rr : Pseudo<(outs FP32:$dst), (ins FP32:$src1, FP32:$src2), + "aebr\t{$dst, $src2}", + [(set FP32:$dst, (fadd FP32:$src1, FP32:$src2)), + (implicit PSW)]>; +def FADD64rr : Pseudo<(outs FP64:$dst), (ins FP64:$src1, FP64:$src2), + "adbr\t{$dst, $src2}", + [(set FP64:$dst, (fadd FP64:$src1, FP64:$src2)), + (implicit PSW)]>; +} + +def FADD32rm : Pseudo<(outs FP32:$dst), (ins FP32:$src1, rriaddr12:$src2), + "aeb\t{$dst, $src2}", + [(set FP32:$dst, (fadd FP32:$src1, (load rriaddr12:$src2))), + (implicit PSW)]>; +def FADD64rm : Pseudo<(outs FP64:$dst), (ins FP64:$src1, rriaddr12:$src2), + "adb\t{$dst, $src2}", + [(set FP64:$dst, (fadd FP64:$src1, (load rriaddr12:$src2))), + (implicit PSW)]>; + +def FSUB32rr : Pseudo<(outs FP32:$dst), (ins FP32:$src1, FP32:$src2), + "sebr\t{$dst, $src2}", + [(set FP32:$dst, (fsub FP32:$src1, FP32:$src2)), + (implicit PSW)]>; +def FSUB64rr : Pseudo<(outs FP64:$dst), (ins FP64:$src1, FP64:$src2), + "sdbr\t{$dst, $src2}", + [(set FP64:$dst, (fsub FP64:$src1, FP64:$src2)), + (implicit PSW)]>; + +def FSUB32rm : Pseudo<(outs FP32:$dst), (ins FP32:$src1, rriaddr12:$src2), + "seb\t{$dst, $src2}", + [(set FP32:$dst, (fsub FP32:$src1, (load rriaddr12:$src2))), + (implicit PSW)]>; +def FSUB64rm : Pseudo<(outs FP64:$dst), (ins FP64:$src1, rriaddr12:$src2), + "sdb\t{$dst, $src2}", + [(set FP64:$dst, (fsub FP64:$src1, (load rriaddr12:$src2))), + (implicit PSW)]>; +} // Defs = [PSW] + +let isCommutable = 1 in { // X = MUL Y, Z == X = MUL Z, Y +def FMUL32rr : Pseudo<(outs FP32:$dst), (ins FP32:$src1, FP32:$src2), + "meebr\t{$dst, $src2}", + [(set FP32:$dst, (fmul FP32:$src1, FP32:$src2))]>; +def FMUL64rr : Pseudo<(outs FP64:$dst), (ins FP64:$src1, FP64:$src2), + "mdbr\t{$dst, $src2}", + [(set FP64:$dst, (fmul FP64:$src1, FP64:$src2))]>; +} + +def FMUL32rm : Pseudo<(outs FP32:$dst), (ins FP32:$src1, rriaddr12:$src2), + "meeb\t{$dst, $src2}", + [(set FP32:$dst, (fmul FP32:$src1, (load rriaddr12:$src2)))]>; +def FMUL64rm : Pseudo<(outs FP64:$dst), (ins FP64:$src1, rriaddr12:$src2), + "mdb\t{$dst, $src2}", + [(set FP64:$dst, (fmul FP64:$src1, (load rriaddr12:$src2)))]>; + +def FMADD32rr : Pseudo<(outs FP32:$dst), (ins FP32:$src1, FP32:$src2, FP32:$src3), + "maebr\t{$dst, $src3, $src2}", + [(set FP32:$dst, (fadd (fmul FP32:$src2, FP32:$src3), + FP32:$src1))]>; +def FMADD32rm : Pseudo<(outs FP32:$dst), (ins FP32:$src1, rriaddr12:$src2, FP32:$src3), + "maeb\t{$dst, $src3, $src2}", + [(set FP32:$dst, (fadd (fmul (load rriaddr12:$src2), + FP32:$src3), + FP32:$src1))]>; + +def FMADD64rr : Pseudo<(outs FP64:$dst), (ins FP64:$src1, FP64:$src2, FP64:$src3), + "madbr\t{$dst, $src3, $src2}", + [(set FP64:$dst, (fadd (fmul FP64:$src2, FP64:$src3), + FP64:$src1))]>; +def FMADD64rm : Pseudo<(outs FP64:$dst), (ins FP64:$src1, rriaddr12:$src2, FP64:$src3), + "madb\t{$dst, $src3, $src2}", + [(set FP64:$dst, (fadd (fmul (load rriaddr12:$src2), + FP64:$src3), + FP64:$src1))]>; + +def FMSUB32rr : Pseudo<(outs FP32:$dst), (ins FP32:$src1, FP32:$src2, FP32:$src3), + "msebr\t{$dst, $src3, $src2}", + [(set FP32:$dst, (fsub (fmul FP32:$src2, FP32:$src3), + FP32:$src1))]>; +def FMSUB32rm : Pseudo<(outs FP32:$dst), (ins FP32:$src1, rriaddr12:$src2, FP32:$src3), + "mseb\t{$dst, $src3, $src2}", + [(set FP32:$dst, (fsub (fmul (load rriaddr12:$src2), + FP32:$src3), + FP32:$src1))]>; + +def FMSUB64rr : Pseudo<(outs FP64:$dst), (ins FP64:$src1, FP64:$src2, FP64:$src3), + "msdbr\t{$dst, $src3, $src2}", + [(set FP64:$dst, (fsub (fmul FP64:$src2, FP64:$src3), + FP64:$src1))]>; +def FMSUB64rm : Pseudo<(outs FP64:$dst), (ins FP64:$src1, rriaddr12:$src2, FP64:$src3), + "msdb\t{$dst, $src3, $src2}", + [(set FP64:$dst, (fsub (fmul (load rriaddr12:$src2), + FP64:$src3), + FP64:$src1))]>; + +def FDIV32rr : Pseudo<(outs FP32:$dst), (ins FP32:$src1, FP32:$src2), + "debr\t{$dst, $src2}", + [(set FP32:$dst, (fdiv FP32:$src1, FP32:$src2))]>; +def FDIV64rr : Pseudo<(outs FP64:$dst), (ins FP64:$src1, FP64:$src2), + "ddbr\t{$dst, $src2}", + [(set FP64:$dst, (fdiv FP64:$src1, FP64:$src2))]>; + +def FDIV32rm : Pseudo<(outs FP32:$dst), (ins FP32:$src1, rriaddr12:$src2), + "deb\t{$dst, $src2}", + [(set FP32:$dst, (fdiv FP32:$src1, (load rriaddr12:$src2)))]>; +def FDIV64rm : Pseudo<(outs FP64:$dst), (ins FP64:$src1, rriaddr12:$src2), + "ddb\t{$dst, $src2}", + [(set FP64:$dst, (fdiv FP64:$src1, (load rriaddr12:$src2)))]>; + +} // Constraints = "$src1 = $dst" + +def FSQRT32rr : Pseudo<(outs FP32:$dst), (ins FP32:$src), + "sqebr\t{$dst, $src}", + [(set FP32:$dst, (fsqrt FP32:$src))]>; +def FSQRT64rr : Pseudo<(outs FP64:$dst), (ins FP64:$src), + "sqdbr\t{$dst, $src}", + [(set FP64:$dst, (fsqrt FP64:$src))]>; + +def FSQRT32rm : Pseudo<(outs FP32:$dst), (ins rriaddr12:$src), + "sqeb\t{$dst, $src}", + [(set FP32:$dst, (fsqrt (load rriaddr12:$src)))]>; +def FSQRT64rm : Pseudo<(outs FP64:$dst), (ins rriaddr12:$src), + "sqdb\t{$dst, $src}", + [(set FP64:$dst, (fsqrt (load rriaddr12:$src)))]>; + +def FROUND64r32 : Pseudo<(outs FP32:$dst), (ins FP64:$src), + "ledbr\t{$dst, $src}", + [(set FP32:$dst, (fround FP64:$src))]>; + +def FEXT32r64 : Pseudo<(outs FP64:$dst), (ins FP32:$src), + "ldebr\t{$dst, $src}", + [(set FP64:$dst, (fextend FP32:$src))]>; +def FEXT32m64 : Pseudo<(outs FP64:$dst), (ins rriaddr12:$src), + "ldeb\t{$dst, $src}", + [(set FP64:$dst, (fextend (load rriaddr12:$src)))]>; + +let Defs = [PSW] in { +def FCONVFP32 : Pseudo<(outs FP32:$dst), (ins GR32:$src), + "cefbr\t{$dst, $src}", + [(set FP32:$dst, (sint_to_fp GR32:$src)), + (implicit PSW)]>; +def FCONVFP32r64: Pseudo<(outs FP32:$dst), (ins GR64:$src), + "cegbr\t{$dst, $src}", + [(set FP32:$dst, (sint_to_fp GR64:$src)), + (implicit PSW)]>; + +def FCONVFP64r32: Pseudo<(outs FP64:$dst), (ins GR32:$src), + "cdfbr\t{$dst, $src}", + [(set FP64:$dst, (sint_to_fp GR32:$src)), + (implicit PSW)]>; +def FCONVFP64 : Pseudo<(outs FP64:$dst), (ins GR64:$src), + "cdgbr\t{$dst, $src}", + [(set FP64:$dst, (sint_to_fp GR64:$src)), + (implicit PSW)]>; + +def FCONVGR32 : Pseudo<(outs GR32:$dst), (ins FP32:$src), + "cfebr\t{$dst, 5, $src}", + [(set GR32:$dst, (fp_to_sint FP32:$src)), + (implicit PSW)]>; +def FCONVGR32r64: Pseudo<(outs GR32:$dst), (ins FP64:$src), + "cfdbr\t{$dst, 5, $src}", + [(set GR32:$dst, (fp_to_sint FP64:$src)), + (implicit PSW)]>; + +def FCONVGR64r32: Pseudo<(outs GR64:$dst), (ins FP32:$src), + "cgebr\t{$dst, 5, $src}", + [(set GR64:$dst, (fp_to_sint FP32:$src)), + (implicit PSW)]>; +def FCONVGR64 : Pseudo<(outs GR64:$dst), (ins FP64:$src), + "cgdbr\t{$dst, 5, $src}", + [(set GR64:$dst, (fp_to_sint FP64:$src)), + (implicit PSW)]>; +} // Defs = [PSW] + +def FBCONVG64 : Pseudo<(outs GR64:$dst), (ins FP64:$src), + "lgdr\t{$dst, $src}", + [(set GR64:$dst, (bitconvert FP64:$src))]>; +def FBCONVF64 : Pseudo<(outs FP64:$dst), (ins GR64:$src), + "ldgr\t{$dst, $src}", + [(set FP64:$dst, (bitconvert GR64:$src))]>; + +//===----------------------------------------------------------------------===// +// Test instructions (like AND but do not produce any result) + +// Integer comparisons +let Defs = [PSW] in { +def FCMP32rr : Pseudo<(outs), (ins FP32:$src1, FP32:$src2), + "cebr\t$src1, $src2", + [(set PSW, (SystemZcmp FP32:$src1, FP32:$src2))]>; +def FCMP64rr : Pseudo<(outs), (ins FP64:$src1, FP64:$src2), + "cdbr\t$src1, $src2", + [(set PSW, (SystemZcmp FP64:$src1, FP64:$src2))]>; + +def FCMP32rm : Pseudo<(outs), (ins FP32:$src1, rriaddr12:$src2), + "ceb\t$src1, $src2", + [(set PSW, (SystemZcmp FP32:$src1, + (load rriaddr12:$src2)))]>; +def FCMP64rm : Pseudo<(outs), (ins FP64:$src1, rriaddr12:$src2), + "cdb\t$src1, $src2", + [(set PSW, (SystemZcmp FP64:$src1, + (load rriaddr12:$src2)))]>; +} // Defs = [PSW] + +//===----------------------------------------------------------------------===// +// Non-Instruction Patterns +//===----------------------------------------------------------------------===// + +// Floating point constant -0.0 +def : Pat<(f32 fpimmneg0), (FNEG32rr (LD_Fp032))>; +def : Pat<(f64 fpimmneg0), (FNEG64rr (LD_Fp064))>; diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZInstrFormats.td b/contrib/llvm/lib/Target/SystemZ/SystemZInstrFormats.td new file mode 100644 index 0000000..b4a8993 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZInstrFormats.td @@ -0,0 +1,133 @@ +//===- SystemZInstrFormats.td - SystemZ Instruction Formats ----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Format specifies the encoding used by the instruction. This is part of the +// ad-hoc solution used to emit machine instruction encodings by our machine +// code emitter. +class Format<bits<5> val> { + bits<5> Value = val; +} + +def Pseudo : Format<0>; +def EForm : Format<1>; +def IForm : Format<2>; +def RIForm : Format<3>; +def RIEForm : Format<4>; +def RILForm : Format<5>; +def RISForm : Format<6>; +def RRForm : Format<7>; +def RREForm : Format<8>; +def RRFForm : Format<9>; +def RRRForm : Format<10>; +def RRSForm : Format<11>; +def RSForm : Format<12>; +def RSIForm : Format<13>; +def RSILForm : Format<14>; +def RSYForm : Format<15>; +def RXForm : Format<16>; +def RXEForm : Format<17>; +def RXFForm : Format<18>; +def RXYForm : Format<19>; +def SForm : Format<20>; +def SIForm : Format<21>; +def SILForm : Format<22>; +def SIYForm : Format<23>; +def SSForm : Format<24>; +def SSEForm : Format<25>; +def SSFForm : Format<26>; + +class InstSystemZ<bits<16> op, Format f, dag outs, dag ins> : Instruction { + let Namespace = "SystemZ"; + + bits<16> Opcode = op; + + Format Form = f; + bits<5> FormBits = Form.Value; + + dag OutOperandList = outs; + dag InOperandList = ins; +} + +class I8<bits<8> op, Format f, dag outs, dag ins, string asmstr, + list<dag> pattern> + : InstSystemZ<0, f, outs, ins> { + let Opcode{0-7} = op; + let Opcode{8-15} = 0; + + let Pattern = pattern; + let AsmString = asmstr; +} + +class I12<bits<12> op, Format f, dag outs, dag ins, string asmstr, + list<dag> pattern> + : InstSystemZ<0, f, outs, ins> { + let Opcode{0-11} = op; + let Opcode{12-15} = 0; + + let Pattern = pattern; + let AsmString = asmstr; +} + +class I16<bits<16> op, Format f, dag outs, dag ins, string asmstr, + list<dag> pattern> + : InstSystemZ<op, f, outs, ins> { + let Pattern = pattern; + let AsmString = asmstr; +} + +class RRI<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : I8<op, RRForm, outs, ins, asmstr, pattern>; + +class RII<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : I12<op, RIForm, outs, ins, asmstr, pattern>; + +class RILI<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : I12<op, RILForm, outs, ins, asmstr, pattern>; + +class RREI<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : I16<op, RREForm, outs, ins, asmstr, pattern>; + +class RXI<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : I8<op, RXForm, outs, ins, asmstr, pattern> { + let AddedComplexity = 1; +} + +class RXYI<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : I16<op, RXYForm, outs, ins, asmstr, pattern>; + +class RSI<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : I8<op, RSForm, outs, ins, asmstr, pattern> { + let AddedComplexity = 1; +} + +class RSYI<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : I16<op, RSYForm, outs, ins, asmstr, pattern>; + +class SII<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : I8<op, SIForm, outs, ins, asmstr, pattern> { + let AddedComplexity = 1; +} + +class SIYI<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : I16<op, SIYForm, outs, ins, asmstr, pattern>; + +class SILI<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : I16<op, SILForm, outs, ins, asmstr, pattern>; + + +//===----------------------------------------------------------------------===// +// Pseudo instructions +//===----------------------------------------------------------------------===// + +class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<0, Pseudo, outs, ins> { + + let Pattern = pattern; + let AsmString = asmstr; +} diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp new file mode 100644 index 0000000..5f3dd80 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -0,0 +1,439 @@ +//===- SystemZInstrInfo.cpp - SystemZ Instruction Information --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the SystemZ implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "SystemZ.h" +#include "SystemZInstrBuilder.h" +#include "SystemZInstrInfo.h" +#include "SystemZMachineFunctionInfo.h" +#include "SystemZTargetMachine.h" +#include "llvm/Function.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/PseudoSourceValue.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +#define GET_INSTRINFO_CTOR +#include "SystemZGenInstrInfo.inc" + +using namespace llvm; + +SystemZInstrInfo::SystemZInstrInfo(SystemZTargetMachine &tm) + : SystemZGenInstrInfo(SystemZ::ADJCALLSTACKUP, SystemZ::ADJCALLSTACKDOWN), + RI(tm, *this), TM(tm) { +} + +/// isGVStub - Return true if the GV requires an extra load to get the +/// real address. +static inline bool isGVStub(GlobalValue *GV, SystemZTargetMachine &TM) { + return TM.getSubtarget<SystemZSubtarget>().GVRequiresExtraLoad(GV, TM, false); +} + +void SystemZInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL; + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + unsigned Opc = 0; + if (RC == &SystemZ::GR32RegClass || + RC == &SystemZ::ADDR32RegClass) + Opc = SystemZ::MOV32mr; + else if (RC == &SystemZ::GR64RegClass || + RC == &SystemZ::ADDR64RegClass) { + Opc = SystemZ::MOV64mr; + } else if (RC == &SystemZ::FP32RegClass) { + Opc = SystemZ::FMOV32mr; + } else if (RC == &SystemZ::FP64RegClass) { + Opc = SystemZ::FMOV64mr; + } else if (RC == &SystemZ::GR64PRegClass) { + Opc = SystemZ::MOV64Pmr; + } else if (RC == &SystemZ::GR128RegClass) { + Opc = SystemZ::MOV128mr; + } else + llvm_unreachable("Unsupported regclass to store"); + + addFrameReference(BuildMI(MBB, MI, DL, get(Opc)), FrameIdx) + .addReg(SrcReg, getKillRegState(isKill)); +} + +void SystemZInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const{ + DebugLoc DL; + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + unsigned Opc = 0; + if (RC == &SystemZ::GR32RegClass || + RC == &SystemZ::ADDR32RegClass) + Opc = SystemZ::MOV32rm; + else if (RC == &SystemZ::GR64RegClass || + RC == &SystemZ::ADDR64RegClass) { + Opc = SystemZ::MOV64rm; + } else if (RC == &SystemZ::FP32RegClass) { + Opc = SystemZ::FMOV32rm; + } else if (RC == &SystemZ::FP64RegClass) { + Opc = SystemZ::FMOV64rm; + } else if (RC == &SystemZ::GR64PRegClass) { + Opc = SystemZ::MOV64Prm; + } else if (RC == &SystemZ::GR128RegClass) { + Opc = SystemZ::MOV128rm; + } else + llvm_unreachable("Unsupported regclass to load"); + + addFrameReference(BuildMI(MBB, MI, DL, get(Opc), DestReg), FrameIdx); +} + +void SystemZInstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const { + unsigned Opc; + if (SystemZ::GR64RegClass.contains(DestReg, SrcReg)) + Opc = SystemZ::MOV64rr; + else if (SystemZ::GR32RegClass.contains(DestReg, SrcReg)) + Opc = SystemZ::MOV32rr; + else if (SystemZ::GR64PRegClass.contains(DestReg, SrcReg)) + Opc = SystemZ::MOV64rrP; + else if (SystemZ::GR128RegClass.contains(DestReg, SrcReg)) + Opc = SystemZ::MOV128rr; + else if (SystemZ::FP32RegClass.contains(DestReg, SrcReg)) + Opc = SystemZ::FMOV32rr; + else if (SystemZ::FP64RegClass.contains(DestReg, SrcReg)) + Opc = SystemZ::FMOV64rr; + else + llvm_unreachable("Impossible reg-to-reg copy"); + + BuildMI(MBB, I, DL, get(Opc), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); +} + +unsigned SystemZInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const { + switch (MI->getOpcode()) { + default: break; + case SystemZ::MOV32rm: + case SystemZ::MOV32rmy: + case SystemZ::MOV64rm: + case SystemZ::MOVSX32rm8: + case SystemZ::MOVSX32rm16y: + case SystemZ::MOVSX64rm8: + case SystemZ::MOVSX64rm16: + case SystemZ::MOVSX64rm32: + case SystemZ::MOVZX32rm8: + case SystemZ::MOVZX32rm16: + case SystemZ::MOVZX64rm8: + case SystemZ::MOVZX64rm16: + case SystemZ::MOVZX64rm32: + case SystemZ::FMOV32rm: + case SystemZ::FMOV32rmy: + case SystemZ::FMOV64rm: + case SystemZ::FMOV64rmy: + case SystemZ::MOV64Prm: + case SystemZ::MOV64Prmy: + case SystemZ::MOV128rm: + if (MI->getOperand(1).isFI() && + MI->getOperand(2).isImm() && MI->getOperand(3).isReg() && + MI->getOperand(2).getImm() == 0 && MI->getOperand(3).getReg() == 0) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + break; + } + return 0; +} + +unsigned SystemZInstrInfo::isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const { + switch (MI->getOpcode()) { + default: break; + case SystemZ::MOV32mr: + case SystemZ::MOV32mry: + case SystemZ::MOV64mr: + case SystemZ::MOV32m8r: + case SystemZ::MOV32m8ry: + case SystemZ::MOV32m16r: + case SystemZ::MOV32m16ry: + case SystemZ::MOV64m8r: + case SystemZ::MOV64m8ry: + case SystemZ::MOV64m16r: + case SystemZ::MOV64m16ry: + case SystemZ::MOV64m32r: + case SystemZ::MOV64m32ry: + case SystemZ::FMOV32mr: + case SystemZ::FMOV32mry: + case SystemZ::FMOV64mr: + case SystemZ::FMOV64mry: + case SystemZ::MOV64Pmr: + case SystemZ::MOV64Pmry: + case SystemZ::MOV128mr: + if (MI->getOperand(0).isFI() && + MI->getOperand(1).isImm() && MI->getOperand(2).isReg() && + MI->getOperand(1).getImm() == 0 && MI->getOperand(2).getReg() == 0) { + FrameIndex = MI->getOperand(0).getIndex(); + return MI->getOperand(3).getReg(); + } + break; + } + return 0; +} + +bool SystemZInstrInfo:: +ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const { + assert(Cond.size() == 1 && "Invalid Xbranch condition!"); + + SystemZCC::CondCodes CC = static_cast<SystemZCC::CondCodes>(Cond[0].getImm()); + Cond[0].setImm(getOppositeCondition(CC)); + return false; +} + +bool SystemZInstrInfo::isUnpredicatedTerminator(const MachineInstr *MI) const { + const MCInstrDesc &MCID = MI->getDesc(); + if (!MCID.isTerminator()) return false; + + // Conditional branch is a special case. + if (MCID.isBranch() && !MCID.isBarrier()) + return true; + if (!MCID.isPredicable()) + return true; + return !isPredicated(MI); +} + +bool SystemZInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const { + // Start from the bottom of the block and work up, examining the + // terminator instructions. + MachineBasicBlock::iterator I = MBB.end(); + while (I != MBB.begin()) { + --I; + if (I->isDebugValue()) + continue; + // Working from the bottom, when we see a non-terminator + // instruction, we're done. + if (!isUnpredicatedTerminator(I)) + break; + + // A terminator that isn't a branch can't easily be handled + // by this analysis. + if (!I->getDesc().isBranch()) + return true; + + // Handle unconditional branches. + if (I->getOpcode() == SystemZ::JMP) { + if (!AllowModify) { + TBB = I->getOperand(0).getMBB(); + continue; + } + + // If the block has any instructions after a JMP, delete them. + while (llvm::next(I) != MBB.end()) + llvm::next(I)->eraseFromParent(); + Cond.clear(); + FBB = 0; + + // Delete the JMP if it's equivalent to a fall-through. + if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) { + TBB = 0; + I->eraseFromParent(); + I = MBB.end(); + continue; + } + + // TBB is used to indicate the unconditinal destination. + TBB = I->getOperand(0).getMBB(); + continue; + } + + // Handle conditional branches. + SystemZCC::CondCodes BranchCode = getCondFromBranchOpc(I->getOpcode()); + if (BranchCode == SystemZCC::INVALID) + return true; // Can't handle indirect branch. + + // Working from the bottom, handle the first conditional branch. + if (Cond.empty()) { + FBB = TBB; + TBB = I->getOperand(0).getMBB(); + Cond.push_back(MachineOperand::CreateImm(BranchCode)); + continue; + } + + // Handle subsequent conditional branches. Only handle the case where all + // conditional branches branch to the same destination. + assert(Cond.size() == 1); + assert(TBB); + + // Only handle the case where all conditional branches branch to + // the same destination. + if (TBB != I->getOperand(0).getMBB()) + return true; + + SystemZCC::CondCodes OldBranchCode = (SystemZCC::CondCodes)Cond[0].getImm(); + // If the conditions are the same, we can leave them alone. + if (OldBranchCode == BranchCode) + continue; + + return true; + } + + return false; +} + +unsigned SystemZInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator I = MBB.end(); + unsigned Count = 0; + + while (I != MBB.begin()) { + --I; + if (I->isDebugValue()) + continue; + if (I->getOpcode() != SystemZ::JMP && + getCondFromBranchOpc(I->getOpcode()) == SystemZCC::INVALID) + break; + // Remove the branch. + I->eraseFromParent(); + I = MBB.end(); + ++Count; + } + + return Count; +} + +unsigned +SystemZInstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond, + DebugLoc DL) const { + // Shouldn't be a fall through. + assert(TBB && "InsertBranch must not be told to insert a fallthrough"); + assert((Cond.size() == 1 || Cond.size() == 0) && + "SystemZ branch conditions have one component!"); + + if (Cond.empty()) { + // Unconditional branch? + assert(!FBB && "Unconditional branch with multiple successors!"); + BuildMI(&MBB, DL, get(SystemZ::JMP)).addMBB(TBB); + return 1; + } + + // Conditional branch. + unsigned Count = 0; + SystemZCC::CondCodes CC = (SystemZCC::CondCodes)Cond[0].getImm(); + BuildMI(&MBB, DL, getBrCond(CC)).addMBB(TBB); + ++Count; + + if (FBB) { + // Two-way Conditional branch. Insert the second branch. + BuildMI(&MBB, DL, get(SystemZ::JMP)).addMBB(FBB); + ++Count; + } + return Count; +} + +const MCInstrDesc& +SystemZInstrInfo::getBrCond(SystemZCC::CondCodes CC) const { + switch (CC) { + default: + llvm_unreachable("Unknown condition code!"); + case SystemZCC::O: return get(SystemZ::JO); + case SystemZCC::H: return get(SystemZ::JH); + case SystemZCC::NLE: return get(SystemZ::JNLE); + case SystemZCC::L: return get(SystemZ::JL); + case SystemZCC::NHE: return get(SystemZ::JNHE); + case SystemZCC::LH: return get(SystemZ::JLH); + case SystemZCC::NE: return get(SystemZ::JNE); + case SystemZCC::E: return get(SystemZ::JE); + case SystemZCC::NLH: return get(SystemZ::JNLH); + case SystemZCC::HE: return get(SystemZ::JHE); + case SystemZCC::NL: return get(SystemZ::JNL); + case SystemZCC::LE: return get(SystemZ::JLE); + case SystemZCC::NH: return get(SystemZ::JNH); + case SystemZCC::NO: return get(SystemZ::JNO); + } +} + +SystemZCC::CondCodes +SystemZInstrInfo::getCondFromBranchOpc(unsigned Opc) const { + switch (Opc) { + default: return SystemZCC::INVALID; + case SystemZ::JO: return SystemZCC::O; + case SystemZ::JH: return SystemZCC::H; + case SystemZ::JNLE: return SystemZCC::NLE; + case SystemZ::JL: return SystemZCC::L; + case SystemZ::JNHE: return SystemZCC::NHE; + case SystemZ::JLH: return SystemZCC::LH; + case SystemZ::JNE: return SystemZCC::NE; + case SystemZ::JE: return SystemZCC::E; + case SystemZ::JNLH: return SystemZCC::NLH; + case SystemZ::JHE: return SystemZCC::HE; + case SystemZ::JNL: return SystemZCC::NL; + case SystemZ::JLE: return SystemZCC::LE; + case SystemZ::JNH: return SystemZCC::NH; + case SystemZ::JNO: return SystemZCC::NO; + } +} + +SystemZCC::CondCodes +SystemZInstrInfo::getOppositeCondition(SystemZCC::CondCodes CC) const { + switch (CC) { + default: + llvm_unreachable("Invalid condition!"); + case SystemZCC::O: return SystemZCC::NO; + case SystemZCC::H: return SystemZCC::NH; + case SystemZCC::NLE: return SystemZCC::LE; + case SystemZCC::L: return SystemZCC::NL; + case SystemZCC::NHE: return SystemZCC::HE; + case SystemZCC::LH: return SystemZCC::NLH; + case SystemZCC::NE: return SystemZCC::E; + case SystemZCC::E: return SystemZCC::NE; + case SystemZCC::NLH: return SystemZCC::LH; + case SystemZCC::HE: return SystemZCC::NHE; + case SystemZCC::NL: return SystemZCC::L; + case SystemZCC::LE: return SystemZCC::NLE; + case SystemZCC::NH: return SystemZCC::H; + case SystemZCC::NO: return SystemZCC::O; + } +} + +const MCInstrDesc& +SystemZInstrInfo::getLongDispOpc(unsigned Opc) const { + switch (Opc) { + default: + llvm_unreachable("Don't have long disp version of this instruction"); + case SystemZ::MOV32mr: return get(SystemZ::MOV32mry); + case SystemZ::MOV32rm: return get(SystemZ::MOV32rmy); + case SystemZ::MOVSX32rm16: return get(SystemZ::MOVSX32rm16y); + case SystemZ::MOV32m8r: return get(SystemZ::MOV32m8ry); + case SystemZ::MOV32m16r: return get(SystemZ::MOV32m16ry); + case SystemZ::MOV64m8r: return get(SystemZ::MOV64m8ry); + case SystemZ::MOV64m16r: return get(SystemZ::MOV64m16ry); + case SystemZ::MOV64m32r: return get(SystemZ::MOV64m32ry); + case SystemZ::MOV8mi: return get(SystemZ::MOV8miy); + case SystemZ::MUL32rm: return get(SystemZ::MUL32rmy); + case SystemZ::CMP32rm: return get(SystemZ::CMP32rmy); + case SystemZ::UCMP32rm: return get(SystemZ::UCMP32rmy); + case SystemZ::FMOV32mr: return get(SystemZ::FMOV32mry); + case SystemZ::FMOV64mr: return get(SystemZ::FMOV64mry); + case SystemZ::FMOV32rm: return get(SystemZ::FMOV32rmy); + case SystemZ::FMOV64rm: return get(SystemZ::FMOV64rmy); + case SystemZ::MOV64Pmr: return get(SystemZ::MOV64Pmry); + case SystemZ::MOV64Prm: return get(SystemZ::MOV64Prmy); + } +} diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.h b/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.h new file mode 100644 index 0000000..6a31e94 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.h @@ -0,0 +1,113 @@ +//===- SystemZInstrInfo.h - SystemZ Instruction Information -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the SystemZ implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_SYSTEMZINSTRINFO_H +#define LLVM_TARGET_SYSTEMZINSTRINFO_H + +#include "SystemZ.h" +#include "SystemZRegisterInfo.h" +#include "llvm/ADT/IndexedMap.h" +#include "llvm/Target/TargetInstrInfo.h" + +#define GET_INSTRINFO_HEADER +#include "SystemZGenInstrInfo.inc" + +namespace llvm { + +class SystemZTargetMachine; + +/// SystemZII - This namespace holds all of the target specific flags that +/// instruction info tracks. +/// +namespace SystemZII { + enum { + //===------------------------------------------------------------------===// + // SystemZ Specific MachineOperand flags. + + MO_NO_FLAG = 0, + + /// MO_GOTENT - On a symbol operand this indicates that the immediate is + /// the offset to the location of the symbol name from the base of the GOT. + /// + /// SYMBOL_LABEL @GOTENT + MO_GOTENT = 1, + + /// MO_PLT - On a symbol operand this indicates that the immediate is + /// offset to the PLT entry of symbol name from the current code location. + /// + /// SYMBOL_LABEL @PLT + MO_PLT = 2 + }; +} + +class SystemZInstrInfo : public SystemZGenInstrInfo { + const SystemZRegisterInfo RI; + SystemZTargetMachine &TM; +public: + explicit SystemZInstrInfo(SystemZTargetMachine &TM); + + /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As + /// such, whenever a client has an instance of instruction info, it should + /// always be able to get register info as well (through this method). + /// + virtual const SystemZRegisterInfo &getRegisterInfo() const { return RI; } + + virtual void copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const; + + unsigned isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const; + unsigned isStoreToStackSlot(const MachineInstr *MI, int &FrameIndex) const; + + virtual void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, + int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const; + virtual void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const; + + bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const; + virtual bool isUnpredicatedTerminator(const MachineInstr *MI) const; + virtual bool AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const; + virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond, + DebugLoc DL) const; + virtual unsigned RemoveBranch(MachineBasicBlock &MBB) const; + + SystemZCC::CondCodes getOppositeCondition(SystemZCC::CondCodes CC) const; + SystemZCC::CondCodes getCondFromBranchOpc(unsigned Opc) const; + const MCInstrDesc& getBrCond(SystemZCC::CondCodes CC) const; + const MCInstrDesc& getLongDispOpc(unsigned Opc) const; + + const MCInstrDesc& getMemoryInstr(unsigned Opc, int64_t Offset = 0) const { + if (Offset < 0 || Offset >= 4096) + return getLongDispOpc(Opc); + else + return get(Opc); + } +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.td new file mode 100644 index 0000000..580d65b --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.td @@ -0,0 +1,1147 @@ +//===- SystemZInstrInfo.td - SystemZ Instruction defs ---------*- tblgen-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the SystemZ instructions in TableGen format. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// SystemZ Instruction Predicate Definitions. +def IsZ10 : Predicate<"Subtarget.isZ10()">; + +include "SystemZInstrFormats.td" + +//===----------------------------------------------------------------------===// +// Type Constraints. +//===----------------------------------------------------------------------===// +class SDTCisI8<int OpNum> : SDTCisVT<OpNum, i8>; +class SDTCisI16<int OpNum> : SDTCisVT<OpNum, i16>; +class SDTCisI32<int OpNum> : SDTCisVT<OpNum, i32>; +class SDTCisI64<int OpNum> : SDTCisVT<OpNum, i64>; + +//===----------------------------------------------------------------------===// +// Type Profiles. +//===----------------------------------------------------------------------===// +def SDT_SystemZCall : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>; +def SDT_SystemZCallSeqStart : SDCallSeqStart<[SDTCisI64<0>]>; +def SDT_SystemZCallSeqEnd : SDCallSeqEnd<[SDTCisI64<0>, SDTCisI64<1>]>; +def SDT_CmpTest : SDTypeProfile<1, 2, [SDTCisI64<0>, + SDTCisSameAs<1, 2>]>; +def SDT_BrCond : SDTypeProfile<0, 3, + [SDTCisVT<0, OtherVT>, + SDTCisI8<1>, SDTCisVT<2, i64>]>; +def SDT_SelectCC : SDTypeProfile<1, 4, + [SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>, + SDTCisI8<3>, SDTCisVT<4, i64>]>; +def SDT_Address : SDTypeProfile<1, 1, + [SDTCisSameAs<0, 1>, SDTCisPtrTy<0>]>; + +//===----------------------------------------------------------------------===// +// SystemZ Specific Node Definitions. +//===----------------------------------------------------------------------===// +def SystemZretflag : SDNode<"SystemZISD::RET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInGlue]>; +def SystemZcall : SDNode<"SystemZISD::CALL", SDT_SystemZCall, + [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>; +def SystemZcallseq_start : + SDNode<"ISD::CALLSEQ_START", SDT_SystemZCallSeqStart, + [SDNPHasChain, SDNPOutGlue]>; +def SystemZcallseq_end : + SDNode<"ISD::CALLSEQ_END", SDT_SystemZCallSeqEnd, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; +def SystemZcmp : SDNode<"SystemZISD::CMP", SDT_CmpTest>; +def SystemZucmp : SDNode<"SystemZISD::UCMP", SDT_CmpTest>; +def SystemZbrcond : SDNode<"SystemZISD::BRCOND", SDT_BrCond, + [SDNPHasChain]>; +def SystemZselect : SDNode<"SystemZISD::SELECT", SDT_SelectCC>; +def SystemZpcrelwrapper : SDNode<"SystemZISD::PCRelativeWrapper", SDT_Address, []>; + + +include "SystemZOperands.td" + +//===----------------------------------------------------------------------===// +// Instruction list.. + +def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i64imm:$amt), + "#ADJCALLSTACKDOWN", + [(SystemZcallseq_start timm:$amt)]>; +def ADJCALLSTACKUP : Pseudo<(outs), (ins i64imm:$amt1, i64imm:$amt2), + "#ADJCALLSTACKUP", + [(SystemZcallseq_end timm:$amt1, timm:$amt2)]>; + +let Uses = [PSW], usesCustomInserter = 1 in { + def Select32 : Pseudo<(outs GR32:$dst), (ins GR32:$src1, GR32:$src2, i8imm:$cc), + "# Select32 PSEUDO", + [(set GR32:$dst, + (SystemZselect GR32:$src1, GR32:$src2, imm:$cc, PSW))]>; + def Select64 : Pseudo<(outs GR64:$dst), (ins GR64:$src1, GR64:$src2, i8imm:$cc), + "# Select64 PSEUDO", + [(set GR64:$dst, + (SystemZselect GR64:$src1, GR64:$src2, imm:$cc, PSW))]>; +} + + +//===----------------------------------------------------------------------===// +// Control Flow Instructions... +// + +// FIXME: Provide proper encoding! +let isReturn = 1, isTerminator = 1, isBarrier = 1, hasCtrlDep = 1 in { + def RET : Pseudo<(outs), (ins), "br\t%r14", [(SystemZretflag)]>; +} + +let isBranch = 1, isTerminator = 1 in { + let isBarrier = 1 in { + def JMP : Pseudo<(outs), (ins brtarget:$dst), "j\t{$dst}", [(br bb:$dst)]>; + + let isIndirectBranch = 1 in + def JMPr : Pseudo<(outs), (ins GR64:$dst), "br\t{$dst}", [(brind GR64:$dst)]>; + } + + let Uses = [PSW] in { + def JO : Pseudo<(outs), (ins brtarget:$dst), + "jo\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_O, PSW)]>; + def JH : Pseudo<(outs), (ins brtarget:$dst), + "jh\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_H, PSW)]>; + def JNLE: Pseudo<(outs), (ins brtarget:$dst), + "jnle\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_NLE, PSW)]>; + def JL : Pseudo<(outs), (ins brtarget:$dst), + "jl\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_L, PSW)]>; + def JNHE: Pseudo<(outs), (ins brtarget:$dst), + "jnhe\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_NHE, PSW)]>; + def JLH : Pseudo<(outs), (ins brtarget:$dst), + "jlh\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_LH, PSW)]>; + def JNE : Pseudo<(outs), (ins brtarget:$dst), + "jne\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_NE, PSW)]>; + def JE : Pseudo<(outs), (ins brtarget:$dst), + "je\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_E, PSW)]>; + def JNLH: Pseudo<(outs), (ins brtarget:$dst), + "jnlh\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_NLH, PSW)]>; + def JHE : Pseudo<(outs), (ins brtarget:$dst), + "jhe\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_HE, PSW)]>; + def JNL : Pseudo<(outs), (ins brtarget:$dst), + "jnl\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_NL, PSW)]>; + def JLE : Pseudo<(outs), (ins brtarget:$dst), + "jle\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_LE, PSW)]>; + def JNH : Pseudo<(outs), (ins brtarget:$dst), + "jnh\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_NH, PSW)]>; + def JNO : Pseudo<(outs), (ins brtarget:$dst), + "jno\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_NO, PSW)]>; + } // Uses = [PSW] +} // isBranch = 1 + +//===----------------------------------------------------------------------===// +// Call Instructions... +// + +let isCall = 1 in + // All calls clobber the non-callee saved registers. Uses for argument + // registers are added manually. + let Defs = [R0D, R1D, R2D, R3D, R4D, R5D, R14D, + F0L, F1L, F2L, F3L, F4L, F5L, F6L, F7L] in { + def CALLi : Pseudo<(outs), (ins imm_pcrel:$dst, variable_ops), + "brasl\t%r14, $dst", [(SystemZcall imm:$dst)]>; + def CALLr : Pseudo<(outs), (ins ADDR64:$dst, variable_ops), + "basr\t%r14, $dst", [(SystemZcall ADDR64:$dst)]>; + } + +//===----------------------------------------------------------------------===// +// Miscellaneous Instructions. +// + +let isReMaterializable = 1 in +// FIXME: Provide imm12 variant +// FIXME: Address should be halfword aligned... +def LA64r : RXI<0x47, + (outs GR64:$dst), (ins laaddr:$src), + "lay\t{$dst, $src}", + [(set GR64:$dst, laaddr:$src)]>; +def LA64rm : RXYI<0x71E3, + (outs GR64:$dst), (ins i64imm:$src), + "larl\t{$dst, $src}", + [(set GR64:$dst, + (SystemZpcrelwrapper tglobaladdr:$src))]>; + +let neverHasSideEffects = 1 in +def NOP : Pseudo<(outs), (ins), "# no-op", []>; + +//===----------------------------------------------------------------------===// +// Move Instructions + +let neverHasSideEffects = 1 in { +def MOV32rr : RRI<0x18, + (outs GR32:$dst), (ins GR32:$src), + "lr\t{$dst, $src}", + []>; +def MOV64rr : RREI<0xB904, + (outs GR64:$dst), (ins GR64:$src), + "lgr\t{$dst, $src}", + []>; +def MOV128rr : Pseudo<(outs GR128:$dst), (ins GR128:$src), + "# MOV128 PSEUDO!\n" + "\tlgr\t${dst:subreg_odd}, ${src:subreg_odd}\n" + "\tlgr\t${dst:subreg_even}, ${src:subreg_even}", + []>; +def MOV64rrP : Pseudo<(outs GR64P:$dst), (ins GR64P:$src), + "# MOV64P PSEUDO!\n" + "\tlr\t${dst:subreg_odd}, ${src:subreg_odd}\n" + "\tlr\t${dst:subreg_even}, ${src:subreg_even}", + []>; +} + +def MOVSX64rr32 : RREI<0xB914, + (outs GR64:$dst), (ins GR32:$src), + "lgfr\t{$dst, $src}", + [(set GR64:$dst, (sext GR32:$src))]>; +def MOVZX64rr32 : RREI<0xB916, + (outs GR64:$dst), (ins GR32:$src), + "llgfr\t{$dst, $src}", + [(set GR64:$dst, (zext GR32:$src))]>; + +let isReMaterializable = 1, isAsCheapAsAMove = 1 in { +def MOV32ri16 : RII<0x8A7, + (outs GR32:$dst), (ins s16imm:$src), + "lhi\t{$dst, $src}", + [(set GR32:$dst, immSExt16:$src)]>; +def MOV64ri16 : RII<0x9A7, + (outs GR64:$dst), (ins s16imm64:$src), + "lghi\t{$dst, $src}", + [(set GR64:$dst, immSExt16:$src)]>; + +def MOV64rill16 : RII<0xFA5, + (outs GR64:$dst), (ins u16imm:$src), + "llill\t{$dst, $src}", + [(set GR64:$dst, i64ll16:$src)]>; +def MOV64rilh16 : RII<0xEA5, + (outs GR64:$dst), (ins u16imm:$src), + "llilh\t{$dst, $src}", + [(set GR64:$dst, i64lh16:$src)]>; +def MOV64rihl16 : RII<0xDA5, + (outs GR64:$dst), (ins u16imm:$src), + "llihl\t{$dst, $src}", + [(set GR64:$dst, i64hl16:$src)]>; +def MOV64rihh16 : RII<0xCA5, + (outs GR64:$dst), (ins u16imm:$src), + "llihh\t{$dst, $src}", + [(set GR64:$dst, i64hh16:$src)]>; + +def MOV64ri32 : RILI<0x1C0, + (outs GR64:$dst), (ins s32imm64:$src), + "lgfi\t{$dst, $src}", + [(set GR64:$dst, immSExt32:$src)]>; +def MOV64rilo32 : RILI<0xFC0, + (outs GR64:$dst), (ins u32imm:$src), + "llilf\t{$dst, $src}", + [(set GR64:$dst, i64lo32:$src)]>; +def MOV64rihi32 : RILI<0xEC0, (outs GR64:$dst), (ins u32imm:$src), + "llihf\t{$dst, $src}", + [(set GR64:$dst, i64hi32:$src)]>; +} + +let canFoldAsLoad = 1, isReMaterializable = 1 in { +def MOV32rm : RXI<0x58, + (outs GR32:$dst), (ins rriaddr12:$src), + "l\t{$dst, $src}", + [(set GR32:$dst, (load rriaddr12:$src))]>; +def MOV32rmy : RXYI<0x58E3, + (outs GR32:$dst), (ins rriaddr:$src), + "ly\t{$dst, $src}", + [(set GR32:$dst, (load rriaddr:$src))]>; +def MOV64rm : RXYI<0x04E3, + (outs GR64:$dst), (ins rriaddr:$src), + "lg\t{$dst, $src}", + [(set GR64:$dst, (load rriaddr:$src))]>; +def MOV64Prm : Pseudo<(outs GR64P:$dst), (ins rriaddr12:$src), + "# MOV64P PSEUDO!\n" + "\tl\t${dst:subreg_odd}, $src\n" + "\tl\t${dst:subreg_even}, 4+$src", + [(set GR64P:$dst, (load rriaddr12:$src))]>; +def MOV64Prmy : Pseudo<(outs GR64P:$dst), (ins rriaddr:$src), + "# MOV64P PSEUDO!\n" + "\tly\t${dst:subreg_odd}, $src\n" + "\tly\t${dst:subreg_even}, 4+$src", + [(set GR64P:$dst, (load rriaddr:$src))]>; +def MOV128rm : Pseudo<(outs GR128:$dst), (ins rriaddr:$src), + "# MOV128 PSEUDO!\n" + "\tlg\t${dst:subreg_odd}, $src\n" + "\tlg\t${dst:subreg_even}, 8+$src", + [(set GR128:$dst, (load rriaddr:$src))]>; +} + +def MOV32mr : RXI<0x50, + (outs), (ins rriaddr12:$dst, GR32:$src), + "st\t{$src, $dst}", + [(store GR32:$src, rriaddr12:$dst)]>; +def MOV32mry : RXYI<0x50E3, + (outs), (ins rriaddr:$dst, GR32:$src), + "sty\t{$src, $dst}", + [(store GR32:$src, rriaddr:$dst)]>; +def MOV64mr : RXYI<0x24E3, + (outs), (ins rriaddr:$dst, GR64:$src), + "stg\t{$src, $dst}", + [(store GR64:$src, rriaddr:$dst)]>; +def MOV64Pmr : Pseudo<(outs), (ins rriaddr12:$dst, GR64P:$src), + "# MOV64P PSEUDO!\n" + "\tst\t${src:subreg_odd}, $dst\n" + "\tst\t${src:subreg_even}, 4+$dst", + [(store GR64P:$src, rriaddr12:$dst)]>; +def MOV64Pmry : Pseudo<(outs), (ins rriaddr:$dst, GR64P:$src), + "# MOV64P PSEUDO!\n" + "\tsty\t${src:subreg_odd}, $dst\n" + "\tsty\t${src:subreg_even}, 4+$dst", + [(store GR64P:$src, rriaddr:$dst)]>; +def MOV128mr : Pseudo<(outs), (ins rriaddr:$dst, GR128:$src), + "# MOV128 PSEUDO!\n" + "\tstg\t${src:subreg_odd}, $dst\n" + "\tstg\t${src:subreg_even}, 8+$dst", + [(store GR128:$src, rriaddr:$dst)]>; + +def MOV8mi : SII<0x92, + (outs), (ins riaddr12:$dst, i32i8imm:$src), + "mvi\t{$dst, $src}", + [(truncstorei8 (i32 i32immSExt8:$src), riaddr12:$dst)]>; +def MOV8miy : SIYI<0x52EB, + (outs), (ins riaddr:$dst, i32i8imm:$src), + "mviy\t{$dst, $src}", + [(truncstorei8 (i32 i32immSExt8:$src), riaddr:$dst)]>; + +let AddedComplexity = 2 in { +def MOV16mi : SILI<0xE544, + (outs), (ins riaddr12:$dst, s16imm:$src), + "mvhhi\t{$dst, $src}", + [(truncstorei16 (i32 i32immSExt16:$src), riaddr12:$dst)]>, + Requires<[IsZ10]>; +def MOV32mi16 : SILI<0xE54C, + (outs), (ins riaddr12:$dst, s32imm:$src), + "mvhi\t{$dst, $src}", + [(store (i32 immSExt16:$src), riaddr12:$dst)]>, + Requires<[IsZ10]>; +def MOV64mi16 : SILI<0xE548, + (outs), (ins riaddr12:$dst, s32imm64:$src), + "mvghi\t{$dst, $src}", + [(store (i64 immSExt16:$src), riaddr12:$dst)]>, + Requires<[IsZ10]>; +} + +// sexts +def MOVSX32rr8 : RREI<0xB926, + (outs GR32:$dst), (ins GR32:$src), + "lbr\t{$dst, $src}", + [(set GR32:$dst, (sext_inreg GR32:$src, i8))]>; +def MOVSX64rr8 : RREI<0xB906, + (outs GR64:$dst), (ins GR64:$src), + "lgbr\t{$dst, $src}", + [(set GR64:$dst, (sext_inreg GR64:$src, i8))]>; +def MOVSX32rr16 : RREI<0xB927, + (outs GR32:$dst), (ins GR32:$src), + "lhr\t{$dst, $src}", + [(set GR32:$dst, (sext_inreg GR32:$src, i16))]>; +def MOVSX64rr16 : RREI<0xB907, + (outs GR64:$dst), (ins GR64:$src), + "lghr\t{$dst, $src}", + [(set GR64:$dst, (sext_inreg GR64:$src, i16))]>; + +// extloads +def MOVSX32rm8 : RXYI<0x76E3, + (outs GR32:$dst), (ins rriaddr:$src), + "lb\t{$dst, $src}", + [(set GR32:$dst, (sextloadi32i8 rriaddr:$src))]>; +def MOVSX32rm16 : RXI<0x48, + (outs GR32:$dst), (ins rriaddr12:$src), + "lh\t{$dst, $src}", + [(set GR32:$dst, (sextloadi32i16 rriaddr12:$src))]>; +def MOVSX32rm16y : RXYI<0x78E3, + (outs GR32:$dst), (ins rriaddr:$src), + "lhy\t{$dst, $src}", + [(set GR32:$dst, (sextloadi32i16 rriaddr:$src))]>; +def MOVSX64rm8 : RXYI<0x77E3, + (outs GR64:$dst), (ins rriaddr:$src), + "lgb\t{$dst, $src}", + [(set GR64:$dst, (sextloadi64i8 rriaddr:$src))]>; +def MOVSX64rm16 : RXYI<0x15E3, + (outs GR64:$dst), (ins rriaddr:$src), + "lgh\t{$dst, $src}", + [(set GR64:$dst, (sextloadi64i16 rriaddr:$src))]>; +def MOVSX64rm32 : RXYI<0x14E3, + (outs GR64:$dst), (ins rriaddr:$src), + "lgf\t{$dst, $src}", + [(set GR64:$dst, (sextloadi64i32 rriaddr:$src))]>; + +def MOVZX32rm8 : RXYI<0x94E3, + (outs GR32:$dst), (ins rriaddr:$src), + "llc\t{$dst, $src}", + [(set GR32:$dst, (zextloadi32i8 rriaddr:$src))]>; +def MOVZX32rm16 : RXYI<0x95E3, + (outs GR32:$dst), (ins rriaddr:$src), + "llh\t{$dst, $src}", + [(set GR32:$dst, (zextloadi32i16 rriaddr:$src))]>; +def MOVZX64rm8 : RXYI<0x90E3, + (outs GR64:$dst), (ins rriaddr:$src), + "llgc\t{$dst, $src}", + [(set GR64:$dst, (zextloadi64i8 rriaddr:$src))]>; +def MOVZX64rm16 : RXYI<0x91E3, + (outs GR64:$dst), (ins rriaddr:$src), + "llgh\t{$dst, $src}", + [(set GR64:$dst, (zextloadi64i16 rriaddr:$src))]>; +def MOVZX64rm32 : RXYI<0x16E3, + (outs GR64:$dst), (ins rriaddr:$src), + "llgf\t{$dst, $src}", + [(set GR64:$dst, (zextloadi64i32 rriaddr:$src))]>; + +// truncstores +def MOV32m8r : RXI<0x42, + (outs), (ins rriaddr12:$dst, GR32:$src), + "stc\t{$src, $dst}", + [(truncstorei8 GR32:$src, rriaddr12:$dst)]>; + +def MOV32m8ry : RXYI<0x72E3, + (outs), (ins rriaddr:$dst, GR32:$src), + "stcy\t{$src, $dst}", + [(truncstorei8 GR32:$src, rriaddr:$dst)]>; + +def MOV32m16r : RXI<0x40, + (outs), (ins rriaddr12:$dst, GR32:$src), + "sth\t{$src, $dst}", + [(truncstorei16 GR32:$src, rriaddr12:$dst)]>; + +def MOV32m16ry : RXYI<0x70E3, + (outs), (ins rriaddr:$dst, GR32:$src), + "sthy\t{$src, $dst}", + [(truncstorei16 GR32:$src, rriaddr:$dst)]>; + +def MOV64m8r : RXI<0x42, + (outs), (ins rriaddr12:$dst, GR64:$src), + "stc\t{$src, $dst}", + [(truncstorei8 GR64:$src, rriaddr12:$dst)]>; + +def MOV64m8ry : RXYI<0x72E3, + (outs), (ins rriaddr:$dst, GR64:$src), + "stcy\t{$src, $dst}", + [(truncstorei8 GR64:$src, rriaddr:$dst)]>; + +def MOV64m16r : RXI<0x40, + (outs), (ins rriaddr12:$dst, GR64:$src), + "sth\t{$src, $dst}", + [(truncstorei16 GR64:$src, rriaddr12:$dst)]>; + +def MOV64m16ry : RXYI<0x70E3, + (outs), (ins rriaddr:$dst, GR64:$src), + "sthy\t{$src, $dst}", + [(truncstorei16 GR64:$src, rriaddr:$dst)]>; + +def MOV64m32r : RXI<0x50, + (outs), (ins rriaddr12:$dst, GR64:$src), + "st\t{$src, $dst}", + [(truncstorei32 GR64:$src, rriaddr12:$dst)]>; + +def MOV64m32ry : RXYI<0x50E3, + (outs), (ins rriaddr:$dst, GR64:$src), + "sty\t{$src, $dst}", + [(truncstorei32 GR64:$src, rriaddr:$dst)]>; + +// multiple regs moves +// FIXME: should we use multiple arg nodes? +def MOV32mrm : RSYI<0x90EB, + (outs), (ins riaddr:$dst, GR32:$from, GR32:$to), + "stmy\t{$from, $to, $dst}", + []>; +def MOV64mrm : RSYI<0x24EB, + (outs), (ins riaddr:$dst, GR64:$from, GR64:$to), + "stmg\t{$from, $to, $dst}", + []>; +def MOV32rmm : RSYI<0x90EB, + (outs GR32:$from, GR32:$to), (ins riaddr:$dst), + "lmy\t{$from, $to, $dst}", + []>; +def MOV64rmm : RSYI<0x04EB, + (outs GR64:$from, GR64:$to), (ins riaddr:$dst), + "lmg\t{$from, $to, $dst}", + []>; + +let isReMaterializable = 1, neverHasSideEffects = 1, isAsCheapAsAMove = 1, + Constraints = "$src = $dst" in { +def MOV64Pr0_even : Pseudo<(outs GR64P:$dst), (ins GR64P:$src), + "lhi\t${dst:subreg_even}, 0", + []>; +def MOV128r0_even : Pseudo<(outs GR128:$dst), (ins GR128:$src), + "lghi\t${dst:subreg_even}, 0", + []>; +} + +// Byte swaps +def BSWAP32rr : RREI<0xB91F, + (outs GR32:$dst), (ins GR32:$src), + "lrvr\t{$dst, $src}", + [(set GR32:$dst, (bswap GR32:$src))]>; +def BSWAP64rr : RREI<0xB90F, + (outs GR64:$dst), (ins GR64:$src), + "lrvgr\t{$dst, $src}", + [(set GR64:$dst, (bswap GR64:$src))]>; + +// FIXME: this is invalid pattern for big-endian +//def BSWAP16rm : RXYI<0x1FE3, (outs GR32:$dst), (ins rriaddr:$src), +// "lrvh\t{$dst, $src}", +// [(set GR32:$dst, (bswap (extloadi32i16 rriaddr:$src)))]>; +def BSWAP32rm : RXYI<0x1EE3, (outs GR32:$dst), (ins rriaddr:$src), + "lrv\t{$dst, $src}", + [(set GR32:$dst, (bswap (load rriaddr:$src)))]>; +def BSWAP64rm : RXYI<0x0FE3, (outs GR64:$dst), (ins rriaddr:$src), + "lrvg\t{$dst, $src}", + [(set GR64:$dst, (bswap (load rriaddr:$src)))]>; + +//def BSWAP16mr : RXYI<0xE33F, (outs), (ins rriaddr:$dst, GR32:$src), +// "strvh\t{$src, $dst}", +// [(truncstorei16 (bswap GR32:$src), rriaddr:$dst)]>; +def BSWAP32mr : RXYI<0xE33E, (outs), (ins rriaddr:$dst, GR32:$src), + "strv\t{$src, $dst}", + [(store (bswap GR32:$src), rriaddr:$dst)]>; +def BSWAP64mr : RXYI<0xE32F, (outs), (ins rriaddr:$dst, GR64:$src), + "strvg\t{$src, $dst}", + [(store (bswap GR64:$src), rriaddr:$dst)]>; + +//===----------------------------------------------------------------------===// +// Arithmetic Instructions + +let Defs = [PSW] in { +def NEG32rr : RRI<0x13, + (outs GR32:$dst), (ins GR32:$src), + "lcr\t{$dst, $src}", + [(set GR32:$dst, (ineg GR32:$src)), + (implicit PSW)]>; +def NEG64rr : RREI<0xB903, (outs GR64:$dst), (ins GR64:$src), + "lcgr\t{$dst, $src}", + [(set GR64:$dst, (ineg GR64:$src)), + (implicit PSW)]>; +def NEG64rr32 : RREI<0xB913, (outs GR64:$dst), (ins GR32:$src), + "lcgfr\t{$dst, $src}", + [(set GR64:$dst, (ineg (sext GR32:$src))), + (implicit PSW)]>; +} + +let Constraints = "$src1 = $dst" in { + +let Defs = [PSW] in { + +let isCommutable = 1 in { // X = ADD Y, Z == X = ADD Z, Y +def ADD32rr : RRI<0x1A, (outs GR32:$dst), (ins GR32:$src1, GR32:$src2), + "ar\t{$dst, $src2}", + [(set GR32:$dst, (add GR32:$src1, GR32:$src2)), + (implicit PSW)]>; +def ADD64rr : RREI<0xB908, (outs GR64:$dst), (ins GR64:$src1, GR64:$src2), + "agr\t{$dst, $src2}", + [(set GR64:$dst, (add GR64:$src1, GR64:$src2)), + (implicit PSW)]>; +} + +def ADD32rm : RXI<0x5A, (outs GR32:$dst), (ins GR32:$src1, rriaddr12:$src2), + "a\t{$dst, $src2}", + [(set GR32:$dst, (add GR32:$src1, (load rriaddr12:$src2))), + (implicit PSW)]>; +def ADD32rmy : RXYI<0xE35A, (outs GR32:$dst), (ins GR32:$src1, rriaddr:$src2), + "ay\t{$dst, $src2}", + [(set GR32:$dst, (add GR32:$src1, (load rriaddr:$src2))), + (implicit PSW)]>; +def ADD64rm : RXYI<0xE308, (outs GR64:$dst), (ins GR64:$src1, rriaddr:$src2), + "ag\t{$dst, $src2}", + [(set GR64:$dst, (add GR64:$src1, (load rriaddr:$src2))), + (implicit PSW)]>; + + +def ADD32ri16 : RII<0xA7A, + (outs GR32:$dst), (ins GR32:$src1, s16imm:$src2), + "ahi\t{$dst, $src2}", + [(set GR32:$dst, (add GR32:$src1, immSExt16:$src2)), + (implicit PSW)]>; +def ADD32ri : RILI<0xC29, + (outs GR32:$dst), (ins GR32:$src1, s32imm:$src2), + "afi\t{$dst, $src2}", + [(set GR32:$dst, (add GR32:$src1, imm:$src2)), + (implicit PSW)]>; +def ADD64ri16 : RILI<0xA7B, + (outs GR64:$dst), (ins GR64:$src1, s16imm64:$src2), + "aghi\t{$dst, $src2}", + [(set GR64:$dst, (add GR64:$src1, immSExt16:$src2)), + (implicit PSW)]>; +def ADD64ri32 : RILI<0xC28, + (outs GR64:$dst), (ins GR64:$src1, s32imm64:$src2), + "agfi\t{$dst, $src2}", + [(set GR64:$dst, (add GR64:$src1, immSExt32:$src2)), + (implicit PSW)]>; + +let isCommutable = 1 in { // X = ADC Y, Z == X = ADC Z, Y +def ADC32rr : RRI<0x1E, (outs GR32:$dst), (ins GR32:$src1, GR32:$src2), + "alr\t{$dst, $src2}", + [(set GR32:$dst, (addc GR32:$src1, GR32:$src2))]>; +def ADC64rr : RREI<0xB90A, (outs GR64:$dst), (ins GR64:$src1, GR64:$src2), + "algr\t{$dst, $src2}", + [(set GR64:$dst, (addc GR64:$src1, GR64:$src2))]>; +} + +def ADC32ri : RILI<0xC2B, + (outs GR32:$dst), (ins GR32:$src1, s32imm:$src2), + "alfi\t{$dst, $src2}", + [(set GR32:$dst, (addc GR32:$src1, imm:$src2))]>; +def ADC64ri32 : RILI<0xC2A, + (outs GR64:$dst), (ins GR64:$src1, s32imm64:$src2), + "algfi\t{$dst, $src2}", + [(set GR64:$dst, (addc GR64:$src1, immSExt32:$src2))]>; + +let Uses = [PSW] in { +def ADDE32rr : RREI<0xB998, (outs GR32:$dst), (ins GR32:$src1, GR32:$src2), + "alcr\t{$dst, $src2}", + [(set GR32:$dst, (adde GR32:$src1, GR32:$src2)), + (implicit PSW)]>; +def ADDE64rr : RREI<0xB988, (outs GR64:$dst), (ins GR64:$src1, GR64:$src2), + "alcgr\t{$dst, $src2}", + [(set GR64:$dst, (adde GR64:$src1, GR64:$src2)), + (implicit PSW)]>; +} + +let isCommutable = 1 in { // X = AND Y, Z == X = AND Z, Y +def AND32rr : RRI<0x14, + (outs GR32:$dst), (ins GR32:$src1, GR32:$src2), + "nr\t{$dst, $src2}", + [(set GR32:$dst, (and GR32:$src1, GR32:$src2))]>; +def AND64rr : RREI<0xB980, + (outs GR64:$dst), (ins GR64:$src1, GR64:$src2), + "ngr\t{$dst, $src2}", + [(set GR64:$dst, (and GR64:$src1, GR64:$src2))]>; +} + +def AND32rm : RXI<0x54, (outs GR32:$dst), (ins GR32:$src1, rriaddr12:$src2), + "n\t{$dst, $src2}", + [(set GR32:$dst, (and GR32:$src1, (load rriaddr12:$src2))), + (implicit PSW)]>; +def AND32rmy : RXYI<0xE354, (outs GR32:$dst), (ins GR32:$src1, rriaddr:$src2), + "ny\t{$dst, $src2}", + [(set GR32:$dst, (and GR32:$src1, (load rriaddr:$src2))), + (implicit PSW)]>; +def AND64rm : RXYI<0xE360, (outs GR64:$dst), (ins GR64:$src1, rriaddr:$src2), + "ng\t{$dst, $src2}", + [(set GR64:$dst, (and GR64:$src1, (load rriaddr:$src2))), + (implicit PSW)]>; + +def AND32rill16 : RII<0xA57, + (outs GR32:$dst), (ins GR32:$src1, u16imm:$src2), + "nill\t{$dst, $src2}", + [(set GR32:$dst, (and GR32:$src1, i32ll16c:$src2))]>; +def AND64rill16 : RII<0xA57, + (outs GR64:$dst), (ins GR64:$src1, u16imm:$src2), + "nill\t{$dst, $src2}", + [(set GR64:$dst, (and GR64:$src1, i64ll16c:$src2))]>; + +def AND32rilh16 : RII<0xA56, + (outs GR32:$dst), (ins GR32:$src1, u16imm:$src2), + "nilh\t{$dst, $src2}", + [(set GR32:$dst, (and GR32:$src1, i32lh16c:$src2))]>; +def AND64rilh16 : RII<0xA56, + (outs GR64:$dst), (ins GR64:$src1, u16imm:$src2), + "nilh\t{$dst, $src2}", + [(set GR64:$dst, (and GR64:$src1, i64lh16c:$src2))]>; + +def AND64rihl16 : RII<0xA55, + (outs GR64:$dst), (ins GR64:$src1, u16imm:$src2), + "nihl\t{$dst, $src2}", + [(set GR64:$dst, (and GR64:$src1, i64hl16c:$src2))]>; +def AND64rihh16 : RII<0xA54, + (outs GR64:$dst), (ins GR64:$src1, u16imm:$src2), + "nihh\t{$dst, $src2}", + [(set GR64:$dst, (and GR64:$src1, i64hh16c:$src2))]>; + +def AND32ri : RILI<0xC0B, + (outs GR32:$dst), (ins GR32:$src1, u32imm:$src2), + "nilf\t{$dst, $src2}", + [(set GR32:$dst, (and GR32:$src1, imm:$src2))]>; +def AND64rilo32 : RILI<0xC0B, + (outs GR64:$dst), (ins GR64:$src1, u32imm:$src2), + "nilf\t{$dst, $src2}", + [(set GR64:$dst, (and GR64:$src1, i64lo32c:$src2))]>; +def AND64rihi32 : RILI<0xC0A, + (outs GR64:$dst), (ins GR64:$src1, u32imm:$src2), + "nihf\t{$dst, $src2}", + [(set GR64:$dst, (and GR64:$src1, i64hi32c:$src2))]>; + +let isCommutable = 1 in { // X = OR Y, Z == X = OR Z, Y +def OR32rr : RRI<0x16, + (outs GR32:$dst), (ins GR32:$src1, GR32:$src2), + "or\t{$dst, $src2}", + [(set GR32:$dst, (or GR32:$src1, GR32:$src2))]>; +def OR64rr : RREI<0xB981, + (outs GR64:$dst), (ins GR64:$src1, GR64:$src2), + "ogr\t{$dst, $src2}", + [(set GR64:$dst, (or GR64:$src1, GR64:$src2))]>; +} + +def OR32rm : RXI<0x56, (outs GR32:$dst), (ins GR32:$src1, rriaddr12:$src2), + "o\t{$dst, $src2}", + [(set GR32:$dst, (or GR32:$src1, (load rriaddr12:$src2))), + (implicit PSW)]>; +def OR32rmy : RXYI<0xE356, (outs GR32:$dst), (ins GR32:$src1, rriaddr:$src2), + "oy\t{$dst, $src2}", + [(set GR32:$dst, (or GR32:$src1, (load rriaddr:$src2))), + (implicit PSW)]>; +def OR64rm : RXYI<0xE381, (outs GR64:$dst), (ins GR64:$src1, rriaddr:$src2), + "og\t{$dst, $src2}", + [(set GR64:$dst, (or GR64:$src1, (load rriaddr:$src2))), + (implicit PSW)]>; + + // FIXME: Provide proper encoding! +def OR32ri16 : RII<0xA5B, + (outs GR32:$dst), (ins GR32:$src1, u32imm:$src2), + "oill\t{$dst, $src2}", + [(set GR32:$dst, (or GR32:$src1, i32ll16:$src2))]>; +def OR32ri16h : RII<0xA5A, + (outs GR32:$dst), (ins GR32:$src1, u32imm:$src2), + "oilh\t{$dst, $src2}", + [(set GR32:$dst, (or GR32:$src1, i32lh16:$src2))]>; +def OR32ri : RILI<0xC0D, + (outs GR32:$dst), (ins GR32:$src1, u32imm:$src2), + "oilf\t{$dst, $src2}", + [(set GR32:$dst, (or GR32:$src1, imm:$src2))]>; + +def OR64rill16 : RII<0xA5B, + (outs GR64:$dst), (ins GR64:$src1, u16imm:$src2), + "oill\t{$dst, $src2}", + [(set GR64:$dst, (or GR64:$src1, i64ll16:$src2))]>; +def OR64rilh16 : RII<0xA5A, + (outs GR64:$dst), (ins GR64:$src1, u16imm:$src2), + "oilh\t{$dst, $src2}", + [(set GR64:$dst, (or GR64:$src1, i64lh16:$src2))]>; +def OR64rihl16 : RII<0xA59, + (outs GR64:$dst), (ins GR64:$src1, u16imm:$src2), + "oihl\t{$dst, $src2}", + [(set GR64:$dst, (or GR64:$src1, i64hl16:$src2))]>; +def OR64rihh16 : RII<0xA58, + (outs GR64:$dst), (ins GR64:$src1, u16imm:$src2), + "oihh\t{$dst, $src2}", + [(set GR64:$dst, (or GR64:$src1, i64hh16:$src2))]>; + +def OR64rilo32 : RILI<0xC0D, + (outs GR64:$dst), (ins GR64:$src1, u32imm:$src2), + "oilf\t{$dst, $src2}", + [(set GR64:$dst, (or GR64:$src1, i64lo32:$src2))]>; +def OR64rihi32 : RILI<0xC0C, + (outs GR64:$dst), (ins GR64:$src1, u32imm:$src2), + "oihf\t{$dst, $src2}", + [(set GR64:$dst, (or GR64:$src1, i64hi32:$src2))]>; + +def SUB32rr : RRI<0x1B, + (outs GR32:$dst), (ins GR32:$src1, GR32:$src2), + "sr\t{$dst, $src2}", + [(set GR32:$dst, (sub GR32:$src1, GR32:$src2))]>; +def SUB64rr : RREI<0xB909, + (outs GR64:$dst), (ins GR64:$src1, GR64:$src2), + "sgr\t{$dst, $src2}", + [(set GR64:$dst, (sub GR64:$src1, GR64:$src2))]>; + +def SUB32rm : RXI<0x5B, (outs GR32:$dst), (ins GR32:$src1, rriaddr12:$src2), + "s\t{$dst, $src2}", + [(set GR32:$dst, (sub GR32:$src1, (load rriaddr12:$src2))), + (implicit PSW)]>; +def SUB32rmy : RXYI<0xE35B, (outs GR32:$dst), (ins GR32:$src1, rriaddr:$src2), + "sy\t{$dst, $src2}", + [(set GR32:$dst, (sub GR32:$src1, (load rriaddr:$src2))), + (implicit PSW)]>; +def SUB64rm : RXYI<0xE309, (outs GR64:$dst), (ins GR64:$src1, rriaddr:$src2), + "sg\t{$dst, $src2}", + [(set GR64:$dst, (sub GR64:$src1, (load rriaddr:$src2))), + (implicit PSW)]>; + +def SBC32rr : RRI<0x1F, + (outs GR32:$dst), (ins GR32:$src1, GR32:$src2), + "slr\t{$dst, $src2}", + [(set GR32:$dst, (subc GR32:$src1, GR32:$src2))]>; +def SBC64rr : RREI<0xB90B, + (outs GR64:$dst), (ins GR64:$src1, GR64:$src2), + "slgr\t{$dst, $src2}", + [(set GR64:$dst, (subc GR64:$src1, GR64:$src2))]>; + +def SBC32ri : RILI<0xC25, + (outs GR32:$dst), (ins GR32:$src1, s32imm:$src2), + "sllfi\t{$dst, $src2}", + [(set GR32:$dst, (subc GR32:$src1, imm:$src2))]>; +def SBC64ri32 : RILI<0xC24, + (outs GR64:$dst), (ins GR64:$src1, s32imm64:$src2), + "slgfi\t{$dst, $src2}", + [(set GR64:$dst, (subc GR64:$src1, immSExt32:$src2))]>; + +let Uses = [PSW] in { +def SUBE32rr : RREI<0xB999, (outs GR32:$dst), (ins GR32:$src1, GR32:$src2), + "slbr\t{$dst, $src2}", + [(set GR32:$dst, (sube GR32:$src1, GR32:$src2)), + (implicit PSW)]>; +def SUBE64rr : RREI<0xB989, (outs GR64:$dst), (ins GR64:$src1, GR64:$src2), + "slbgr\t{$dst, $src2}", + [(set GR64:$dst, (sube GR64:$src1, GR64:$src2)), + (implicit PSW)]>; +} + +let isCommutable = 1 in { // X = XOR Y, Z == X = XOR Z, Y +def XOR32rr : RRI<0x17, + (outs GR32:$dst), (ins GR32:$src1, GR32:$src2), + "xr\t{$dst, $src2}", + [(set GR32:$dst, (xor GR32:$src1, GR32:$src2))]>; +def XOR64rr : RREI<0xB982, + (outs GR64:$dst), (ins GR64:$src1, GR64:$src2), + "xgr\t{$dst, $src2}", + [(set GR64:$dst, (xor GR64:$src1, GR64:$src2))]>; +} + +def XOR32rm : RXI<0x57,(outs GR32:$dst), (ins GR32:$src1, rriaddr12:$src2), + "x\t{$dst, $src2}", + [(set GR32:$dst, (xor GR32:$src1, (load rriaddr12:$src2))), + (implicit PSW)]>; +def XOR32rmy : RXYI<0xE357, (outs GR32:$dst), (ins GR32:$src1, rriaddr:$src2), + "xy\t{$dst, $src2}", + [(set GR32:$dst, (xor GR32:$src1, (load rriaddr:$src2))), + (implicit PSW)]>; +def XOR64rm : RXYI<0xE382, (outs GR64:$dst), (ins GR64:$src1, rriaddr:$src2), + "xg\t{$dst, $src2}", + [(set GR64:$dst, (xor GR64:$src1, (load rriaddr:$src2))), + (implicit PSW)]>; + +def XOR32ri : RILI<0xC07, + (outs GR32:$dst), (ins GR32:$src1, i32imm:$src2), + "xilf\t{$dst, $src2}", + [(set GR32:$dst, (xor GR32:$src1, imm:$src2))]>; + +} // Defs = [PSW] + +let isCommutable = 1 in { // X = MUL Y, Z == X = MUL Z, Y +def MUL32rr : RREI<0xB252, + (outs GR32:$dst), (ins GR32:$src1, GR32:$src2), + "msr\t{$dst, $src2}", + [(set GR32:$dst, (mul GR32:$src1, GR32:$src2))]>; +def MUL64rr : RREI<0xB90C, + (outs GR64:$dst), (ins GR64:$src1, GR64:$src2), + "msgr\t{$dst, $src2}", + [(set GR64:$dst, (mul GR64:$src1, GR64:$src2))]>; +} + +def MUL64rrP : RRI<0x1C, + (outs GR64P:$dst), (ins GR64P:$src1, GR32:$src2), + "mr\t{$dst, $src2}", + []>; +def UMUL64rrP : RREI<0xB996, + (outs GR64P:$dst), (ins GR64P:$src1, GR32:$src2), + "mlr\t{$dst, $src2}", + []>; +def UMUL128rrP : RREI<0xB986, + (outs GR128:$dst), (ins GR128:$src1, GR64:$src2), + "mlgr\t{$dst, $src2}", + []>; + +def MUL32ri16 : RII<0xA7C, + (outs GR32:$dst), (ins GR32:$src1, s16imm:$src2), + "mhi\t{$dst, $src2}", + [(set GR32:$dst, (mul GR32:$src1, i32immSExt16:$src2))]>; +def MUL64ri16 : RII<0xA7D, + (outs GR64:$dst), (ins GR64:$src1, s16imm64:$src2), + "mghi\t{$dst, $src2}", + [(set GR64:$dst, (mul GR64:$src1, immSExt16:$src2))]>; + +let AddedComplexity = 2 in { +def MUL32ri : RILI<0xC21, + (outs GR32:$dst), (ins GR32:$src1, s32imm:$src2), + "msfi\t{$dst, $src2}", + [(set GR32:$dst, (mul GR32:$src1, imm:$src2))]>, + Requires<[IsZ10]>; +def MUL64ri32 : RILI<0xC20, + (outs GR64:$dst), (ins GR64:$src1, s32imm64:$src2), + "msgfi\t{$dst, $src2}", + [(set GR64:$dst, (mul GR64:$src1, i64immSExt32:$src2))]>, + Requires<[IsZ10]>; +} + +def MUL32rm : RXI<0x71, + (outs GR32:$dst), (ins GR32:$src1, rriaddr12:$src2), + "ms\t{$dst, $src2}", + [(set GR32:$dst, (mul GR32:$src1, (load rriaddr12:$src2)))]>; +def MUL32rmy : RXYI<0xE351, + (outs GR32:$dst), (ins GR32:$src1, rriaddr:$src2), + "msy\t{$dst, $src2}", + [(set GR32:$dst, (mul GR32:$src1, (load rriaddr:$src2)))]>; +def MUL64rm : RXYI<0xE30C, + (outs GR64:$dst), (ins GR64:$src1, rriaddr:$src2), + "msg\t{$dst, $src2}", + [(set GR64:$dst, (mul GR64:$src1, (load rriaddr:$src2)))]>; + +def MULSX64rr32 : RREI<0xB91C, + (outs GR64:$dst), (ins GR64:$src1, GR32:$src2), + "msgfr\t{$dst, $src2}", + [(set GR64:$dst, (mul GR64:$src1, (sext GR32:$src2)))]>; + +def SDIVREM32r : RREI<0xB91D, + (outs GR128:$dst), (ins GR128:$src1, GR32:$src2), + "dsgfr\t{$dst, $src2}", + []>; +def SDIVREM64r : RREI<0xB90D, + (outs GR128:$dst), (ins GR128:$src1, GR64:$src2), + "dsgr\t{$dst, $src2}", + []>; + +def UDIVREM32r : RREI<0xB997, + (outs GR64P:$dst), (ins GR64P:$src1, GR32:$src2), + "dlr\t{$dst, $src2}", + []>; +def UDIVREM64r : RREI<0xB987, + (outs GR128:$dst), (ins GR128:$src1, GR64:$src2), + "dlgr\t{$dst, $src2}", + []>; +let mayLoad = 1 in { +def SDIVREM32m : RXYI<0xE31D, + (outs GR128:$dst), (ins GR128:$src1, rriaddr:$src2), + "dsgf\t{$dst, $src2}", + []>; +def SDIVREM64m : RXYI<0xE30D, + (outs GR128:$dst), (ins GR128:$src1, rriaddr:$src2), + "dsg\t{$dst, $src2}", + []>; + +def UDIVREM32m : RXYI<0xE397, (outs GR64P:$dst), (ins GR64P:$src1, rriaddr:$src2), + "dl\t{$dst, $src2}", + []>; +def UDIVREM64m : RXYI<0xE387, (outs GR128:$dst), (ins GR128:$src1, rriaddr:$src2), + "dlg\t{$dst, $src2}", + []>; +} // mayLoad +} // Constraints = "$src1 = $dst" + +//===----------------------------------------------------------------------===// +// Shifts + +let Constraints = "$src = $dst" in +def SRL32rri : RSI<0x88, + (outs GR32:$dst), (ins GR32:$src, riaddr32:$amt), + "srl\t{$src, $amt}", + [(set GR32:$dst, (srl GR32:$src, riaddr32:$amt))]>; +def SRL64rri : RSYI<0xEB0C, + (outs GR64:$dst), (ins GR64:$src, riaddr:$amt), + "srlg\t{$dst, $src, $amt}", + [(set GR64:$dst, (srl GR64:$src, riaddr:$amt))]>; + +let Constraints = "$src = $dst" in +def SHL32rri : RSI<0x89, + (outs GR32:$dst), (ins GR32:$src, riaddr32:$amt), + "sll\t{$src, $amt}", + [(set GR32:$dst, (shl GR32:$src, riaddr32:$amt))]>; +def SHL64rri : RSYI<0xEB0D, + (outs GR64:$dst), (ins GR64:$src, riaddr:$amt), + "sllg\t{$dst, $src, $amt}", + [(set GR64:$dst, (shl GR64:$src, riaddr:$amt))]>; + +let Defs = [PSW] in { +let Constraints = "$src = $dst" in +def SRA32rri : RSI<0x8A, + (outs GR32:$dst), (ins GR32:$src, riaddr32:$amt), + "sra\t{$src, $amt}", + [(set GR32:$dst, (sra GR32:$src, riaddr32:$amt)), + (implicit PSW)]>; + +def SRA64rri : RSYI<0xEB0A, + (outs GR64:$dst), (ins GR64:$src, riaddr:$amt), + "srag\t{$dst, $src, $amt}", + [(set GR64:$dst, (sra GR64:$src, riaddr:$amt)), + (implicit PSW)]>; +} // Defs = [PSW] + +def ROTL32rri : RSYI<0xEB1D, + (outs GR32:$dst), (ins GR32:$src, riaddr32:$amt), + "rll\t{$dst, $src, $amt}", + [(set GR32:$dst, (rotl GR32:$src, riaddr32:$amt))]>; +def ROTL64rri : RSYI<0xEB1C, + (outs GR64:$dst), (ins GR64:$src, riaddr:$amt), + "rllg\t{$dst, $src, $amt}", + [(set GR64:$dst, (rotl GR64:$src, riaddr:$amt))]>; + +//===----------------------------------------------------------------------===// +// Test instructions (like AND but do not produce any result) + +// Integer comparisons +let Defs = [PSW] in { +def CMP32rr : RRI<0x19, + (outs), (ins GR32:$src1, GR32:$src2), + "cr\t$src1, $src2", + [(set PSW, (SystemZcmp GR32:$src1, GR32:$src2))]>; +def CMP64rr : RREI<0xB920, + (outs), (ins GR64:$src1, GR64:$src2), + "cgr\t$src1, $src2", + [(set PSW, (SystemZcmp GR64:$src1, GR64:$src2))]>; + +def CMP32ri : RILI<0xC2D, + (outs), (ins GR32:$src1, s32imm:$src2), + "cfi\t$src1, $src2", + [(set PSW, (SystemZcmp GR32:$src1, imm:$src2))]>; +def CMP64ri32 : RILI<0xC2C, + (outs), (ins GR64:$src1, s32imm64:$src2), + "cgfi\t$src1, $src2", + [(set PSW, (SystemZcmp GR64:$src1, i64immSExt32:$src2))]>; + +def CMP32rm : RXI<0x59, + (outs), (ins GR32:$src1, rriaddr12:$src2), + "c\t$src1, $src2", + [(set PSW, (SystemZcmp GR32:$src1, (load rriaddr12:$src2)))]>; +def CMP32rmy : RXYI<0xE359, + (outs), (ins GR32:$src1, rriaddr:$src2), + "cy\t$src1, $src2", + [(set PSW, (SystemZcmp GR32:$src1, (load rriaddr:$src2)))]>; +def CMP64rm : RXYI<0xE320, + (outs), (ins GR64:$src1, rriaddr:$src2), + "cg\t$src1, $src2", + [(set PSW, (SystemZcmp GR64:$src1, (load rriaddr:$src2)))]>; + +def UCMP32rr : RRI<0x15, + (outs), (ins GR32:$src1, GR32:$src2), + "clr\t$src1, $src2", + [(set PSW, (SystemZucmp GR32:$src1, GR32:$src2))]>; +def UCMP64rr : RREI<0xB921, + (outs), (ins GR64:$src1, GR64:$src2), + "clgr\t$src1, $src2", + [(set PSW, (SystemZucmp GR64:$src1, GR64:$src2))]>; + +def UCMP32ri : RILI<0xC2F, + (outs), (ins GR32:$src1, i32imm:$src2), + "clfi\t$src1, $src2", + [(set PSW, (SystemZucmp GR32:$src1, imm:$src2))]>; +def UCMP64ri32 : RILI<0xC2E, + (outs), (ins GR64:$src1, i64i32imm:$src2), + "clgfi\t$src1, $src2", + [(set PSW,(SystemZucmp GR64:$src1, i64immZExt32:$src2))]>; + +def UCMP32rm : RXI<0x55, + (outs), (ins GR32:$src1, rriaddr12:$src2), + "cl\t$src1, $src2", + [(set PSW, (SystemZucmp GR32:$src1, + (load rriaddr12:$src2)))]>; +def UCMP32rmy : RXYI<0xE355, + (outs), (ins GR32:$src1, rriaddr:$src2), + "cly\t$src1, $src2", + [(set PSW, (SystemZucmp GR32:$src1, + (load rriaddr:$src2)))]>; +def UCMP64rm : RXYI<0xE351, + (outs), (ins GR64:$src1, rriaddr:$src2), + "clg\t$src1, $src2", + [(set PSW, (SystemZucmp GR64:$src1, + (load rriaddr:$src2)))]>; + +def CMPSX64rr32 : RREI<0xB930, + (outs), (ins GR64:$src1, GR32:$src2), + "cgfr\t$src1, $src2", + [(set PSW, (SystemZucmp GR64:$src1, + (sext GR32:$src2)))]>; +def UCMPZX64rr32 : RREI<0xB931, + (outs), (ins GR64:$src1, GR32:$src2), + "clgfr\t$src1, $src2", + [(set PSW, (SystemZucmp GR64:$src1, + (zext GR32:$src2)))]>; + +def CMPSX64rm32 : RXYI<0xE330, + (outs), (ins GR64:$src1, rriaddr:$src2), + "cgf\t$src1, $src2", + [(set PSW, (SystemZucmp GR64:$src1, + (sextloadi64i32 rriaddr:$src2)))]>; +def UCMPZX64rm32 : RXYI<0xE331, + (outs), (ins GR64:$src1, rriaddr:$src2), + "clgf\t$src1, $src2", + [(set PSW, (SystemZucmp GR64:$src1, + (zextloadi64i32 rriaddr:$src2)))]>; + +// FIXME: Add other crazy ucmp forms + +} // Defs = [PSW] + +//===----------------------------------------------------------------------===// +// Other crazy stuff +let Defs = [PSW] in { +def FLOGR64 : RREI<0xB983, + (outs GR128:$dst), (ins GR64:$src), + "flogr\t{$dst, $src}", + []>; +} // Defs = [PSW] + +//===----------------------------------------------------------------------===// +// Non-Instruction Patterns. +//===----------------------------------------------------------------------===// + +// ConstPools, JumpTables +def : Pat<(SystemZpcrelwrapper tjumptable:$src), (LA64rm tjumptable:$src)>; +def : Pat<(SystemZpcrelwrapper tconstpool:$src), (LA64rm tconstpool:$src)>; + +// anyext +def : Pat<(i64 (anyext GR32:$src)), + (INSERT_SUBREG (i64 (IMPLICIT_DEF)), GR32:$src, subreg_32bit)>; + +// calls +def : Pat<(SystemZcall (i64 tglobaladdr:$dst)), (CALLi tglobaladdr:$dst)>; +def : Pat<(SystemZcall (i64 texternalsym:$dst)), (CALLi texternalsym:$dst)>; + +//===----------------------------------------------------------------------===// +// Peepholes. +//===----------------------------------------------------------------------===// + +// FIXME: use add/sub tricks with 32678/-32768 + +// Arbitrary immediate support. +def : Pat<(i32 imm:$src), + (EXTRACT_SUBREG (MOV64ri32 (GetI64FromI32 (i32 imm:$src))), + subreg_32bit)>; + +// Implement in terms of LLIHF/OILF. +def : Pat<(i64 imm:$imm), + (OR64rilo32 (MOV64rihi32 (HI32 imm:$imm)), (LO32 imm:$imm))>; + +// trunc patterns +def : Pat<(i32 (trunc GR64:$src)), + (EXTRACT_SUBREG GR64:$src, subreg_32bit)>; + +// sext_inreg patterns +def : Pat<(sext_inreg GR64:$src, i32), + (MOVSX64rr32 (EXTRACT_SUBREG GR64:$src, subreg_32bit))>; + +// extload patterns +def : Pat<(extloadi32i8 rriaddr:$src), (MOVZX32rm8 rriaddr:$src)>; +def : Pat<(extloadi32i16 rriaddr:$src), (MOVZX32rm16 rriaddr:$src)>; +def : Pat<(extloadi64i8 rriaddr:$src), (MOVZX64rm8 rriaddr:$src)>; +def : Pat<(extloadi64i16 rriaddr:$src), (MOVZX64rm16 rriaddr:$src)>; +def : Pat<(extloadi64i32 rriaddr:$src), (MOVZX64rm32 rriaddr:$src)>; + +// muls +def : Pat<(mulhs GR32:$src1, GR32:$src2), + (EXTRACT_SUBREG (MUL64rrP (INSERT_SUBREG (v2i32 (IMPLICIT_DEF)), + GR32:$src1, subreg_odd32), + GR32:$src2), + subreg_32bit)>; + +def : Pat<(mulhu GR32:$src1, GR32:$src2), + (EXTRACT_SUBREG (UMUL64rrP (INSERT_SUBREG (v2i32 (IMPLICIT_DEF)), + GR32:$src1, subreg_odd32), + GR32:$src2), + subreg_32bit)>; +def : Pat<(mulhu GR64:$src1, GR64:$src2), + (EXTRACT_SUBREG (UMUL128rrP (INSERT_SUBREG (v2i64 (IMPLICIT_DEF)), + GR64:$src1, subreg_odd), + GR64:$src2), + subreg_even)>; + +def : Pat<(ctlz GR64:$src), + (EXTRACT_SUBREG (FLOGR64 GR64:$src), subreg_even)>; diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h b/contrib/llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h new file mode 100644 index 0000000..fd6e330 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h @@ -0,0 +1,51 @@ +//==- SystemZMachineFuctionInfo.h - SystemZ machine function info -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares SystemZ-specific per-machine-function information. +// +//===----------------------------------------------------------------------===// + +#ifndef SYSTEMZMACHINEFUNCTIONINFO_H +#define SYSTEMZMACHINEFUNCTIONINFO_H + +#include "llvm/CodeGen/MachineFunction.h" + +namespace llvm { + +/// SystemZMachineFunctionInfo - This class is derived from MachineFunction and +/// contains private SystemZ target-specific information for each MachineFunction. +class SystemZMachineFunctionInfo : public MachineFunctionInfo { + /// CalleeSavedFrameSize - Size of the callee-saved register portion of the + /// stack frame in bytes. + unsigned CalleeSavedFrameSize; + + /// LowReg - Low register of range of callee-saved registers to store. + unsigned LowReg; + + /// HighReg - High register of range of callee-saved registers to store. + unsigned HighReg; +public: + SystemZMachineFunctionInfo() : CalleeSavedFrameSize(0) {} + + explicit SystemZMachineFunctionInfo(MachineFunction &MF) + : CalleeSavedFrameSize(0) {} + + unsigned getCalleeSavedFrameSize() const { return CalleeSavedFrameSize; } + void setCalleeSavedFrameSize(unsigned bytes) { CalleeSavedFrameSize = bytes; } + + unsigned getLowReg() const { return LowReg; } + void setLowReg(unsigned Reg) { LowReg = Reg; } + + unsigned getHighReg() const { return HighReg; } + void setHighReg(unsigned Reg) { HighReg = Reg; } +}; + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZOperands.td b/contrib/llvm/lib/Target/SystemZ/SystemZOperands.td new file mode 100644 index 0000000..8b835cc --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZOperands.td @@ -0,0 +1,325 @@ +//=====- SystemZOperands.td - SystemZ Operands defs ---------*- tblgen-*-=====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the various SystemZ instruction operands. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Instruction Pattern Stuff. +//===----------------------------------------------------------------------===// + +// SystemZ specific condition code. These correspond to CondCode in +// SystemZ.h. They must be kept in synch. +def SYSTEMZ_COND_O : PatLeaf<(i8 0)>; +def SYSTEMZ_COND_H : PatLeaf<(i8 1)>; +def SYSTEMZ_COND_NLE : PatLeaf<(i8 2)>; +def SYSTEMZ_COND_L : PatLeaf<(i8 3)>; +def SYSTEMZ_COND_NHE : PatLeaf<(i8 4)>; +def SYSTEMZ_COND_LH : PatLeaf<(i8 5)>; +def SYSTEMZ_COND_NE : PatLeaf<(i8 6)>; +def SYSTEMZ_COND_E : PatLeaf<(i8 7)>; +def SYSTEMZ_COND_NLH : PatLeaf<(i8 8)>; +def SYSTEMZ_COND_HE : PatLeaf<(i8 9)>; +def SYSTEMZ_COND_NL : PatLeaf<(i8 10)>; +def SYSTEMZ_COND_LE : PatLeaf<(i8 11)>; +def SYSTEMZ_COND_NH : PatLeaf<(i8 12)>; +def SYSTEMZ_COND_NO : PatLeaf<(i8 13)>; + +def LO8 : SDNodeXForm<imm, [{ + // Transformation function: return low 8 bits. + return getI8Imm(N->getZExtValue() & 0x00000000000000FFULL); +}]>; + +def LL16 : SDNodeXForm<imm, [{ + // Transformation function: return low 16 bits. + return getI16Imm(N->getZExtValue() & 0x000000000000FFFFULL); +}]>; + +def LH16 : SDNodeXForm<imm, [{ + // Transformation function: return bits 16-31. + return getI16Imm((N->getZExtValue() & 0x00000000FFFF0000ULL) >> 16); +}]>; + +def HL16 : SDNodeXForm<imm, [{ + // Transformation function: return bits 32-47. + return getI16Imm((N->getZExtValue() & 0x0000FFFF00000000ULL) >> 32); +}]>; + +def HH16 : SDNodeXForm<imm, [{ + // Transformation function: return bits 48-63. + return getI16Imm((N->getZExtValue() & 0xFFFF000000000000ULL) >> 48); +}]>; + +def LO32 : SDNodeXForm<imm, [{ + // Transformation function: return low 32 bits. + return getI32Imm(N->getZExtValue() & 0x00000000FFFFFFFFULL); +}]>; + +def HI32 : SDNodeXForm<imm, [{ + // Transformation function: return bits 32-63. + return getI32Imm(N->getZExtValue() >> 32); +}]>; + +def GetI64FromI32 : SDNodeXForm<imm, [{ + return CurDAG->getTargetConstant(N->getSExtValue(), MVT::i64); +}]>; + +def i32ll16 : PatLeaf<(i32 imm), [{ + // i32ll16 predicate - true if the 32-bit immediate has only rightmost 16 + // bits set. + return ((N->getZExtValue() & 0x000000000000FFFFULL) == N->getZExtValue()); +}], LL16>; + +def i32lh16 : PatLeaf<(i32 imm), [{ + // i32lh16 predicate - true if the 32-bit immediate has only bits 16-31 set. + return ((N->getZExtValue() & 0x00000000FFFF0000ULL) == N->getZExtValue()); +}], LH16>; + +def i32ll16c : PatLeaf<(i32 imm), [{ + // i32ll16c predicate - true if the 32-bit immediate has all bits 16-31 set. + return ((N->getZExtValue() | 0x00000000FFFF0000ULL) == N->getZExtValue()); +}], LL16>; + +def i32lh16c : PatLeaf<(i32 imm), [{ + // i32lh16c predicate - true if the 32-bit immediate has all rightmost 16 + // bits set. + return ((N->getZExtValue() | 0x000000000000FFFFULL) == N->getZExtValue()); +}], LH16>; + +def i64ll16 : PatLeaf<(i64 imm), [{ + // i64ll16 predicate - true if the 64-bit immediate has only rightmost 16 + // bits set. + return ((N->getZExtValue() & 0x000000000000FFFFULL) == N->getZExtValue()); +}], LL16>; + +def i64lh16 : PatLeaf<(i64 imm), [{ + // i64lh16 predicate - true if the 64-bit immediate has only bits 16-31 set. + return ((N->getZExtValue() & 0x00000000FFFF0000ULL) == N->getZExtValue()); +}], LH16>; + +def i64hl16 : PatLeaf<(i64 imm), [{ + // i64hl16 predicate - true if the 64-bit immediate has only bits 32-47 set. + return ((N->getZExtValue() & 0x0000FFFF00000000ULL) == N->getZExtValue()); +}], HL16>; + +def i64hh16 : PatLeaf<(i64 imm), [{ + // i64hh16 predicate - true if the 64-bit immediate has only bits 48-63 set. + return ((N->getZExtValue() & 0xFFFF000000000000ULL) == N->getZExtValue()); +}], HH16>; + +def i64ll16c : PatLeaf<(i64 imm), [{ + // i64ll16c predicate - true if the 64-bit immediate has only rightmost 16 + // bits set. + return ((N->getZExtValue() | 0xFFFFFFFFFFFF0000ULL) == N->getZExtValue()); +}], LL16>; + +def i64lh16c : PatLeaf<(i64 imm), [{ + // i64lh16c predicate - true if the 64-bit immediate has only bits 16-31 set. + return ((N->getZExtValue() | 0xFFFFFFFF0000FFFFULL) == N->getZExtValue()); +}], LH16>; + +def i64hl16c : PatLeaf<(i64 imm), [{ + // i64hl16c predicate - true if the 64-bit immediate has only bits 32-47 set. + return ((N->getZExtValue() | 0xFFFF0000FFFFFFFFULL) == N->getZExtValue()); +}], HL16>; + +def i64hh16c : PatLeaf<(i64 imm), [{ + // i64hh16c predicate - true if the 64-bit immediate has only bits 48-63 set. + return ((N->getZExtValue() | 0x0000FFFFFFFFFFFFULL) == N->getZExtValue()); +}], HH16>; + +def immSExt16 : PatLeaf<(imm), [{ + // immSExt16 predicate - true if the immediate fits in a 16-bit sign extended + // field. + if (N->getValueType(0) == MVT::i64) { + uint64_t val = N->getZExtValue(); + return ((int64_t)val == (int16_t)val); + } else if (N->getValueType(0) == MVT::i32) { + uint32_t val = N->getZExtValue(); + return ((int32_t)val == (int16_t)val); + } + + return false; +}], LL16>; + +def immSExt32 : PatLeaf<(i64 imm), [{ + // immSExt32 predicate - true if the immediate fits in a 32-bit sign extended + // field. + uint64_t val = N->getZExtValue(); + return ((int64_t)val == (int32_t)val); +}], LO32>; + +def i64lo32 : PatLeaf<(i64 imm), [{ + // i64lo32 predicate - true if the 64-bit immediate has only rightmost 32 + // bits set. + return ((N->getZExtValue() & 0x00000000FFFFFFFFULL) == N->getZExtValue()); +}], LO32>; + +def i64hi32 : PatLeaf<(i64 imm), [{ + // i64hi32 predicate - true if the 64-bit immediate has only bits 32-63 set. + return ((N->getZExtValue() & 0xFFFFFFFF00000000ULL) == N->getZExtValue()); +}], HI32>; + +def i64lo32c : PatLeaf<(i64 imm), [{ + // i64lo32 predicate - true if the 64-bit immediate has only rightmost 32 + // bits set. + return ((N->getZExtValue() | 0xFFFFFFFF00000000ULL) == N->getZExtValue()); +}], LO32>; + +def i64hi32c : PatLeaf<(i64 imm), [{ + // i64hi32 predicate - true if the 64-bit immediate has only bits 32-63 set. + return ((N->getZExtValue() | 0x00000000FFFFFFFFULL) == N->getZExtValue()); +}], HI32>; + +def i32immSExt8 : PatLeaf<(i32 imm), [{ + // i32immSExt8 predicate - True if the 32-bit immediate fits in a 8-bit + // sign extended field. + return (int32_t)N->getZExtValue() == (int8_t)N->getZExtValue(); +}], LO8>; + +def i32immSExt16 : PatLeaf<(i32 imm), [{ + // i32immSExt16 predicate - True if the 32-bit immediate fits in a 16-bit + // sign extended field. + return (int32_t)N->getZExtValue() == (int16_t)N->getZExtValue(); +}], LL16>; + +def i64immSExt32 : PatLeaf<(i64 imm), [{ + // i64immSExt32 predicate - True if the 64-bit immediate fits in a 32-bit + // sign extended field. + return (int64_t)N->getZExtValue() == (int32_t)N->getZExtValue(); +}], LO32>; + +def i64immZExt32 : PatLeaf<(i64 imm), [{ + // i64immZExt32 predicate - True if the 64-bit immediate fits in a 32-bit + // zero extended field. + return (uint64_t)N->getZExtValue() == (uint32_t)N->getZExtValue(); +}], LO32>; + +// extloads +def extloadi32i8 : PatFrag<(ops node:$ptr), (i32 (extloadi8 node:$ptr))>; +def extloadi32i16 : PatFrag<(ops node:$ptr), (i32 (extloadi16 node:$ptr))>; +def extloadi64i8 : PatFrag<(ops node:$ptr), (i64 (extloadi8 node:$ptr))>; +def extloadi64i16 : PatFrag<(ops node:$ptr), (i64 (extloadi16 node:$ptr))>; +def extloadi64i32 : PatFrag<(ops node:$ptr), (i64 (extloadi32 node:$ptr))>; + +def sextloadi32i8 : PatFrag<(ops node:$ptr), (i32 (sextloadi8 node:$ptr))>; +def sextloadi32i16 : PatFrag<(ops node:$ptr), (i32 (sextloadi16 node:$ptr))>; +def sextloadi64i8 : PatFrag<(ops node:$ptr), (i64 (sextloadi8 node:$ptr))>; +def sextloadi64i16 : PatFrag<(ops node:$ptr), (i64 (sextloadi16 node:$ptr))>; +def sextloadi64i32 : PatFrag<(ops node:$ptr), (i64 (sextloadi32 node:$ptr))>; + +def zextloadi32i8 : PatFrag<(ops node:$ptr), (i32 (zextloadi8 node:$ptr))>; +def zextloadi32i16 : PatFrag<(ops node:$ptr), (i32 (zextloadi16 node:$ptr))>; +def zextloadi64i8 : PatFrag<(ops node:$ptr), (i64 (zextloadi8 node:$ptr))>; +def zextloadi64i16 : PatFrag<(ops node:$ptr), (i64 (zextloadi16 node:$ptr))>; +def zextloadi64i32 : PatFrag<(ops node:$ptr), (i64 (zextloadi32 node:$ptr))>; + +// A couple of more descriptive operand definitions. +// 32-bits but only 8 bits are significant. +def i32i8imm : Operand<i32>; +// 32-bits but only 16 bits are significant. +def i32i16imm : Operand<i32>; +// 64-bits but only 32 bits are significant. +def i64i32imm : Operand<i64>; +// Branch targets have OtherVT type. +def brtarget : Operand<OtherVT>; + +// Unsigned i12 +def u12imm : Operand<i32> { + let PrintMethod = "printU12ImmOperand"; +} +def u12imm64 : Operand<i64> { + let PrintMethod = "printU12ImmOperand"; +} + +// Signed i16 +def s16imm : Operand<i32> { + let PrintMethod = "printS16ImmOperand"; +} +def s16imm64 : Operand<i64> { + let PrintMethod = "printS16ImmOperand"; +} +// Unsigned i16 +def u16imm : Operand<i32> { + let PrintMethod = "printU16ImmOperand"; +} +def u16imm64 : Operand<i64> { + let PrintMethod = "printU16ImmOperand"; +} + +// Signed i20 +def s20imm : Operand<i32> { + let PrintMethod = "printS20ImmOperand"; +} +def s20imm64 : Operand<i64> { + let PrintMethod = "printS20ImmOperand"; +} +// Signed i32 +def s32imm : Operand<i32> { + let PrintMethod = "printS32ImmOperand"; +} +def s32imm64 : Operand<i64> { + let PrintMethod = "printS32ImmOperand"; +} +// Unsigned i32 +def u32imm : Operand<i32> { + let PrintMethod = "printU32ImmOperand"; +} +def u32imm64 : Operand<i64> { + let PrintMethod = "printU32ImmOperand"; +} + +def imm_pcrel : Operand<i64> { + let PrintMethod = "printPCRelImmOperand"; +} + +//===----------------------------------------------------------------------===// +// SystemZ Operand Definitions. +//===----------------------------------------------------------------------===// + +// Address operands + +// riaddr := reg + imm +def riaddr32 : Operand<i64>, + ComplexPattern<i64, 2, "SelectAddrRI12Only", []> { + let PrintMethod = "printRIAddrOperand"; + let MIOperandInfo = (ops ADDR64:$base, u12imm:$disp); +} + +def riaddr12 : Operand<i64>, + ComplexPattern<i64, 2, "SelectAddrRI12", []> { + let PrintMethod = "printRIAddrOperand"; + let MIOperandInfo = (ops ADDR64:$base, u12imm64:$disp); +} + +def riaddr : Operand<i64>, + ComplexPattern<i64, 2, "SelectAddrRI", []> { + let PrintMethod = "printRIAddrOperand"; + let MIOperandInfo = (ops ADDR64:$base, s20imm64:$disp); +} + +//===----------------------------------------------------------------------===// + +// rriaddr := reg + reg + imm +def rriaddr12 : Operand<i64>, + ComplexPattern<i64, 3, "SelectAddrRRI12", [], []> { + let PrintMethod = "printRRIAddrOperand"; + let MIOperandInfo = (ops ADDR64:$base, u12imm64:$disp, ADDR64:$index); +} +def rriaddr : Operand<i64>, + ComplexPattern<i64, 3, "SelectAddrRRI20", [], []> { + let PrintMethod = "printRRIAddrOperand"; + let MIOperandInfo = (ops ADDR64:$base, s20imm64:$disp, ADDR64:$index); +} +def laaddr : Operand<i64>, + ComplexPattern<i64, 3, "SelectLAAddr", [add, sub, or, frameindex], []> { + let PrintMethod = "printRRIAddrOperand"; + let MIOperandInfo = (ops ADDR64:$base, s20imm64:$disp, ADDR64:$index); +} diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp new file mode 100644 index 0000000..b1050d4 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp @@ -0,0 +1,143 @@ +//===- SystemZRegisterInfo.cpp - SystemZ Register Information -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the SystemZ implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#include "SystemZ.h" +#include "SystemZInstrInfo.h" +#include "SystemZMachineFunctionInfo.h" +#include "SystemZRegisterInfo.h" +#include "SystemZSubtarget.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/ADT/BitVector.h" + +#define GET_REGINFO_TARGET_DESC +#include "SystemZGenRegisterInfo.inc" + +using namespace llvm; + +SystemZRegisterInfo::SystemZRegisterInfo(SystemZTargetMachine &tm, + const SystemZInstrInfo &tii) + : SystemZGenRegisterInfo(0), TM(tm), TII(tii) { +} + +const unsigned* +SystemZRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + static const unsigned CalleeSavedRegs[] = { + SystemZ::R6D, SystemZ::R7D, SystemZ::R8D, SystemZ::R9D, + SystemZ::R10D, SystemZ::R11D, SystemZ::R12D, SystemZ::R13D, + SystemZ::R14D, SystemZ::R15D, + SystemZ::F8L, SystemZ::F9L, SystemZ::F10L, SystemZ::F11L, + SystemZ::F12L, SystemZ::F13L, SystemZ::F14L, SystemZ::F15L, + 0 + }; + + return CalleeSavedRegs; +} + +BitVector SystemZRegisterInfo::getReservedRegs(const MachineFunction &MF) const { + BitVector Reserved(getNumRegs()); + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + + if (TFI->hasFP(MF)) { + // R11D is the frame pointer. Reserve all aliases. + Reserved.set(SystemZ::R11D); + Reserved.set(SystemZ::R11W); + Reserved.set(SystemZ::R10P); + Reserved.set(SystemZ::R10Q); + } + + Reserved.set(SystemZ::R14D); + Reserved.set(SystemZ::R15D); + Reserved.set(SystemZ::R14W); + Reserved.set(SystemZ::R15W); + Reserved.set(SystemZ::R14P); + Reserved.set(SystemZ::R14Q); + return Reserved; +} + +const TargetRegisterClass* +SystemZRegisterInfo::getMatchingSuperRegClass(const TargetRegisterClass *A, + const TargetRegisterClass *B, + unsigned Idx) const { + switch(Idx) { + // Exact sub-classes don't exist for the other sub-register indexes. + default: return 0; + case SystemZ::subreg_32bit: + if (B == SystemZ::ADDR32RegisterClass) + return A->getSize() == 8 ? SystemZ::ADDR64RegisterClass : 0; + return A; + } +} + +void SystemZRegisterInfo:: +eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + MBB.erase(I); +} + +void +SystemZRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS) const { + assert(SPAdj == 0 && "Unxpected"); + + unsigned i = 0; + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + + while (!MI.getOperand(i).isFI()) { + ++i; + assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!"); + } + + int FrameIndex = MI.getOperand(i).getIndex(); + + unsigned BasePtr = (TFI->hasFP(MF) ? SystemZ::R11D : SystemZ::R15D); + + // This must be part of a rri or ri operand memory reference. Replace the + // FrameIndex with base register with BasePtr. Add an offset to the + // displacement field. + MI.getOperand(i).ChangeToRegister(BasePtr, false); + + // Offset is a either 12-bit unsigned or 20-bit signed integer. + // FIXME: handle "too long" displacements. + int Offset = + TFI->getFrameIndexOffset(MF, FrameIndex) + MI.getOperand(i+1).getImm(); + + // Check whether displacement is too long to fit into 12 bit zext field. + MI.setDesc(TII.getMemoryInstr(MI.getOpcode(), Offset)); + + MI.getOperand(i+1).ChangeToImmediate(Offset); +} + +unsigned +SystemZRegisterInfo::getFrameRegister(const MachineFunction &MF) const { + assert(0 && "What is the frame register"); + return 0; +} + +unsigned SystemZRegisterInfo::getEHExceptionRegister() const { + assert(0 && "What is the exception register"); + return 0; +} + +unsigned SystemZRegisterInfo::getEHHandlerRegister() const { + assert(0 && "What is the exception handler register"); + return 0; +} diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.h b/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.h new file mode 100644 index 0000000..03935b2 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.h @@ -0,0 +1,60 @@ +//===-- SystemZRegisterInfo.h - SystemZ Register Information ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the SystemZ implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef SystemZREGISTERINFO_H +#define SystemZREGISTERINFO_H + +#include "llvm/Target/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "SystemZGenRegisterInfo.inc" + +namespace llvm { + +class SystemZSubtarget; +class SystemZInstrInfo; +class Type; + +struct SystemZRegisterInfo : public SystemZGenRegisterInfo { + SystemZTargetMachine &TM; + const SystemZInstrInfo &TII; + + SystemZRegisterInfo(SystemZTargetMachine &tm, const SystemZInstrInfo &tii); + + /// Code Generation virtual methods... + const unsigned *getCalleeSavedRegs(const MachineFunction *MF = 0) const; + + BitVector getReservedRegs(const MachineFunction &MF) const; + + const TargetRegisterClass* + getMatchingSuperRegClass(const TargetRegisterClass *A, + const TargetRegisterClass *B, unsigned Idx) const; + + void eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; + + // Debug information queries. + unsigned getFrameRegister(const MachineFunction &MF) const; + + // Exception handling queries. + unsigned getEHExceptionRegister() const; + unsigned getEHHandlerRegister() const; +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td b/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td new file mode 100644 index 0000000..a24cbcf --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td @@ -0,0 +1,205 @@ +//===- SystemZRegisterInfo.td - The PowerPC Register File ------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +class SystemZReg<string n> : Register<n> { + let Namespace = "SystemZ"; +} + +class SystemZRegWithSubregs<string n, list<Register> subregs> + : RegisterWithSubRegs<n, subregs> { + let Namespace = "SystemZ"; +} + +// We identify all our registers with a 4-bit ID, for consistency's sake. + +// GPR32 - Lower 32 bits of one of the 16 64-bit general-purpose registers +class GPR32<bits<4> num, string n> : SystemZReg<n> { + field bits<4> Num = num; +} + +// GPR64 - One of the 16 64-bit general-purpose registers +class GPR64<bits<4> num, string n, list<Register> subregs, + list<Register> aliases = []> + : SystemZRegWithSubregs<n, subregs> { + field bits<4> Num = num; + let Aliases = aliases; +} + +// GPR128 - 8 even-odd register pairs +class GPR128<bits<4> num, string n, list<Register> subregs, + list<Register> aliases = []> + : SystemZRegWithSubregs<n, subregs> { + field bits<4> Num = num; + let Aliases = aliases; +} + +// FPRS - Lower 32 bits of one of the 16 64-bit floating-point registers +class FPRS<bits<4> num, string n> : SystemZReg<n> { + field bits<4> Num = num; +} + +// FPRL - One of the 16 64-bit floating-point registers +class FPRL<bits<4> num, string n, list<Register> subregs> + : SystemZRegWithSubregs<n, subregs> { + field bits<4> Num = num; +} + +let Namespace = "SystemZ" in { +def subreg_32bit : SubRegIndex; +def subreg_odd32 : SubRegIndex; +def subreg_even : SubRegIndex; +def subreg_odd : SubRegIndex; +} + +// General-purpose registers +def R0W : GPR32< 0, "r0">; +def R1W : GPR32< 1, "r1">; +def R2W : GPR32< 2, "r2">; +def R3W : GPR32< 3, "r3">; +def R4W : GPR32< 4, "r4">; +def R5W : GPR32< 5, "r5">; +def R6W : GPR32< 6, "r6">; +def R7W : GPR32< 7, "r7">; +def R8W : GPR32< 8, "r8">; +def R9W : GPR32< 9, "r9">; +def R10W : GPR32<10, "r10">; +def R11W : GPR32<11, "r11">; +def R12W : GPR32<12, "r12">; +def R13W : GPR32<13, "r13">; +def R14W : GPR32<14, "r14">; +def R15W : GPR32<15, "r15">; + +let SubRegIndices = [subreg_32bit] in { +def R0D : GPR64< 0, "r0", [R0W]>, DwarfRegNum<[0]>; +def R1D : GPR64< 1, "r1", [R1W]>, DwarfRegNum<[1]>; +def R2D : GPR64< 2, "r2", [R2W]>, DwarfRegNum<[2]>; +def R3D : GPR64< 3, "r3", [R3W]>, DwarfRegNum<[3]>; +def R4D : GPR64< 4, "r4", [R4W]>, DwarfRegNum<[4]>; +def R5D : GPR64< 5, "r5", [R5W]>, DwarfRegNum<[5]>; +def R6D : GPR64< 6, "r6", [R6W]>, DwarfRegNum<[6]>; +def R7D : GPR64< 7, "r7", [R7W]>, DwarfRegNum<[7]>; +def R8D : GPR64< 8, "r8", [R8W]>, DwarfRegNum<[8]>; +def R9D : GPR64< 9, "r9", [R9W]>, DwarfRegNum<[9]>; +def R10D : GPR64<10, "r10", [R10W]>, DwarfRegNum<[10]>; +def R11D : GPR64<11, "r11", [R11W]>, DwarfRegNum<[11]>; +def R12D : GPR64<12, "r12", [R12W]>, DwarfRegNum<[12]>; +def R13D : GPR64<13, "r13", [R13W]>, DwarfRegNum<[13]>; +def R14D : GPR64<14, "r14", [R14W]>, DwarfRegNum<[14]>; +def R15D : GPR64<15, "r15", [R15W]>, DwarfRegNum<[15]>; +} + +// Register pairs +let SubRegIndices = [subreg_32bit, subreg_odd32] in { +def R0P : GPR64< 0, "r0", [R0W, R1W], [R0D, R1D]>; +def R2P : GPR64< 2, "r2", [R2W, R3W], [R2D, R3D]>; +def R4P : GPR64< 4, "r4", [R4W, R5W], [R4D, R5D]>; +def R6P : GPR64< 6, "r6", [R6W, R7W], [R6D, R7D]>; +def R8P : GPR64< 8, "r8", [R8W, R9W], [R8D, R9D]>; +def R10P : GPR64<10, "r10", [R10W, R11W], [R10D, R11D]>; +def R12P : GPR64<12, "r12", [R12W, R13W], [R12D, R13D]>; +def R14P : GPR64<14, "r14", [R14W, R15W], [R14D, R15D]>; +} + +let SubRegIndices = [subreg_even, subreg_odd], + CompositeIndices = [(subreg_odd32 subreg_odd, subreg_32bit)] in { +def R0Q : GPR128< 0, "r0", [R0D, R1D], [R0P]>; +def R2Q : GPR128< 2, "r2", [R2D, R3D], [R2P]>; +def R4Q : GPR128< 4, "r4", [R4D, R5D], [R4P]>; +def R6Q : GPR128< 6, "r6", [R6D, R7D], [R6P]>; +def R8Q : GPR128< 8, "r8", [R8D, R9D], [R8P]>; +def R10Q : GPR128<10, "r10", [R10D, R11D], [R10P]>; +def R12Q : GPR128<12, "r12", [R12D, R13D], [R12P]>; +def R14Q : GPR128<14, "r14", [R14D, R15D], [R14P]>; +} + +// Floating-point registers +def F0S : FPRS< 0, "f0">, DwarfRegNum<[16]>; +def F1S : FPRS< 1, "f1">, DwarfRegNum<[17]>; +def F2S : FPRS< 2, "f2">, DwarfRegNum<[18]>; +def F3S : FPRS< 3, "f3">, DwarfRegNum<[19]>; +def F4S : FPRS< 4, "f4">, DwarfRegNum<[20]>; +def F5S : FPRS< 5, "f5">, DwarfRegNum<[21]>; +def F6S : FPRS< 6, "f6">, DwarfRegNum<[22]>; +def F7S : FPRS< 7, "f7">, DwarfRegNum<[23]>; +def F8S : FPRS< 8, "f8">, DwarfRegNum<[24]>; +def F9S : FPRS< 9, "f9">, DwarfRegNum<[25]>; +def F10S : FPRS<10, "f10">, DwarfRegNum<[26]>; +def F11S : FPRS<11, "f11">, DwarfRegNum<[27]>; +def F12S : FPRS<12, "f12">, DwarfRegNum<[28]>; +def F13S : FPRS<13, "f13">, DwarfRegNum<[29]>; +def F14S : FPRS<14, "f14">, DwarfRegNum<[30]>; +def F15S : FPRS<15, "f15">, DwarfRegNum<[31]>; + +let SubRegIndices = [subreg_32bit] in { +def F0L : FPRL< 0, "f0", [F0S]>; +def F1L : FPRL< 1, "f1", [F1S]>; +def F2L : FPRL< 2, "f2", [F2S]>; +def F3L : FPRL< 3, "f3", [F3S]>; +def F4L : FPRL< 4, "f4", [F4S]>; +def F5L : FPRL< 5, "f5", [F5S]>; +def F6L : FPRL< 6, "f6", [F6S]>; +def F7L : FPRL< 7, "f7", [F7S]>; +def F8L : FPRL< 8, "f8", [F8S]>; +def F9L : FPRL< 9, "f9", [F9S]>; +def F10L : FPRL<10, "f10", [F10S]>; +def F11L : FPRL<11, "f11", [F11S]>; +def F12L : FPRL<12, "f12", [F12S]>; +def F13L : FPRL<13, "f13", [F13S]>; +def F14L : FPRL<14, "f14", [F14S]>; +def F15L : FPRL<15, "f15", [F15S]>; +} + +// Status register +def PSW : SystemZReg<"psw">; + +/// Register classes. +/// Allocate the callee-saved R6-R12 backwards. That way they can be saved +/// together with R14 and R15 in one prolog instruction. +def GR32 : RegisterClass<"SystemZ", [i32], 32, (add (sequence "R%uW", 0, 5), + (sequence "R%uW", 15, 6))>; + +/// Registers used to generate address. Everything except R0. +def ADDR32 : RegisterClass<"SystemZ", [i32], 32, (sub GR32, R0W)>; + +def GR64 : RegisterClass<"SystemZ", [i64], 64, (add (sequence "R%uD", 0, 5), + (sequence "R%uD", 15, 6))> { + let SubRegClasses = [(GR32 subreg_32bit)]; +} + +def ADDR64 : RegisterClass<"SystemZ", [i64], 64, (sub GR64, R0D)> { + let SubRegClasses = [(ADDR32 subreg_32bit)]; +} + +// Even-odd register pairs +def GR64P : RegisterClass<"SystemZ", [v2i32], 64, (add R0P, R2P, R4P, + R12P, R10P, R8P, R6P, + R14P)> { + let SubRegClasses = [(GR32 subreg_32bit, subreg_odd32)]; +} + +def GR128 : RegisterClass<"SystemZ", [v2i64], 128, (add R0Q, R2Q, R4Q, + R12Q, R10Q, R8Q, R6Q, + R14Q)> { + let SubRegClasses = [(GR32 subreg_32bit, subreg_odd32), + (GR64 subreg_even, subreg_odd)]; +} + +def FP32 : RegisterClass<"SystemZ", [f32], 32, (sequence "F%uS", 0, 15)>; + +def FP64 : RegisterClass<"SystemZ", [f64], 64, (sequence "F%uL", 0, 15)> { + let SubRegClasses = [(FP32 subreg_32bit)]; +} + +// Status flags registers. +def CCR : RegisterClass<"SystemZ", [i64], 64, (add PSW)> { + let CopyCost = -1; // Don't allow copying of status registers. +} diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp new file mode 100644 index 0000000..3eabcd2 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp @@ -0,0 +1,23 @@ +//===-- SystemZSelectionDAGInfo.cpp - SystemZ SelectionDAG Info -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SystemZSelectionDAGInfo class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "systemz-selectiondag-info" +#include "SystemZTargetMachine.h" +using namespace llvm; + +SystemZSelectionDAGInfo::SystemZSelectionDAGInfo(const SystemZTargetMachine &TM) + : TargetSelectionDAGInfo(TM) { +} + +SystemZSelectionDAGInfo::~SystemZSelectionDAGInfo() { +} diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.h b/contrib/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.h new file mode 100644 index 0000000..1450401 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.h @@ -0,0 +1,31 @@ +//===-- SystemZSelectionDAGInfo.h - SystemZ SelectionDAG Info ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the SystemZ subclass for TargetSelectionDAGInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef SYSTEMZSELECTIONDAGINFO_H +#define SYSTEMZSELECTIONDAGINFO_H + +#include "llvm/Target/TargetSelectionDAGInfo.h" + +namespace llvm { + +class SystemZTargetMachine; + +class SystemZSelectionDAGInfo : public TargetSelectionDAGInfo { +public: + explicit SystemZSelectionDAGInfo(const SystemZTargetMachine &TM); + ~SystemZSelectionDAGInfo(); +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.cpp new file mode 100644 index 0000000..0845510 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.cpp @@ -0,0 +1,54 @@ +//===- SystemZSubtarget.cpp - SystemZ Subtarget Information -------*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SystemZ specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#include "SystemZSubtarget.h" +#include "SystemZ.h" +#include "llvm/GlobalValue.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/TargetRegistry.h" + +#define GET_SUBTARGETINFO_TARGET_DESC +#define GET_SUBTARGETINFO_CTOR +#include "SystemZGenSubtargetInfo.inc" + +using namespace llvm; + +SystemZSubtarget::SystemZSubtarget(const std::string &TT, + const std::string &CPU, + const std::string &FS): + SystemZGenSubtargetInfo(TT, CPU, FS), HasZ10Insts(false) { + std::string CPUName = CPU; + if (CPUName.empty()) + CPUName = "z9"; + + // Parse features string. + ParseSubtargetFeatures(CPUName, FS); +} + +/// True if accessing the GV requires an extra load. +bool SystemZSubtarget::GVRequiresExtraLoad(const GlobalValue* GV, + const TargetMachine& TM, + bool isDirectCall) const { + if (TM.getRelocationModel() == Reloc::PIC_) { + // Extra load is needed for all externally visible. + if (isDirectCall) + return false; + + if (GV->hasLocalLinkage() || GV->hasHiddenVisibility()) + return false; + + return true; + } + + return false; +} diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.h b/contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.h new file mode 100644 index 0000000..55cfd80 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.h @@ -0,0 +1,48 @@ +//==-- SystemZSubtarget.h - Define Subtarget for the SystemZ ---*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the SystemZ specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_SystemZ_SUBTARGET_H +#define LLVM_TARGET_SystemZ_SUBTARGET_H + +#include "llvm/Target/TargetSubtargetInfo.h" +#include <string> + +#define GET_SUBTARGETINFO_HEADER +#include "SystemZGenSubtargetInfo.inc" + +namespace llvm { +class GlobalValue; +class StringRef; +class TargetMachine; + +class SystemZSubtarget : public SystemZGenSubtargetInfo { + bool HasZ10Insts; +public: + /// This constructor initializes the data members to match that + /// of the specified triple. + /// + SystemZSubtarget(const std::string &TT, const std::string &CPU, + const std::string &FS); + + /// ParseSubtargetFeatures - Parses features string setting specified + /// subtarget options. Definition of function is auto generated by tblgen. + void ParseSubtargetFeatures(StringRef CPU, StringRef FS); + + bool isZ10() const { return HasZ10Insts; } + + bool GVRequiresExtraLoad(const GlobalValue* GV, const TargetMachine& TM, + bool isDirectCall) const; +}; +} // End llvm namespace + +#endif // LLVM_TARGET_SystemZ_SUBTARGET_H diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp new file mode 100644 index 0000000..e390f06 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp @@ -0,0 +1,40 @@ +//===-- SystemZTargetMachine.cpp - Define TargetMachine for SystemZ -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SystemZTargetMachine.h" +#include "SystemZ.h" +#include "llvm/PassManager.h" +#include "llvm/Support/TargetRegistry.h" +using namespace llvm; + +extern "C" void LLVMInitializeSystemZTarget() { + // Register the target. + RegisterTargetMachine<SystemZTargetMachine> X(TheSystemZTarget); +} + +/// SystemZTargetMachine ctor - Create an ILP64 architecture model +/// +SystemZTargetMachine::SystemZTargetMachine(const Target &T, + StringRef TT, StringRef CPU, + StringRef FS, Reloc::Model RM, + CodeModel::Model CM) + : LLVMTargetMachine(T, TT, CPU, FS, RM, CM), + Subtarget(TT, CPU, FS), + DataLayout("E-p:64:64:64-i8:8:16-i16:16:16-i32:32:32-i64:64:64-f32:32:32" + "-f64:64:64-f128:128:128-a0:16:16-n32:64"), + InstrInfo(*this), TLInfo(*this), TSInfo(*this), + FrameLowering(Subtarget) { +} + +bool SystemZTargetMachine::addInstSelector(PassManagerBase &PM, + CodeGenOpt::Level OptLevel) { + // Install an instruction selector. + PM.add(createSystemZISelDag(*this, OptLevel)); + return false; +} diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZTargetMachine.h b/contrib/llvm/lib/Target/SystemZ/SystemZTargetMachine.h new file mode 100644 index 0000000..43dce4b --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/SystemZTargetMachine.h @@ -0,0 +1,68 @@ +//==- SystemZTargetMachine.h - Define TargetMachine for SystemZ ---*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the SystemZ specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_TARGET_SYSTEMZ_TARGETMACHINE_H +#define LLVM_TARGET_SYSTEMZ_TARGETMACHINE_H + +#include "SystemZInstrInfo.h" +#include "SystemZISelLowering.h" +#include "SystemZFrameLowering.h" +#include "SystemZSelectionDAGInfo.h" +#include "SystemZRegisterInfo.h" +#include "SystemZSubtarget.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + +/// SystemZTargetMachine +/// +class SystemZTargetMachine : public LLVMTargetMachine { + SystemZSubtarget Subtarget; + const TargetData DataLayout; // Calculates type size & alignment + SystemZInstrInfo InstrInfo; + SystemZTargetLowering TLInfo; + SystemZSelectionDAGInfo TSInfo; + SystemZFrameLowering FrameLowering; +public: + SystemZTargetMachine(const Target &T, StringRef TT, + StringRef CPU, StringRef FS, + Reloc::Model RM, CodeModel::Model CM); + + virtual const TargetFrameLowering *getFrameLowering() const { + return &FrameLowering; + } + virtual const SystemZInstrInfo *getInstrInfo() const { return &InstrInfo; } + virtual const TargetData *getTargetData() const { return &DataLayout;} + virtual const SystemZSubtarget *getSubtargetImpl() const { return &Subtarget; } + + virtual const SystemZRegisterInfo *getRegisterInfo() const { + return &InstrInfo.getRegisterInfo(); + } + + virtual const SystemZTargetLowering *getTargetLowering() const { + return &TLInfo; + } + + virtual const SystemZSelectionDAGInfo* getSelectionDAGInfo() const { + return &TSInfo; + } + + virtual bool addInstSelector(PassManagerBase &PM, CodeGenOpt::Level OptLevel); +}; // SystemZTargetMachine. + +} // end namespace llvm + +#endif // LLVM_TARGET_SystemZ_TARGETMACHINE_H diff --git a/contrib/llvm/lib/Target/SystemZ/TargetInfo/SystemZTargetInfo.cpp b/contrib/llvm/lib/Target/SystemZ/TargetInfo/SystemZTargetInfo.cpp new file mode 100644 index 0000000..da99282 --- /dev/null +++ b/contrib/llvm/lib/Target/SystemZ/TargetInfo/SystemZTargetInfo.cpp @@ -0,0 +1,19 @@ +//===-- SystemZTargetInfo.cpp - SystemZ Target Implementation -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SystemZ.h" +#include "llvm/Module.h" +#include "llvm/Support/TargetRegistry.h" +using namespace llvm; + +Target llvm::TheSystemZTarget; + +extern "C" void LLVMInitializeSystemZTargetInfo() { + RegisterTarget<Triple::systemz> X(TheSystemZTarget, "systemz", "SystemZ"); +} |