diff options
Diffstat (limited to 'lib')
62 files changed, 10763 insertions, 1 deletions
diff --git a/lib/Target/LLVMBuild.txt b/lib/Target/LLVMBuild.txt index c06e8bc3cd..1022ae9088 100644 --- a/lib/Target/LLVMBuild.txt +++ b/lib/Target/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = AArch64 ARM CppBackend Hexagon MBlaze MSP430 NVPTX Mips PowerPC R600 Sparc X86 XCore +subdirectories = AArch64 ARM CppBackend Hexagon MBlaze MSP430 NVPTX Mips PowerPC R600 Sparc SystemZ X86 XCore ; This is a special group whose required libraries are extended (by llvm-build) ; with the best execution engine (the native JIT, if available, or the diff --git a/lib/Target/SystemZ/AsmParser/CMakeLists.txt b/lib/Target/SystemZ/AsmParser/CMakeLists.txt new file mode 100644 index 0000000000..78a57146e1 --- /dev/null +++ b/lib/Target/SystemZ/AsmParser/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMSystemZAsmParser + SystemZAsmParser.cpp + ) + +add_dependencies(LLVMSystemZAsmParser SystemZCommonTableGen) diff --git a/lib/Target/SystemZ/AsmParser/LLVMBuild.txt b/lib/Target/SystemZ/AsmParser/LLVMBuild.txt new file mode 100644 index 0000000000..0b97e71e92 --- /dev/null +++ b/lib/Target/SystemZ/AsmParser/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/SystemZ/AsmParser/LLVMBuild.txt -------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = SystemZAsmParser +parent = SystemZ +required_libraries = SystemZDesc SystemZInfo MC MCParser Support +add_to_library_groups = SystemZ diff --git a/lib/Target/SystemZ/AsmParser/Makefile b/lib/Target/SystemZ/AsmParser/Makefile new file mode 100644 index 0000000000..623ae2c4e3 --- /dev/null +++ b/lib/Target/SystemZ/AsmParser/Makefile @@ -0,0 +1,16 @@ +##===- lib/Target/SystemZ/AsmParser/Makefile ---------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME = LLVMSystemZAsmParser + +# Hack: we need to include 'main' SystemZ target directory to grab private headers +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp b/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp new file mode 100644 index 0000000000..c7725a1459 --- /dev/null +++ b/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp @@ -0,0 +1,689 @@ +//===-- SystemZAsmParser.cpp - Parse SystemZ assembly instructions --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/SystemZMCTargetDesc.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +// Return true if Expr is in the range [MinValue, MaxValue]. +static bool inRange(const MCExpr *Expr, int64_t MinValue, int64_t MaxValue) { + if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr)) { + int64_t Value = CE->getValue(); + return Value >= MinValue && Value <= MaxValue; + } + return false; +} + +namespace { +class SystemZOperand : public MCParsedAsmOperand { +public: + enum RegisterKind { + GR32Reg, + GR64Reg, + GR128Reg, + ADDR32Reg, + ADDR64Reg, + FP32Reg, + FP64Reg, + FP128Reg + }; + +private: + enum OperandKind { + KindToken, + KindReg, + KindAccessReg, + KindImm, + KindMem + }; + + OperandKind Kind; + SMLoc StartLoc, EndLoc; + + // A string of length Length, starting at Data. + struct TokenOp { + const char *Data; + unsigned Length; + }; + + // LLVM register Num, which has kind Kind. + struct RegOp { + RegisterKind Kind; + unsigned Num; + }; + + // Base + Disp + Index, where Base and Index are LLVM registers or 0. + // RegKind says what type the registers have (ADDR32Reg or ADDR64Reg). + struct MemOp { + unsigned Base : 8; + unsigned Index : 8; + unsigned RegKind : 8; + unsigned Unused : 8; + const MCExpr *Disp; + }; + + union { + TokenOp Token; + RegOp Reg; + unsigned AccessReg; + const MCExpr *Imm; + MemOp Mem; + }; + + SystemZOperand(OperandKind kind, SMLoc startLoc, SMLoc endLoc) + : Kind(kind), StartLoc(startLoc), EndLoc(endLoc) + {} + + void addExpr(MCInst &Inst, const MCExpr *Expr) const { + // Add as immediates when possible. Null MCExpr = 0. + if (Expr == 0) + Inst.addOperand(MCOperand::CreateImm(0)); + else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr)) + Inst.addOperand(MCOperand::CreateImm(CE->getValue())); + else + Inst.addOperand(MCOperand::CreateExpr(Expr)); + } + +public: + // Create particular kinds of operand. + static SystemZOperand *createToken(StringRef Str, SMLoc Loc) { + SystemZOperand *Op = new SystemZOperand(KindToken, Loc, Loc); + Op->Token.Data = Str.data(); + Op->Token.Length = Str.size(); + return Op; + } + static SystemZOperand *createReg(RegisterKind Kind, unsigned Num, + SMLoc StartLoc, SMLoc EndLoc) { + SystemZOperand *Op = new SystemZOperand(KindReg, StartLoc, EndLoc); + Op->Reg.Kind = Kind; + Op->Reg.Num = Num; + return Op; + } + static SystemZOperand *createAccessReg(unsigned Num, SMLoc StartLoc, + SMLoc EndLoc) { + SystemZOperand *Op = new SystemZOperand(KindAccessReg, StartLoc, EndLoc); + Op->AccessReg = Num; + return Op; + } + static SystemZOperand *createImm(const MCExpr *Expr, SMLoc StartLoc, + SMLoc EndLoc) { + SystemZOperand *Op = new SystemZOperand(KindImm, StartLoc, EndLoc); + Op->Imm = Expr; + return Op; + } + static SystemZOperand *createMem(RegisterKind RegKind, unsigned Base, + const MCExpr *Disp, unsigned Index, + SMLoc StartLoc, SMLoc EndLoc) { + SystemZOperand *Op = new SystemZOperand(KindMem, StartLoc, EndLoc); + Op->Mem.RegKind = RegKind; + Op->Mem.Base = Base; + Op->Mem.Index = Index; + Op->Mem.Disp = Disp; + return Op; + } + + // Token operands + virtual bool isToken() const LLVM_OVERRIDE { + return Kind == KindToken; + } + StringRef getToken() const { + assert(Kind == KindToken && "Not a token"); + return StringRef(Token.Data, Token.Length); + } + + // Register operands. + virtual bool isReg() const LLVM_OVERRIDE { + return Kind == KindReg; + } + bool isReg(RegisterKind RegKind) const { + return Kind == KindReg && Reg.Kind == RegKind; + } + virtual unsigned getReg() const LLVM_OVERRIDE { + assert(Kind == KindReg && "Not a register"); + return Reg.Num; + } + + // Access register operands. Access registers aren't exposed to LLVM + // as registers. + bool isAccessReg() const { + return Kind == KindAccessReg; + } + + // Immediate operands. + virtual bool isImm() const LLVM_OVERRIDE { + return Kind == KindImm; + } + bool isImm(int64_t MinValue, int64_t MaxValue) const { + return Kind == KindImm && inRange(Imm, MinValue, MaxValue); + } + const MCExpr *getImm() const { + assert(Kind == KindImm && "Not an immediate"); + return Imm; + } + + // Memory operands. + virtual bool isMem() const LLVM_OVERRIDE { + return Kind == KindMem; + } + bool isMem(RegisterKind RegKind, bool HasIndex) const { + return (Kind == KindMem && + Mem.RegKind == RegKind && + (HasIndex || !Mem.Index)); + } + bool isMemDisp12(RegisterKind RegKind, bool HasIndex) const { + return isMem(RegKind, HasIndex) && inRange(Mem.Disp, 0, 0xfff); + } + bool isMemDisp20(RegisterKind RegKind, bool HasIndex) const { + return isMem(RegKind, HasIndex) && inRange(Mem.Disp, -524288, 524287); + } + + // Override MCParsedAsmOperand. + virtual SMLoc getStartLoc() const LLVM_OVERRIDE { return StartLoc; } + virtual SMLoc getEndLoc() const LLVM_OVERRIDE { return EndLoc; } + virtual void print(raw_ostream &OS) const LLVM_OVERRIDE; + + // Used by the TableGen code to add particular types of operand + // to an instruction. + void addRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands"); + Inst.addOperand(MCOperand::CreateReg(getReg())); + } + void addAccessRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands"); + assert(Kind == KindAccessReg && "Invalid operand type"); + Inst.addOperand(MCOperand::CreateImm(AccessReg)); + } + void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands"); + addExpr(Inst, getImm()); + } + void addBDAddrOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands"); + assert(Kind == KindMem && Mem.Index == 0 && "Invalid operand type"); + Inst.addOperand(MCOperand::CreateReg(Mem.Base)); + addExpr(Inst, Mem.Disp); + } + void addBDXAddrOperands(MCInst &Inst, unsigned N) const { + assert(N == 3 && "Invalid number of operands"); + assert(Kind == KindMem && "Invalid operand type"); + Inst.addOperand(MCOperand::CreateReg(Mem.Base)); + addExpr(Inst, Mem.Disp); + Inst.addOperand(MCOperand::CreateReg(Mem.Index)); + } + + // Used by the TableGen code to check for particular operand types. + bool isGR32() const { return isReg(GR32Reg); } + bool isGR64() const { return isReg(GR64Reg); } + bool isGR128() const { return isReg(GR128Reg); } + bool isADDR32() const { return isReg(ADDR32Reg); } + bool isADDR64() const { return isReg(ADDR64Reg); } + bool isADDR128() const { return false; } + bool isFP32() const { return isReg(FP32Reg); } + bool isFP64() const { return isReg(FP64Reg); } + bool isFP128() const { return isReg(FP128Reg); } + bool isBDAddr32Disp12() const { return isMemDisp12(ADDR32Reg, false); } + bool isBDAddr32Disp20() const { return isMemDisp20(ADDR32Reg, false); } + bool isBDAddr64Disp12() const { return isMemDisp12(ADDR64Reg, false); } + bool isBDAddr64Disp20() const { return isMemDisp20(ADDR64Reg, false); } + bool isBDXAddr64Disp12() const { return isMemDisp12(ADDR64Reg, true); } + bool isBDXAddr64Disp20() const { return isMemDisp20(ADDR64Reg, true); } + bool isU4Imm() const { return isImm(0, 15); } + bool isU6Imm() const { return isImm(0, 63); } + bool isU8Imm() const { return isImm(0, 255); } + bool isS8Imm() const { return isImm(-128, 127); } + bool isU16Imm() const { return isImm(0, 65535); } + bool isS16Imm() const { return isImm(-32768, 32767); } + bool isU32Imm() const { return isImm(0, (1LL << 32) - 1); } + bool isS32Imm() const { return isImm(-(1LL << 31), (1LL << 31) - 1); } +}; + +// Maps of asm register numbers to LLVM register numbers, with 0 indicating +// an invalid register. We don't use register class directly because that +// specifies the allocation order. +static const unsigned GR32Regs[] = { + SystemZ::R0W, SystemZ::R1W, SystemZ::R2W, SystemZ::R3W, + SystemZ::R4W, SystemZ::R5W, SystemZ::R6W, SystemZ::R7W, + SystemZ::R8W, SystemZ::R9W, SystemZ::R10W, SystemZ::R11W, + SystemZ::R12W, SystemZ::R13W, SystemZ::R14W, SystemZ::R15W +}; +static const unsigned GR64Regs[] = { + SystemZ::R0D, SystemZ::R1D, SystemZ::R2D, SystemZ::R3D, + SystemZ::R4D, SystemZ::R5D, SystemZ::R6D, SystemZ::R7D, + SystemZ::R8D, SystemZ::R9D, SystemZ::R10D, SystemZ::R11D, + SystemZ::R12D, SystemZ::R13D, SystemZ::R14D, SystemZ::R15D +}; +static const unsigned GR128Regs[] = { + SystemZ::R0Q, 0, SystemZ::R2Q, 0, + SystemZ::R4Q, 0, SystemZ::R6Q, 0, + SystemZ::R8Q, 0, SystemZ::R10Q, 0, + SystemZ::R12Q, 0, SystemZ::R14Q, 0 +}; +static const unsigned FP32Regs[] = { + SystemZ::F0S, SystemZ::F1S, SystemZ::F2S, SystemZ::F3S, + SystemZ::F4S, SystemZ::F5S, SystemZ::F6S, SystemZ::F7S, + SystemZ::F8S, SystemZ::F9S, SystemZ::F10S, SystemZ::F11S, + SystemZ::F12S, SystemZ::F13S, SystemZ::F14S, SystemZ::F15S +}; +static const unsigned FP64Regs[] = { + SystemZ::F0D, SystemZ::F1D, SystemZ::F2D, SystemZ::F3D, + SystemZ::F4D, SystemZ::F5D, SystemZ::F6D, SystemZ::F7D, + SystemZ::F8D, SystemZ::F9D, SystemZ::F10D, SystemZ::F11D, + SystemZ::F12D, SystemZ::F13D, SystemZ::F14D, SystemZ::F15D +}; +static const unsigned FP128Regs[] = { + SystemZ::F0Q, SystemZ::F1Q, 0, 0, + SystemZ::F4Q, SystemZ::F5Q, 0, 0, + SystemZ::F8Q, SystemZ::F9Q, 0, 0, + SystemZ::F12Q, SystemZ::F13Q, 0, 0 +}; + +class SystemZAsmParser : public MCTargetAsmParser { +#define GET_ASSEMBLER_HEADER +#include "SystemZGenAsmMatcher.inc" + +private: + MCSubtargetInfo &STI; + MCAsmParser &Parser; + struct Register { + char Prefix; + unsigned Number; + SMLoc StartLoc, EndLoc; + }; + + bool parseRegister(Register &Reg); + + OperandMatchResultTy + parseRegister(Register &Reg, char Prefix, const unsigned *Regs, + bool IsAddress = false); + + OperandMatchResultTy + parseRegister(SmallVectorImpl<MCParsedAsmOperand*> &Operands, + char Prefix, const unsigned *Regs, + SystemZOperand::RegisterKind Kind, + bool IsAddress = false); + + OperandMatchResultTy + parseAddress(SmallVectorImpl<MCParsedAsmOperand*> &Operands, + const unsigned *Regs, SystemZOperand::RegisterKind RegKind, + bool HasIndex); + + bool parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands, + StringRef Mnemonic); + +public: + SystemZAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser) + : MCTargetAsmParser(), STI(sti), Parser(parser) { + MCAsmParserExtension::Initialize(Parser); + + // Initialize the set of available features. + setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + } + + // Override MCTargetAsmParser. + virtual bool ParseDirective(AsmToken DirectiveID) LLVM_OVERRIDE; + virtual bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, + SMLoc &EndLoc) LLVM_OVERRIDE; + virtual bool ParseInstruction(ParseInstructionInfo &Info, + StringRef Name, SMLoc NameLoc, + SmallVectorImpl<MCParsedAsmOperand*> &Operands) + LLVM_OVERRIDE; + virtual bool + MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + SmallVectorImpl<MCParsedAsmOperand*> &Operands, + MCStreamer &Out, unsigned &ErrorInfo, + bool MatchingInlineAsm) LLVM_OVERRIDE; + + // Used by the TableGen code to parse particular operand types. + OperandMatchResultTy + parseGR32(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + return parseRegister(Operands, 'r', GR32Regs, SystemZOperand::GR32Reg); + } + OperandMatchResultTy + parseGR64(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + return parseRegister(Operands, 'r', GR64Regs, SystemZOperand::GR64Reg); + } + OperandMatchResultTy + parseGR128(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + return parseRegister(Operands, 'r', GR128Regs, SystemZOperand::GR128Reg); + } + OperandMatchResultTy + parseADDR32(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + return parseRegister(Operands, 'r', GR32Regs, SystemZOperand::ADDR32Reg, + true); + } + OperandMatchResultTy + parseADDR64(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + return parseRegister(Operands, 'r', GR64Regs, SystemZOperand::ADDR64Reg, + true); + } + OperandMatchResultTy + parseADDR128(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + llvm_unreachable("Shouldn't be used as an operand"); + } + OperandMatchResultTy + parseFP32(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + return parseRegister(Operands, 'f', FP32Regs, SystemZOperand::FP32Reg); + } + OperandMatchResultTy + parseFP64(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + return parseRegister(Operands, 'f', FP64Regs, SystemZOperand::FP64Reg); + } + OperandMatchResultTy + parseFP128(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + return parseRegister(Operands, 'f', FP128Regs, SystemZOperand::FP128Reg); + } + OperandMatchResultTy + parseBDAddr32(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + return parseAddress(Operands, GR32Regs, SystemZOperand::ADDR32Reg, false); + } + OperandMatchResultTy + parseBDAddr64(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + return parseAddress(Operands, GR64Regs, SystemZOperand::ADDR64Reg, false); + } + OperandMatchResultTy + parseBDXAddr64(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + return parseAddress(Operands, GR64Regs, SystemZOperand::ADDR64Reg, true); + } + OperandMatchResultTy + parseAccessReg(SmallVectorImpl<MCParsedAsmOperand*> &Operands); +}; +} + +#define GET_REGISTER_MATCHER +#define GET_SUBTARGET_FEATURE_NAME +#define GET_MATCHER_IMPLEMENTATION +#include "SystemZGenAsmMatcher.inc" + +void SystemZOperand::print(raw_ostream &OS) const { + llvm_unreachable("Not implemented"); +} + +// Parse one register of the form %<prefix><number>. +bool SystemZAsmParser::parseRegister(Register &Reg) { + Reg.StartLoc = Parser.getTok().getLoc(); + + // Eat the % prefix. + if (Parser.getTok().isNot(AsmToken::Percent)) + return true; + Parser.Lex(); + + // Expect a register name. + if (Parser.getTok().isNot(AsmToken::Identifier)) + return true; + + // Check the prefix. + StringRef Name = Parser.getTok().getString(); + if (Name.size() < 2) + return true; + Reg.Prefix = Name[0]; + + // Treat the rest of the register name as a register number. + if (Name.substr(1).getAsInteger(10, Reg.Number)) + return true; + + Reg.EndLoc = Parser.getTok().getLoc(); + Parser.Lex(); + return false; +} + +// Parse a register with prefix Prefix and convert it to LLVM numbering. +// Regs maps asm register numbers to LLVM register numbers, with zero +// entries indicating an invalid register. IsAddress says whether the +// register appears in an address context. +SystemZAsmParser::OperandMatchResultTy +SystemZAsmParser::parseRegister(Register &Reg, char Prefix, + const unsigned *Regs, bool IsAddress) { + if (parseRegister(Reg)) + return MatchOperand_NoMatch; + if (Reg.Prefix != Prefix || Reg.Number > 15 || Regs[Reg.Number] == 0) { + Error(Reg.StartLoc, "invalid register"); + return MatchOperand_ParseFail; + } + if (Reg.Number == 0 && IsAddress) { + Error(Reg.StartLoc, "%r0 used in an address"); + return MatchOperand_ParseFail; + } + Reg.Number = Regs[Reg.Number]; + return MatchOperand_Success; +} + +// Parse a register and add it to Operands. Prefix is 'r' for GPRs, +// 'f' for FPRs, etc. Regs maps asm register numbers to LLVM register numbers, +// with zero entries indicating an invalid register. Kind is the type of +// register represented by Regs and IsAddress says whether the register is +// being parsed in an address context, meaning that %r0 evaluates as 0. +SystemZAsmParser::OperandMatchResultTy +SystemZAsmParser::parseRegister(SmallVectorImpl<MCParsedAsmOperand*> &Operands, + char Prefix, const unsigned *Regs, + SystemZOperand::RegisterKind Kind, + bool IsAddress) { + Register Reg; + OperandMatchResultTy Result = parseRegister(Reg, Prefix, Regs, IsAddress); + if (Result == MatchOperand_Success) + Operands.push_back(SystemZOperand::createReg(Kind, Reg.Number, + Reg.StartLoc, Reg.EndLoc)); + return Result; +} + +// Parse a memory operand and add it to Operands. Regs maps asm register +// numbers to LLVM address registers and RegKind says what kind of address +// register we're using (ADDR32Reg or ADDR64Reg). HasIndex says whether +// the address allows index registers. +SystemZAsmParser::OperandMatchResultTy +SystemZAsmParser::parseAddress(SmallVectorImpl<MCParsedAsmOperand*> &Operands, + const unsigned *Regs, + SystemZOperand::RegisterKind RegKind, + bool HasIndex) { + SMLoc StartLoc = Parser.getTok().getLoc(); + + // Parse the displacement, which must always be present. + const MCExpr *Disp; + if (getParser().parseExpression(Disp)) + return MatchOperand_NoMatch; + + // Parse the optional base and index. + unsigned Index = 0; + unsigned Base = 0; + if (getLexer().is(AsmToken::LParen)) { + Parser.Lex(); + + // Parse the first register. + Register Reg; + OperandMatchResultTy Result = parseRegister(Reg, 'r', GR64Regs, true); + if (Result != MatchOperand_Success) + return Result; + + // Check whether there's a second register. If so, the one that we + // just parsed was the index. + if (getLexer().is(AsmToken::Comma)) { + Parser.Lex(); + + if (!HasIndex) { + Error(Reg.StartLoc, "invalid use of indexed addressing"); + return MatchOperand_ParseFail; + } + + Index = Reg.Number; + Result = parseRegister(Reg, 'r', GR64Regs, true); + if (Result != MatchOperand_Success) + return Result; + } + Base = Reg.Number; + + // Consume the closing bracket. + if (getLexer().isNot(AsmToken::RParen)) + return MatchOperand_NoMatch; + Parser.Lex(); + } + + SMLoc EndLoc = + SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Operands.push_back(SystemZOperand::createMem(RegKind, Base, Disp, Index, + StartLoc, EndLoc)); + return MatchOperand_Success; +} + +bool SystemZAsmParser::ParseDirective(AsmToken DirectiveID) { + return true; +} + +bool SystemZAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, + SMLoc &EndLoc) { + Register Reg; + if (parseRegister(Reg)) + return Error(Reg.StartLoc, "register expected"); + if (Reg.Prefix == 'r' && Reg.Number < 16) + RegNo = GR64Regs[Reg.Number]; + else if (Reg.Prefix == 'f' && Reg.Number < 16) + RegNo = FP64Regs[Reg.Number]; + else + return Error(Reg.StartLoc, "invalid register"); + StartLoc = Reg.StartLoc; + EndLoc = Reg.EndLoc; + return false; +} + +bool SystemZAsmParser:: +ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, + SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + Operands.push_back(SystemZOperand::createToken(Name, NameLoc)); + + // Read the remaining operands. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + // Read the first operand. + if (parseOperand(Operands, Name)) { + Parser.eatToEndOfStatement(); + return true; + } + + // Read any subsequent operands. + while (getLexer().is(AsmToken::Comma)) { + Parser.Lex(); + if (parseOperand(Operands, Name)) { + Parser.eatToEndOfStatement(); + return true; + } + } + if (getLexer().isNot(AsmToken::EndOfStatement)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + } + + // Consume the EndOfStatement. + Parser.Lex(); + return false; +} + +bool SystemZAsmParser:: +parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands, + StringRef Mnemonic) { + // Check if the current operand has a custom associated parser, if so, try to + // custom parse the operand, or fallback to the general approach. + OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic); + if (ResTy == MatchOperand_Success) + return false; + + // If there wasn't a custom match, try the generic matcher below. Otherwise, + // there was a match, but an error occurred, in which case, just return that + // the operand parsing failed. + if (ResTy == MatchOperand_ParseFail) + return true; + + // The only other type of operand is an immediate. + const MCExpr *Expr; + SMLoc StartLoc = Parser.getTok().getLoc(); + if (getParser().parseExpression(Expr)) + return true; + + SMLoc EndLoc = + SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Operands.push_back(SystemZOperand::createImm(Expr, StartLoc, EndLoc)); + return false; +} + +bool SystemZAsmParser:: +MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + SmallVectorImpl<MCParsedAsmOperand*> &Operands, + MCStreamer &Out, unsigned &ErrorInfo, + bool MatchingInlineAsm) { + MCInst Inst; + unsigned MatchResult; + + MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo, + MatchingInlineAsm); + switch (MatchResult) { + default: break; + case Match_Success: + Inst.setLoc(IDLoc); + Out.EmitInstruction(Inst); + return false; + + case Match_MissingFeature: { + assert(ErrorInfo && "Unknown missing feature!"); + // Special case the error message for the very common case where only + // a single subtarget feature is missing + std::string Msg = "instruction requires:"; + unsigned Mask = 1; + for (unsigned I = 0; I < sizeof(ErrorInfo) * 8 - 1; ++I) { + if (ErrorInfo & Mask) { + Msg += " "; + Msg += getSubtargetFeatureName(ErrorInfo & Mask); + } + Mask <<= 1; + } + return Error(IDLoc, Msg); + } + + case Match_InvalidOperand: { + SMLoc ErrorLoc = IDLoc; + if (ErrorInfo != ~0U) { + if (ErrorInfo >= Operands.size()) + return Error(IDLoc, "too few operands for instruction"); + + ErrorLoc = ((SystemZOperand*)Operands[ErrorInfo])->getStartLoc(); + if (ErrorLoc == SMLoc()) + ErrorLoc = IDLoc; + } + return Error(ErrorLoc, "invalid operand for instruction"); + } + + case Match_MnemonicFail: + return Error(IDLoc, "invalid instruction"); + } + + llvm_unreachable("Unexpected match type"); +} + +SystemZAsmParser::OperandMatchResultTy SystemZAsmParser:: +parseAccessReg(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + Register Reg; + if (parseRegister(Reg)) + return MatchOperand_NoMatch; + if (Reg.Prefix != 'a' || Reg.Number > 15) { + Error(Reg.StartLoc, "invalid register"); + return MatchOperand_ParseFail; + } + Operands.push_back(SystemZOperand::createAccessReg(Reg.Number, + Reg.StartLoc, Reg.EndLoc)); + return MatchOperand_Success; +} + +// Force static initialization. +extern "C" void LLVMInitializeSystemZAsmParser() { + RegisterMCAsmParser<SystemZAsmParser> X(TheSystemZTarget); +} diff --git a/lib/Target/SystemZ/CMakeLists.txt b/lib/Target/SystemZ/CMakeLists.txt new file mode 100644 index 0000000000..67b17fcc59 --- /dev/null +++ b/lib/Target/SystemZ/CMakeLists.txt @@ -0,0 +1,32 @@ +set(LLVM_TARGET_DEFINITIONS SystemZ.td) + +tablegen(LLVM SystemZGenAsmMatcher.inc -gen-asm-matcher) +tablegen(LLVM SystemZGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM SystemZGenCallingConv.inc -gen-callingconv) +tablegen(LLVM SystemZGenDAGISel.inc -gen-dag-isel) +tablegen(LLVM SystemZGenMCCodeEmitter.inc -gen-emitter -mc-emitter) +tablegen(LLVM SystemZGenInstrInfo.inc -gen-instr-info) +tablegen(LLVM SystemZGenRegisterInfo.inc -gen-register-info) +tablegen(LLVM SystemZGenSubtargetInfo.inc -gen-subtarget) +add_public_tablegen_target(SystemZCommonTableGen) + +add_llvm_target(SystemZCodeGen + SystemZAsmPrinter.cpp + SystemZCallingConv.cpp + SystemZConstantPoolValue.cpp + SystemZFrameLowering.cpp + SystemZISelDAGToDAG.cpp + SystemZISelLowering.cpp + SystemZInstrInfo.cpp + SystemZMCInstLower.cpp + SystemZRegisterInfo.cpp + SystemZSubtarget.cpp + SystemZTargetMachine.cpp + ) + +add_dependencies(LLVMSystemZCodeGen intrinsics_gen) + +add_subdirectory(AsmParser) +add_subdirectory(InstPrinter) +add_subdirectory(TargetInfo) +add_subdirectory(MCTargetDesc) diff --git a/lib/Target/SystemZ/InstPrinter/CMakeLists.txt b/lib/Target/SystemZ/InstPrinter/CMakeLists.txt new file mode 100644 index 0000000000..ddbf82fe16 --- /dev/null +++ b/lib/Target/SystemZ/InstPrinter/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMSystemZAsmPrinter + SystemZInstPrinter.cpp + ) + +add_dependencies(LLVMSystemZAsmPrinter SystemZCommonTableGen) diff --git a/lib/Target/SystemZ/InstPrinter/LLVMBuild.txt b/lib/Target/SystemZ/InstPrinter/LLVMBuild.txt new file mode 100644 index 0000000000..fdfd738683 --- /dev/null +++ b/lib/Target/SystemZ/InstPrinter/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/SystemZ/InstPrinter/LLVMBuild.txt -----------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = SystemZAsmPrinter +parent = SystemZ +required_libraries = MC Support +add_to_library_groups = SystemZ diff --git a/lib/Target/SystemZ/InstPrinter/Makefile b/lib/Target/SystemZ/InstPrinter/Makefile new file mode 100644 index 0000000000..3ba8126735 --- /dev/null +++ b/lib/Target/SystemZ/InstPrinter/Makefile @@ -0,0 +1,16 @@ +##===- lib/Target/SystemZ/AsmPrinter/Makefile --------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME = LLVMSystemZAsmPrinter + +# Hack: we need to include 'main' mips target directory to grab private headers +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp b/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp new file mode 100644 index 0000000000..d73cf49808 --- /dev/null +++ b/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp @@ -0,0 +1,150 @@ +//===-- SystemZInstPrinter.cpp - Convert SystemZ MCInst to assembly syntax ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" + +#include "SystemZInstPrinter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#include "SystemZGenAsmWriter.inc" + +void SystemZInstPrinter::printAddress(unsigned Base, int64_t Disp, + unsigned Index, raw_ostream &O) { + O << Disp; + if (Base) { + O << '('; + if (Index) + O << '%' << getRegisterName(Index) << ','; + O << '%' << getRegisterName(Base) << ')'; + } else + assert(!Index && "Shouldn't have an index without a base"); +} + +void SystemZInstPrinter::printOperand(const MCOperand &MO, raw_ostream &O) { + if (MO.isReg()) + O << '%' << getRegisterName(MO.getReg()); + else if (MO.isImm()) + O << MO.getImm(); + else if (MO.isExpr()) + O << *MO.getExpr(); + else + llvm_unreachable("Invalid operand"); +} + +void SystemZInstPrinter::printInst(const MCInst *MI, raw_ostream &O, + StringRef Annot) { + printInstruction(MI, O); + printAnnotation(O, Annot); +} + +void SystemZInstPrinter::printRegName(raw_ostream &O, unsigned RegNo) const { + O << '%' << getRegisterName(RegNo); +} + +void SystemZInstPrinter::printU4ImmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert(isUInt<4>(Value) && "Invalid u4imm argument"); + O << Value; +} + +void SystemZInstPrinter::printU6ImmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert(isUInt<6>(Value) && "Invalid u6imm argument"); + O << Value; +} + +void SystemZInstPrinter::printS8ImmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert(isInt<8>(Value) && "Invalid s8imm argument"); + O << Value; +} + +void SystemZInstPrinter::printU8ImmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert(isUInt<8>(Value) && "Invalid u8imm argument"); + O << Value; +} + +void SystemZInstPrinter::printS16ImmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert(isInt<16>(Value) && "Invalid s16imm argument"); + O << Value; +} + +void SystemZInstPrinter::printU16ImmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert(isUInt<16>(Value) && "Invalid u16imm argument"); + O << Value; +} + +void SystemZInstPrinter::printS32ImmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert(isInt<32>(Value) && "Invalid s32imm argument"); + O << Value; +} + +void SystemZInstPrinter::printU32ImmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert(isUInt<32>(Value) && "Invalid u32imm argument"); + O << Value; +} + +void SystemZInstPrinter::printAccessRegOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + uint64_t Value = MI->getOperand(OpNum).getImm(); + assert(Value < 16 && "Invalid access register number"); + O << "%a" << (unsigned int)Value; +} + +void SystemZInstPrinter::printCallOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + printOperand(MI, OpNum, O); + O << "@PLT"; +} + +void SystemZInstPrinter::printOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + printOperand(MI->getOperand(OpNum), O); +} + +void SystemZInstPrinter::printBDAddrOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + printAddress(MI->getOperand(OpNum).getReg(), + MI->getOperand(OpNum + 1).getImm(), 0, O); +} + +void SystemZInstPrinter::printBDXAddrOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + printAddress(MI->getOperand(OpNum).getReg(), + MI->getOperand(OpNum + 1).getImm(), + MI->getOperand(OpNum + 2).getReg(), O); +} + +void SystemZInstPrinter::printCond4Operand(const MCInst *MI, int OpNum, + raw_ostream &O) { + static const char *const CondNames[] = { + "o", "h", "nle", "l", "nhe", "lh", "ne", + "e", "nlh", "he", "nl", "le", "nh", "no" + }; + uint64_t Imm = MI->getOperand(OpNum).getImm(); + assert(Imm > 0 && Imm < 15 && "Invalid condition"); + O << CondNames[Imm - 1]; +} diff --git a/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h b/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h new file mode 100644 index 0000000000..b82e79d93c --- /dev/null +++ b/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h @@ -0,0 +1,68 @@ +//==- SystemZInstPrinter.h - Convert SystemZ MCInst to assembly --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints a SystemZ MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEMZINSTPRINTER_H +#define LLVM_SYSTEMZINSTPRINTER_H + +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { +class MCOperand; + +class SystemZInstPrinter : public MCInstPrinter { +public: + SystemZInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, + const MCRegisterInfo &MRI) + : MCInstPrinter(MAI, MII, MRI) {} + + // Automatically generated by tblgen. + void printInstruction(const MCInst *MI, raw_ostream &O); + static const char *getRegisterName(unsigned RegNo); + + // Print an address with the given base, displacement and index. + static void printAddress(unsigned Base, int64_t Disp, unsigned Index, + raw_ostream &O); + + // Print the given operand. + static void printOperand(const MCOperand &MO, raw_ostream &O); + + // Override MCInstPrinter. + virtual void printRegName(raw_ostream &O, unsigned RegNo) const + LLVM_OVERRIDE; + virtual void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot) + LLVM_OVERRIDE; + +private: + // Print various types of operand. + void printOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printBDAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printBDXAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printU4ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printU6ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printS8ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printU8ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printS16ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printU16ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printS32ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printU32ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printCallOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printAccessRegOperand(const MCInst *MI, int OpNum, raw_ostream &O); + + // Print the mnemonic for a condition-code mask ("ne", "lh", etc.) + // This forms part of the instruction name rather than the operand list. + void printCond4Operand(const MCInst *MI, int OpNum, raw_ostream &O); +}; +} // end namespace llvm + +#endif diff --git a/lib/Target/SystemZ/LLVMBuild.txt b/lib/Target/SystemZ/LLVMBuild.txt new file mode 100644 index 0000000000..aba0de27ac --- /dev/null +++ b/lib/Target/SystemZ/LLVMBuild.txt @@ -0,0 +1,34 @@ +;===- ./lib/Target/SystemZ/LLVMBuild.txt -----------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[common] +subdirectories = AsmParser InstPrinter MCTargetDesc TargetInfo + +[component_0] +type = TargetGroup +name = SystemZ +parent = Target +has_asmparser = 1 +has_asmprinter = 1 +has_jit = 1 + +[component_1] +type = Library +name = SystemZCodeGen +parent = SystemZ +required_libraries = AsmPrinter CodeGen Core MC SelectionDAG SystemZDesc SystemZInfo Support Target +add_to_library_groups = SystemZ diff --git a/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt b/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt new file mode 100644 index 0000000000..3d131288c7 --- /dev/null +++ b/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt @@ -0,0 +1,9 @@ +add_llvm_library(LLVMSystemZDesc + SystemZMCAsmBackend.cpp + SystemZMCAsmInfo.cpp + SystemZMCCodeEmitter.cpp + SystemZMCObjectWriter.cpp + SystemZMCTargetDesc.cpp + ) + +add_dependencies(LLVMSystemZDesc SystemZCommonTableGen) diff --git a/lib/Target/SystemZ/MCTargetDesc/LLVMBuild.txt b/lib/Target/SystemZ/MCTargetDesc/LLVMBuild.txt new file mode 100644 index 0000000000..cbdb59ce31 --- /dev/null +++ b/lib/Target/SystemZ/MCTargetDesc/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/SystemZ/MCTargetDesc/LLVMBuild.txt ----------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = SystemZDesc +parent = SystemZ +required_libraries = MC SystemZAsmPrinter SystemZInfo Support +add_to_library_groups = SystemZ diff --git a/lib/Target/SystemZ/MCTargetDesc/Makefile b/lib/Target/SystemZ/MCTargetDesc/Makefile new file mode 100644 index 0000000000..08f1a9d51f --- /dev/null +++ b/lib/Target/SystemZ/MCTargetDesc/Makefile @@ -0,0 +1,16 @@ +##===- lib/Target/SystemZ/TargetDesc/Makefile --------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME = LLVMSystemZDesc + +# Hack: we need to include 'main' target directory to grab private headers +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp b/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp new file mode 100644 index 0000000000..e901c6c691 --- /dev/null +++ b/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp @@ -0,0 +1,151 @@ +//===-- SystemZMCAsmBackend.cpp - SystemZ assembler backend ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/SystemZMCTargetDesc.h" +#include "MCTargetDesc/SystemZMCFixups.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCObjectWriter.h" + +using namespace llvm; + +// Value is a fully-resolved relocation value: Symbol + Addend [- Pivot]. +// Return the bits that should be installed in a relocation field for +// fixup kind Kind. +static uint64_t extractBitsForFixup(MCFixupKind Kind, uint64_t Value) { + if (Kind < FirstTargetFixupKind) + return Value; + + switch (unsigned(Kind)) { + case SystemZ::FK_390_PC16DBL: + case SystemZ::FK_390_PC32DBL: + case SystemZ::FK_390_PLT16DBL: + case SystemZ::FK_390_PLT32DBL: + return (int64_t)Value / 2; + } + + llvm_unreachable("Unknown fixup kind!"); +} + +// If Opcode can be relaxed, return the relaxed form, otherwise return 0. +static unsigned getRelaxedOpcode(unsigned Opcode) { + switch (Opcode) { + case SystemZ::BRC: return SystemZ::BRCL; + case SystemZ::J: return SystemZ::JG; + case SystemZ::BRAS: return SystemZ::BRASL; + } + return 0; +} + +namespace { +class SystemZMCAsmBackend : public MCAsmBackend { + uint8_t OSABI; +public: + SystemZMCAsmBackend(uint8_t osABI) + : OSABI(osABI) {} + + // Override MCAsmBackend + virtual unsigned getNumFixupKinds() const LLVM_OVERRIDE { + return SystemZ::NumTargetFixupKinds; + } + virtual const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const + LLVM_OVERRIDE; + virtual void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, + uint64_t Value) const LLVM_OVERRIDE; + virtual bool mayNeedRelaxation(const MCInst &Inst) const LLVM_OVERRIDE; + virtual bool fixupNeedsRelaxation(const MCFixup &Fixup, + uint64_t Value, + const MCRelaxableFragment *Fragment, + const MCAsmLayout &Layout) const + LLVM_OVERRIDE; + virtual void relaxInstruction(const MCInst &Inst, + MCInst &Res) const LLVM_OVERRIDE; + virtual bool writeNopData(uint64_t Count, + MCObjectWriter *OW) const LLVM_OVERRIDE; + virtual MCObjectWriter *createObjectWriter(raw_ostream &OS) const + LLVM_OVERRIDE { + return createSystemZObjectWriter(OS, OSABI); + } + virtual bool doesSectionRequireSymbols(const MCSection &Section) const + LLVM_OVERRIDE { + return false; + } +}; +} // end anonymous namespace + +const MCFixupKindInfo & +SystemZMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { + const static MCFixupKindInfo Infos[SystemZ::NumTargetFixupKinds] = { + { "FK_390_PC16DBL", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "FK_390_PC32DBL", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, + { "FK_390_PLT16DBL", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "FK_390_PLT32DBL", 0, 32, MCFixupKindInfo::FKF_IsPCRel } + }; + + if (Kind < FirstTargetFixupKind) + return MCAsmBackend::getFixupKindInfo(Kind); + + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + return Infos[Kind - FirstTargetFixupKind]; +} + +void SystemZMCAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, + unsigned DataSize, uint64_t Value) const { + MCFixupKind Kind = Fixup.getKind(); + unsigned Offset = Fixup.getOffset(); + unsigned Size = (getFixupKindInfo(Kind).TargetSize + 7) / 8; + + assert(Offset + Size <= DataSize && "Invalid fixup offset!"); + + // Big-endian insertion of Size bytes. + Value = extractBitsForFixup(Kind, Value); + unsigned ShiftValue = (Size * 8) - 8; + for (unsigned I = 0; I != Size; ++I) { + Data[Offset + I] |= uint8_t(Value >> ShiftValue); + ShiftValue -= 8; + } +} + +bool SystemZMCAsmBackend::mayNeedRelaxation(const MCInst &Inst) const { + return getRelaxedOpcode(Inst.getOpcode()) != 0; +} + +bool +SystemZMCAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, + uint64_t Value, + const MCRelaxableFragment *Fragment, + const MCAsmLayout &Layout) const { + // At the moment we just need to relax 16-bit fields to wider fields. + Value = extractBitsForFixup(Fixup.getKind(), Value); + return (int16_t)Value != (int64_t)Value; +} + +void SystemZMCAsmBackend::relaxInstruction(const MCInst &Inst, + MCInst &Res) const { + unsigned Opcode = getRelaxedOpcode(Inst.getOpcode()); + assert(Opcode && "Unexpected insn to relax"); + Res = Inst; + Res.setOpcode(Opcode); +} + +bool SystemZMCAsmBackend::writeNopData(uint64_t Count, + MCObjectWriter *OW) const { + for (uint64_t I = 0; I != Count; ++I) + OW->Write8(7); + return true; +} + +MCAsmBackend *llvm::createSystemZMCAsmBackend(const Target &T, StringRef TT, + StringRef CPU) { + uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(Triple(TT).getOS()); + return new SystemZMCAsmBackend(OSABI); +} diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp b/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp new file mode 100644 index 0000000000..c96a0d4c67 --- /dev/null +++ b/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp @@ -0,0 +1,38 @@ +//===-- 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. +// +//===----------------------------------------------------------------------===// + +#include "SystemZMCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" + +using namespace llvm; + +SystemZMCAsmInfo::SystemZMCAsmInfo(const Target &T, StringRef TT) { + PointerSize = 8; + CalleeSaveStackSlotSize = 8; + IsLittleEndian = false; + + CommentString = "#"; + PCSymbol = "."; + GlobalPrefix = ""; + PrivateGlobalPrefix = ".L"; + WeakRefDirective = "\t.weak\t"; + ZeroDirective = "\t.space\t"; + Data64bitsDirective = "\t.quad\t"; + UsesELFSectionDirectiveForBSS = true; + SupportsDebugInformation = true; + HasLEB128 = true; + ExceptionsType = ExceptionHandling::DwarfCFI; +} + +const MCSection * +SystemZMCAsmInfo::getNonexecutableStackSection(MCContext &Ctx) const { + return Ctx.getELFSection(".note.GNU-stack", ELF::SHT_PROGBITS, + 0, SectionKind::getMetadata()); +} diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h b/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h new file mode 100644 index 0000000000..bac1bca381 --- /dev/null +++ b/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h @@ -0,0 +1,31 @@ +//====-- 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. +// +//===----------------------------------------------------------------------===// + +#ifndef SystemZTARGETASMINFO_H +#define SystemZTARGETASMINFO_H + +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { +class Target; +class StringRef; + +class SystemZMCAsmInfo : public MCAsmInfo { +public: + explicit SystemZMCAsmInfo(const Target &T, StringRef TT); + + // Override MCAsmInfo; + virtual const MCSection *getNonexecutableStackSection(MCContext &Ctx) const + LLVM_OVERRIDE; +}; + +} // namespace llvm + +#endif diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp b/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp new file mode 100644 index 0000000000..ea2250f546 --- /dev/null +++ b/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp @@ -0,0 +1,131 @@ +//===-- SystemZMCCodeEmitter.cpp - Convert SystemZ code to machine code ---===// +// +// 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 SystemZMCCodeEmitter class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mccodeemitter" +#include "MCTargetDesc/SystemZMCTargetDesc.h" +#include "MCTargetDesc/SystemZMCFixups.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInstrInfo.h" + +using namespace llvm; + +namespace { +class SystemZMCCodeEmitter : public MCCodeEmitter { + const MCInstrInfo &MCII; + MCContext &Ctx; + +public: + SystemZMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx) + : MCII(mcii), Ctx(ctx) { + } + + ~SystemZMCCodeEmitter() {} + + // OVerride MCCodeEmitter. + virtual void EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups) const + LLVM_OVERRIDE; + +private: + // Automatically generated by TableGen. + uint64_t getBinaryCodeForInstr(const MCInst &MI, + SmallVectorImpl<MCFixup> &Fixups) const; + + // Called by the TableGen code to get the binary encoding of operand + // MO in MI. Fixups is the list of fixups against MI. + unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl<MCFixup> &Fixups) const; + + // Operand OpNum of MI needs a PC-relative fixup of kind Kind at + // Offset bytes from the start of MI. Add the fixup to Fixups + // and return the in-place addend, which since we're a RELA target + // is always 0. + unsigned getPCRelEncoding(const MCInst &MI, unsigned int OpNum, + SmallVectorImpl<MCFixup> &Fixups, + unsigned Kind, int64_t Offset) const; + + unsigned getPC16DBLEncoding(const MCInst &MI, unsigned int OpNum, + SmallVectorImpl<MCFixup> &Fixups) const { + return getPCRelEncoding(MI, OpNum, Fixups, SystemZ::FK_390_PC16DBL, 2); + } + unsigned getPC32DBLEncoding(const MCInst &MI, unsigned int OpNum, + SmallVectorImpl<MCFixup> &Fixups) const { + return getPCRelEncoding(MI, OpNum, Fixups, SystemZ::FK_390_PC32DBL, 2); + } + unsigned getPLT16DBLEncoding(const MCInst &MI, unsigned int OpNum, + SmallVectorImpl<MCFixup> &Fixups) const { + return getPCRelEncoding(MI, OpNum, Fixups, SystemZ::FK_390_PLT16DBL, 2); + } + unsigned getPLT32DBLEncoding(const MCInst &MI, unsigned int OpNum, + SmallVectorImpl<MCFixup> &Fixups) const { + return getPCRelEncoding(MI, OpNum, Fixups, SystemZ::FK_390_PLT32DBL, 2); + } +}; +} + +MCCodeEmitter *llvm::createSystemZMCCodeEmitter(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &MCSTI, + MCContext &Ctx) { + return new SystemZMCCodeEmitter(MCII, Ctx); +} + +void SystemZMCCodeEmitter:: +EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups) const { + uint64_t Bits = getBinaryCodeForInstr(MI, Fixups); + unsigned Size = MCII.get(MI.getOpcode()).getSize(); + // Big-endian insertion of Size bytes. + unsigned ShiftValue = (Size * 8) - 8; + for (unsigned I = 0; I != Size; ++I) { + OS << uint8_t(Bits >> ShiftValue); + ShiftValue -= 8; + } +} + +unsigned SystemZMCCodeEmitter:: +getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl<MCFixup> &Fixups) const { + if (MO.isReg()) + return Ctx.getRegisterInfo().getEncodingValue(MO.getReg()); + if (MO.isImm()) + return static_cast<unsigned>(MO.getImm()); + llvm_unreachable("Unexpected operand type!"); +} + +unsigned +SystemZMCCodeEmitter::getPCRelEncoding(const MCInst &MI, unsigned int OpNum, + SmallVectorImpl<MCFixup> &Fixups, + unsigned Kind, int64_t Offset) const { + const MCOperand &MO = MI.getOperand(OpNum); + // For compatibility with the GNU assembler, treat constant operands as + // unadjusted PC-relative offsets. + if (MO.isImm()) + return MO.getImm() / 2; + + const MCExpr *Expr = MO.getExpr(); + if (Offset) { + // The operand value is relative to the start of MI, but the fixup + // is relative to the operand field itself, which is Offset bytes + // into MI. Add Offset to the relocation value to cancel out + // this difference. + const MCExpr *OffsetExpr = MCConstantExpr::Create(Offset, Ctx); + Expr = MCBinaryExpr::CreateAdd(Expr, OffsetExpr, Ctx); + } + Fixups.push_back(MCFixup::Create(Offset, Expr, (MCFixupKind)Kind)); + return 0; +} + +#include "SystemZGenMCCodeEmitter.inc" diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCFixups.h b/lib/Target/SystemZ/MCTargetDesc/SystemZMCFixups.h new file mode 100644 index 0000000000..9c94ebbaac --- /dev/null +++ b/lib/Target/SystemZ/MCTargetDesc/SystemZMCFixups.h @@ -0,0 +1,31 @@ +//===-- SystemZMCFixups.h - SystemZ-specific fixup entries ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEMZMCFIXUPS_H +#define LLVM_SYSTEMZMCFIXUPS_H + +#include "llvm/MC/MCFixup.h" + +namespace llvm { +namespace SystemZ { + enum FixupKind { + // These correspond directly to R_390_* relocations. + FK_390_PC16DBL = FirstTargetFixupKind, + FK_390_PC32DBL, + FK_390_PLT16DBL, + FK_390_PLT32DBL, + + // Marker + LastTargetFixupKind, + NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind + }; +} +} // end namespace llvm + +#endif diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp b/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp new file mode 100644 index 0000000000..36e3d83d4d --- /dev/null +++ b/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp @@ -0,0 +1,140 @@ +//===-- SystemZMCObjectWriter.cpp - SystemZ ELF writer --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/SystemZMCTargetDesc.h" +#include "MCTargetDesc/SystemZMCFixups.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCValue.h" + +using namespace llvm; + +namespace { +class SystemZObjectWriter : public MCELFObjectTargetWriter { +public: + SystemZObjectWriter(uint8_t OSABI); + + virtual ~SystemZObjectWriter(); + +protected: + // Override MCELFObjectTargetWriter. + virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel, bool IsRelocWithSymbol, + int64_t Addend) const LLVM_OVERRIDE; + virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + const MCFixup &Fixup, + bool IsPCRel) const LLVM_OVERRIDE; +}; +} // end anonymouse namespace + +SystemZObjectWriter::SystemZObjectWriter(uint8_t OSABI) + : MCELFObjectTargetWriter(/*Is64Bit=*/true, OSABI, ELF::EM_S390, + /*HasRelocationAddend=*/ true) {} + +SystemZObjectWriter::~SystemZObjectWriter() { +} + +// Return the relocation type for an absolute value of MCFixupKind Kind. +static unsigned getAbsoluteReloc(unsigned Kind) { + switch (Kind) { + case FK_Data_1: return ELF::R_390_8; + case FK_Data_2: return ELF::R_390_16; + case FK_Data_4: return ELF::R_390_32; + case FK_Data_8: return ELF::R_390_64; + } + llvm_unreachable("Unsupported absolute address"); +} + +// Return the relocation type for a PC-relative value of MCFixupKind Kind. +static unsigned getPCRelReloc(unsigned Kind) { + switch (Kind) { + case FK_Data_2: return ELF::R_390_PC16; + case FK_Data_4: return ELF::R_390_PC32; + case FK_Data_8: return ELF::R_390_PC64; + case SystemZ::FK_390_PC16DBL: return ELF::R_390_PC16DBL; + case SystemZ::FK_390_PC32DBL: return ELF::R_390_PC32DBL; + case SystemZ::FK_390_PLT16DBL: return ELF::R_390_PLT16DBL; + case SystemZ::FK_390_PLT32DBL: return ELF::R_390_PLT32DBL; + } + llvm_unreachable("Unsupported PC-relative address"); +} + +// Return the R_390_TLS_LE* relocation type for MCFixupKind Kind. +static unsigned getTLSLEReloc(unsigned Kind) { + switch (Kind) { + case FK_Data_4: return ELF::R_390_TLS_LE32; + case FK_Data_8: return ELF::R_390_TLS_LE64; + } + llvm_unreachable("Unsupported absolute address"); +} + +// Return the PLT relocation counterpart of MCFixupKind Kind. +static unsigned getPLTReloc(unsigned Kind) { + switch (Kind) { + case SystemZ::FK_390_PC16DBL: return ELF::R_390_PLT16DBL; + case SystemZ::FK_390_PC32DBL: return ELF::R_390_PLT32DBL; + } + llvm_unreachable("Unsupported absolute address"); +} + +unsigned SystemZObjectWriter::GetRelocType(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel, + bool IsRelocWithSymbol, + int64_t Addend) const { + MCSymbolRefExpr::VariantKind Modifier = (Target.isAbsolute() ? + MCSymbolRefExpr::VK_None : + Target.getSymA()->getKind()); + unsigned Kind = Fixup.getKind(); + switch (Modifier) { + case MCSymbolRefExpr::VK_None: + if (IsPCRel) + return getPCRelReloc(Kind); + return getAbsoluteReloc(Kind); + + case MCSymbolRefExpr::VK_NTPOFF: + assert(!IsPCRel && "NTPOFF shouldn't be PC-relative"); + return getTLSLEReloc(Kind); + + case MCSymbolRefExpr::VK_GOT: + if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) + return ELF::R_390_GOTENT; + llvm_unreachable("Only PC-relative GOT accesses are supported for now"); + + case MCSymbolRefExpr::VK_PLT: + assert(IsPCRel && "@PLT shouldt be PC-relative"); + return getPLTReloc(Kind); + + default: + llvm_unreachable("Modifier not supported"); + } +} + +const MCSymbol *SystemZObjectWriter::ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + const MCFixup &Fixup, + bool IsPCRel) const { + // The addend in a PC-relative R_390_* relocation is always applied to + // the PC-relative part of the address. If some kind of indirection + // is applied to the symbol first, we can't use an addend there too. + if (!Target.isAbsolute() && + Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None && + IsPCRel) + return &Target.getSymA()->getSymbol().AliasedSymbol(); + return NULL; +} + +MCObjectWriter *llvm::createSystemZObjectWriter(raw_ostream &OS, + uint8_t OSABI) { + MCELFObjectTargetWriter *MOTW = new SystemZObjectWriter(OSABI); + return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false); +} diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp b/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp new file mode 100644 index 0000000000..20eb98d8d6 --- /dev/null +++ b/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp @@ -0,0 +1,160 @@ +//===-- SystemZMCTargetDesc.cpp - SystemZ target descriptions -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SystemZMCTargetDesc.h" +#include "InstPrinter/SystemZInstPrinter.h" +#include "SystemZMCAsmInfo.h" +#include "llvm/MC/MCCodeGenInfo.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCStreamer.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 MCAsmInfo *createSystemZMCAsmInfo(const Target &T, StringRef TT) { + MCAsmInfo *MAI = new SystemZMCAsmInfo(T, TT); + MachineLocation FPDst(MachineLocation::VirtualFP); + MachineLocation FPSrc(SystemZ::R15D, -SystemZMC::CFAOffsetFromInitialSP); + MAI->addInitialFrameState(0, FPDst, FPSrc); + return MAI; +} + +static MCInstrInfo *createSystemZMCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitSystemZMCInstrInfo(X); + return X; +} + +static MCRegisterInfo *createSystemZMCRegisterInfo(StringRef TT) { + MCRegisterInfo *X = new MCRegisterInfo(); + InitSystemZMCRegisterInfo(X, SystemZ::R14D); + 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, + CodeGenOpt::Level) { + MCCodeGenInfo *X = new MCCodeGenInfo(); + + // Static code is suitable for use in a dynamic executable; there is no + // separate DynamicNoPIC model. + if (RM == Reloc::Default || RM == Reloc::DynamicNoPIC) + RM = Reloc::Static; + + // For SystemZ we define the models as follows: + // + // Small: BRASL can call any function and will use a stub if necessary. + // Locally-binding symbols will always be in range of LARL. + // + // Medium: BRASL can call any function and will use a stub if necessary. + // GOT slots and locally-defined text will always be in range + // of LARL, but other symbols might not be. + // + // Large: Equivalent to Medium for now. + // + // Kernel: Equivalent to Medium for now. + // + // This means that any PIC module smaller than 4GB meets the + // requirements of Small, so Small seems like the best default there. + // + // All symbols bind locally in a non-PIC module, so the choice is less + // obvious. There are two cases: + // + // - When creating an executable, PLTs and copy relocations allow + // us to treat external symbols as part of the executable. + // Any executable smaller than 4GB meets the requirements of Small, + // so that seems like the best default. + // + // - When creating JIT code, stubs will be in range of BRASL if the + // image is less than 4GB in size. GOT entries will likewise be + // in range of LARL. However, the JIT environment has no equivalent + // of copy relocs, so locally-binding data symbols might not be in + // the range of LARL. We need the Medium model in that case. + if (CM == CodeModel::Default) + CM = CodeModel::Small; + else if (CM == CodeModel::JITDefault) + CM = RM == Reloc::PIC_ ? CodeModel::Small : CodeModel::Medium; + X->InitMCCodeGenInfo(RM, CM); + return X; +} + +static MCInstPrinter *createSystemZMCInstPrinter(const Target &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI) { + return new SystemZInstPrinter(MAI, MII, MRI); +} + +static MCStreamer *createSystemZMCObjectStreamer(const Target &T, StringRef TT, + MCContext &Ctx, + MCAsmBackend &MAB, + raw_ostream &OS, + MCCodeEmitter *Emitter, + bool RelaxAll, + bool NoExecStack) { + return createELFStreamer(Ctx, MAB, OS, Emitter, RelaxAll, NoExecStack); +} + +extern "C" void LLVMInitializeSystemZTargetMC() { + // Register the MCAsmInfo. + TargetRegistry::RegisterMCAsmInfo(TheSystemZTarget, + createSystemZMCAsmInfo); + + // Register the MCCodeGenInfo. + TargetRegistry::RegisterMCCodeGenInfo(TheSystemZTarget, + createSystemZMCCodeGenInfo); + + // Register the MCCodeEmitter. + TargetRegistry::RegisterMCCodeEmitter(TheSystemZTarget, + createSystemZMCCodeEmitter); + + // Register the MCInstrInfo. + TargetRegistry::RegisterMCInstrInfo(TheSystemZTarget, + createSystemZMCInstrInfo); + + // Register the MCRegisterInfo. + TargetRegistry::RegisterMCRegInfo(TheSystemZTarget, + createSystemZMCRegisterInfo); + + // Register the MCSubtargetInfo. + TargetRegistry::RegisterMCSubtargetInfo(TheSystemZTarget, + createSystemZMCSubtargetInfo); + + // Register the MCAsmBackend. + TargetRegistry::RegisterMCAsmBackend(TheSystemZTarget, + createSystemZMCAsmBackend); + + // Register the MCInstPrinter. + TargetRegistry::RegisterMCInstPrinter(TheSystemZTarget, + createSystemZMCInstPrinter); + + // Register the MCObjectStreamer; + TargetRegistry::RegisterMCObjectStreamer(TheSystemZTarget, + createSystemZMCObjectStreamer); +} diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h b/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h new file mode 100644 index 0000000000..229912f161 --- /dev/null +++ b/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h @@ -0,0 +1,62 @@ +//===-- 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. +// +//===----------------------------------------------------------------------===// + +#ifndef SYSTEMZMCTARGETDESC_H +#define SYSTEMZMCTARGETDESC_H + +#include "llvm/Support/DataTypes.h" + +namespace llvm { + +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCInstrInfo; +class MCObjectWriter; +class MCRegisterInfo; +class MCSubtargetInfo; +class StringRef; +class Target; +class raw_ostream; + +extern Target TheSystemZTarget; + +namespace SystemZMC { + // How many bytes are in the ABI-defined, caller-allocated part of + // a stack frame. + const int64_t CallFrameSize = 160; + + // The offset of the DWARF CFA from the incoming stack pointer. + const int64_t CFAOffsetFromInitialSP = CallFrameSize; +} + +MCCodeEmitter *createSystemZMCCodeEmitter(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI, + MCContext &Ctx); + +MCAsmBackend *createSystemZMCAsmBackend(const Target &T, StringRef TT, + StringRef CPU); + +MCObjectWriter *createSystemZObjectWriter(raw_ostream &OS, uint8_t OSABI); +} // end namespace llvm + +// 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/lib/Target/SystemZ/Makefile b/lib/Target/SystemZ/Makefile new file mode 100644 index 0000000000..c992584af9 --- /dev/null +++ b/lib/Target/SystemZ/Makefile @@ -0,0 +1,28 @@ +##===- lib/Target/SystemZ/Makefile -------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +LIBRARYNAME = LLVMSystemZCodeGen +TARGET = SystemZ + +# Make sure that tblgen is run, first thing. +BUILT_SOURCES = SystemZGenRegisterInfo.inc \ + SystemZGenAsmWriter.inc \ + SystemZGenAsmMatcher.inc \ + SystemZGenCodeEmitter.inc \ + SystemZGenInstrInfo.inc \ + SystemZGenDAGISel.inc \ + SystemZGenSubtargetInfo.inc \ + SystemZGenCallingConv.inc \ + SystemZGenMCCodeEmitter.inc + +DIRS = InstPrinter AsmParser TargetInfo MCTargetDesc + +include $(LEVEL)/Makefile.common + diff --git a/lib/Target/SystemZ/README.txt b/lib/Target/SystemZ/README.txt new file mode 100644 index 0000000000..d1f56a4916 --- /dev/null +++ b/lib/Target/SystemZ/README.txt @@ -0,0 +1,146 @@ +//===---------------------------------------------------------------------===// +// Random notes about and ideas for the SystemZ backend. +//===---------------------------------------------------------------------===// + +The initial backend is deliberately restricted to z10. We should add support +for later architectures at some point. + +-- + +SystemZDAGToDAGISel::SelectInlineAsmMemoryOperand() is passed "m" for all +inline asm memory constraints; it doesn't get to see the original constraint. +This means that it must conservatively treat all inline asm constraints +as the most restricted type, "R". + +-- + +If an inline asm ties an i32 "r" result to an i64 input, the input +will be treated as an i32, leaving the upper bits uninitialised. +For example: + +define void @f4(i32 *%dst) { + %val = call i32 asm "blah $0", "=r,0" (i64 103) + store i32 %val, i32 *%dst + ret void +} + +from CodeGen/SystemZ/asm-09.ll will use LHI rather than LGHI. +to load 103. This seems to be a general target-independent problem. + +-- + +The tuning of the choice between Load Address (LA) and addition in +SystemZISelDAGToDAG.cpp is suspect. It should be tweaked based on +performance measurements. + +-- + +There is no scheduling support. + +-- + +We don't use the Branch on Count or Branch on Index families of instruction. + +-- + +We don't use the condition code results of anything except comparisons. + +Implementing this may need something more finely grained than the z_cmp +and z_ucmp that we have now. It might (or might not) also be useful to +have a mask of "don't care" values in conditional branches. For example, +integer comparisons never set CC to 3, so the bottom bit of the CC mask +isn't particularly relevant. JNLH and JE are equally good for testing +equality after an integer comparison, etc. + +-- + +We don't optimize string and block memory operations. + +-- + +We don't take full advantage of builtins like fabsl because the calling +conventions require f128s to be returned by invisible reference. + +-- + +DAGCombiner can detect integer absolute, but there's not yet an associated +ISD opcode. We could add one and implement it using Load Positive. +Negated absolutes could use Load Negative. + +-- + +DAGCombiner doesn't yet fold truncations of extended loads. Functions like: + + unsigned long f (unsigned long x, unsigned short *y) + { + return (x << 32) | *y; + } + +therefore end up as: + + sllg %r2, %r2, 32 + llgh %r0, 0(%r3) + lr %r2, %r0 + br %r14 + +but truncating the load would give: + + sllg %r2, %r2, 32 + lh %r2, 0(%r3) + br %r14 + +-- + +Functions like: + +define i64 @f1(i64 %a) { + %and = and i64 %a, 1 + ret i64 %and +} + +ought to be implemented as: + + lhi %r0, 1 + ngr %r2, %r0 + br %r14 + +but two-address optimisations reverse the order of the AND and force: + + lhi %r0, 1 + ngr %r0, %r2 + lgr %r2, %r0 + br %r14 + +CodeGen/SystemZ/and-04.ll has several examples of this. + +-- + +Out-of-range displacements are usually handled by loading the full +address into a register. In many cases it would be better to create +an anchor point instead. E.g. for: + +define void @f4a(i128 *%aptr, i64 %base) { + %addr = add i64 %base, 524288 + %bptr = inttoptr i64 %addr to i128 * + %a = load volatile i128 *%aptr + %b = load i128 *%bptr + %add = add i128 %a, %b + store i128 %add, i128 *%aptr + ret void +} + +(from CodeGen/SystemZ/int-add-08.ll) we load %base+524288 and %base+524296 +into separate registers, rather than using %base+524288 as a base for both. + +-- + +Dynamic stack allocations round the size to 8 bytes and then allocate +that rounded amount. It would be simpler to subtract the unrounded +size from the copy of the stack pointer and then align the result. +See CodeGen/SystemZ/alloca-01.ll for an example. + +-- + +Atomic loads and stores use the default compare-and-swap based implementation. +This is probably much too conservative in practice, and the overhead is +especially bad for 8- and 16-bit accesses. diff --git a/lib/Target/SystemZ/SystemZ.h b/lib/Target/SystemZ/SystemZ.h new file mode 100644 index 0000000000..b811cbe9f0 --- /dev/null +++ b/lib/Target/SystemZ/SystemZ.h @@ -0,0 +1,77 @@ +//==- 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 SYSTEMZ_H +#define SYSTEMZ_H + +#include "MCTargetDesc/SystemZMCTargetDesc.h" +#include "llvm/Support/CodeGen.h" + +namespace llvm { + class SystemZTargetMachine; + class FunctionPass; + + namespace SystemZ { + // Condition-code mask values. + const unsigned CCMASK_0 = 1 << 3; + const unsigned CCMASK_1 = 1 << 2; + const unsigned CCMASK_2 = 1 << 1; + const unsigned CCMASK_3 = 1 << 0; + const unsigned CCMASK_ANY = CCMASK_0 | CCMASK_1 | CCMASK_2 | CCMASK_3; + + // Condition-code mask assignments for floating-point comparisons. + const unsigned CCMASK_CMP_EQ = CCMASK_0; + const unsigned CCMASK_CMP_LT = CCMASK_1; + const unsigned CCMASK_CMP_GT = CCMASK_2; + const unsigned CCMASK_CMP_UO = CCMASK_3; + const unsigned CCMASK_CMP_NE = CCMASK_CMP_LT | CCMASK_CMP_GT; + const unsigned CCMASK_CMP_LE = CCMASK_CMP_EQ | CCMASK_CMP_LT; + const unsigned CCMASK_CMP_GE = CCMASK_CMP_EQ | CCMASK_CMP_GT; + const unsigned CCMASK_CMP_O = CCMASK_ANY ^ CCMASK_CMP_UO; + + // Return true if Val fits an LLILL operand. + static inline bool isImmLL(uint64_t Val) { + return (Val & ~0x000000000000ffffULL) == 0; + } + + // Return true if Val fits an LLILH operand. + static inline bool isImmLH(uint64_t Val) { + return (Val & ~0x00000000ffff0000ULL) == 0; + } + + // Return true if Val fits an LLIHL operand. + static inline bool isImmHL(uint64_t Val) { + return (Val & ~0x00000ffff00000000ULL) == 0; + } + + // Return true if Val fits an LLIHH operand. + static inline bool isImmHH(uint64_t Val) { + return (Val & ~0xffff000000000000ULL) == 0; + } + + // Return true if Val fits an LLILF operand. + static inline bool isImmLF(uint64_t Val) { + return (Val & ~0x00000000ffffffffULL) == 0; + } + + // Return true if Val fits an LLIHF operand. + static inline bool isImmHF(uint64_t Val) { + return (Val & ~0xffffffff00000000ULL) == 0; + } + } + + FunctionPass *createSystemZISelDag(SystemZTargetMachine &TM, + CodeGenOpt::Level OptLevel); +} // end namespace llvm; +#endif diff --git a/lib/Target/SystemZ/SystemZ.td b/lib/Target/SystemZ/SystemZ.td new file mode 100644 index 0000000000..e03c32f56d --- /dev/null +++ b/lib/Target/SystemZ/SystemZ.td @@ -0,0 +1,75 @@ +//===-- 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. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Target-independent interfaces which we are implementing +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + +//===----------------------------------------------------------------------===// +// SystemZ supported processors +//===----------------------------------------------------------------------===// + +class Proc<string Name, list<SubtargetFeature> Features> + : Processor<Name, NoItineraries, Features>; + +def : Proc<"z10", []>; + +//===----------------------------------------------------------------------===// +// Register file description +//===----------------------------------------------------------------------===// + +include "SystemZRegisterInfo.td" + +//===----------------------------------------------------------------------===// +// Calling convention description +//===----------------------------------------------------------------------===// + +include "SystemZCallingConv.td" + +//===----------------------------------------------------------------------===// +// Instruction descriptions +//===----------------------------------------------------------------------===// + +include "SystemZOperators.td" +include "SystemZOperands.td" +include "SystemZPatterns.td" +include "SystemZInstrFormats.td" +include "SystemZInstrInfo.td" +include "SystemZInstrFP.td" + +def SystemZInstrInfo : InstrInfo {} + +//===----------------------------------------------------------------------===// +// Assembly parser +//===----------------------------------------------------------------------===// + +def SystemZAsmParser : AsmParser { + let ShouldEmitMatchRegisterName = 0; +} + +//===----------------------------------------------------------------------===// +// Assembly writer +//===----------------------------------------------------------------------===// + +def SystemZAsmWriter : AsmWriter { + string AsmWriterClassName = "InstPrinter"; + bit isMCAsmWriter = 1; +} + +//===----------------------------------------------------------------------===// +// Top-level target declaration +//===----------------------------------------------------------------------===// + +def SystemZ : Target { + let InstructionSet = SystemZInstrInfo; + let AssemblyParsers = [SystemZAsmParser]; + let AssemblyWriters = [SystemZAsmWriter]; +} diff --git a/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/lib/Target/SystemZ/SystemZAsmPrinter.cpp new file mode 100644 index 0000000000..1e15ab1413 --- /dev/null +++ b/lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -0,0 +1,113 @@ +//===-- SystemZAsmPrinter.cpp - SystemZ LLVM assembly printer -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Streams SystemZ assembly language and associated data, in the form of +// MCInsts and MCExprs respectively. +// +//===----------------------------------------------------------------------===// + +#include "SystemZAsmPrinter.h" +#include "InstPrinter/SystemZInstPrinter.h" +#include "SystemZConstantPoolValue.h" +#include "SystemZMCInstLower.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Target/Mangler.h" + +using namespace llvm; + +void SystemZAsmPrinter::EmitInstruction(const MachineInstr *MI) { + SystemZMCInstLower Lower(Mang, MF->getContext(), *this); + MCInst LoweredMI; + Lower.lower(MI, LoweredMI); + OutStreamer.EmitInstruction(LoweredMI); +} + +// Convert a SystemZ-specific constant pool modifier into the associated +// MCSymbolRefExpr variant kind. +static MCSymbolRefExpr::VariantKind +getModifierVariantKind(SystemZCP::SystemZCPModifier Modifier) { + switch (Modifier) { + case SystemZCP::NTPOFF: return MCSymbolRefExpr::VK_NTPOFF; + } + llvm_unreachable("Invalid SystemCPModifier!"); +} + +void SystemZAsmPrinter:: +EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) { + SystemZConstantPoolValue *ZCPV = + static_cast<SystemZConstantPoolValue*>(MCPV); + + const MCExpr *Expr = + MCSymbolRefExpr::Create(Mang->getSymbol(ZCPV->getGlobalValue()), + getModifierVariantKind(ZCPV->getModifier()), + OutContext); + uint64_t Size = TM.getDataLayout()->getTypeAllocSize(ZCPV->getType()); + + OutStreamer.EmitValue(Expr, Size); +} + +bool SystemZAsmPrinter::PrintAsmOperand(const MachineInstr *MI, + unsigned OpNo, + unsigned AsmVariant, + const char *ExtraCode, + raw_ostream &OS) { + if (ExtraCode && *ExtraCode == 'n') { + if (!MI->getOperand(OpNo).isImm()) + return true; + OS << -int64_t(MI->getOperand(OpNo).getImm()); + } else { + SystemZMCInstLower Lower(Mang, MF->getContext(), *this); + MCOperand MO(Lower.lowerOperand(MI->getOperand(OpNo))); + SystemZInstPrinter::printOperand(MO, OS); + } + return false; +} + +bool SystemZAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNo, + unsigned AsmVariant, + const char *ExtraCode, + raw_ostream &OS) { + SystemZInstPrinter::printAddress(MI->getOperand(OpNo).getReg(), + MI->getOperand(OpNo + 1).getImm(), + MI->getOperand(OpNo + 2).getReg(), OS); + return false; +} + +void SystemZAsmPrinter::EmitEndOfAsmFile(Module &M) { + if (Subtarget->isTargetELF()) { + const TargetLoweringObjectFileELF &TLOFELF = + static_cast<const TargetLoweringObjectFileELF &>(getObjFileLowering()); + + MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>(); + + // Output stubs for external and common global variables. + MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList(); + if (!Stubs.empty()) { + OutStreamer.SwitchSection(TLOFELF.getDataRelSection()); + const DataLayout *TD = TM.getDataLayout(); + + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + OutStreamer.EmitLabel(Stubs[i].first); + OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), + TD->getPointerSize(0), 0); + } + Stubs.clear(); + } + } +} + +// Force static initialization. +extern "C" void LLVMInitializeSystemZAsmPrinter() { + RegisterAsmPrinter<SystemZAsmPrinter> X(TheSystemZTarget); +} diff --git a/lib/Target/SystemZ/SystemZAsmPrinter.h b/lib/Target/SystemZ/SystemZAsmPrinter.h new file mode 100644 index 0000000000..4b6c51b6f0 --- /dev/null +++ b/lib/Target/SystemZ/SystemZAsmPrinter.h @@ -0,0 +1,52 @@ +//===-- SystemZAsmPrinter.h - SystemZ LLVM assembly printer ----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SYSTEMZASMPRINTER_H +#define SYSTEMZASMPRINTER_H + +#include "SystemZTargetMachine.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { +class MCStreamer; +class MachineBasicBlock; +class MachineInstr; +class Module; +class raw_ostream; + +class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter { +private: + const SystemZSubtarget *Subtarget; + +public: + SystemZAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) + : AsmPrinter(TM, Streamer) { + Subtarget = &TM.getSubtarget<SystemZSubtarget>(); + } + + // Override AsmPrinter. + virtual const char *getPassName() const LLVM_OVERRIDE { + return "SystemZ Assembly Printer"; + } + virtual void EmitInstruction(const MachineInstr *MI) LLVM_OVERRIDE; + virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) + LLVM_OVERRIDE; + virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &OS) LLVM_OVERRIDE; + virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, + const char *ExtraCode, + raw_ostream &OS) LLVM_OVERRIDE; + virtual void EmitEndOfAsmFile(Module &M) LLVM_OVERRIDE; +}; +} // end namespace llvm + +#endif diff --git a/lib/Target/SystemZ/SystemZCallingConv.cpp b/lib/Target/SystemZ/SystemZCallingConv.cpp new file mode 100644 index 0000000000..cc9c84b6a0 --- /dev/null +++ b/lib/Target/SystemZ/SystemZCallingConv.cpp @@ -0,0 +1,21 @@ +//===-- SystemZCallingConv.cpp - Calling conventions for SystemZ ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SystemZCallingConv.h" +#include "SystemZRegisterInfo.h" + +using namespace llvm; + +const unsigned SystemZ::ArgGPRs[SystemZ::NumArgGPRs] = { + SystemZ::R2D, SystemZ::R3D, SystemZ::R4D, SystemZ::R5D, SystemZ::R6D +}; + +const unsigned SystemZ::ArgFPRs[SystemZ::NumArgFPRs] = { + SystemZ::F0D, SystemZ::F2D, SystemZ::F4D, SystemZ::F6D +}; diff --git a/lib/Target/SystemZ/SystemZCallingConv.h b/lib/Target/SystemZ/SystemZCallingConv.h new file mode 100644 index 0000000000..298985e7e5 --- /dev/null +++ b/lib/Target/SystemZ/SystemZCallingConv.h @@ -0,0 +1,23 @@ +//===-- SystemZCallingConv.h - Calling conventions for SystemZ --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SYSTEMZCALLINGCONV_H +#define SYSTEMZCALLINGCONV_H + +namespace llvm { + namespace SystemZ { + const unsigned NumArgGPRs = 5; + extern const unsigned ArgGPRs[NumArgGPRs]; + + const unsigned NumArgFPRs = 4; + extern const unsigned ArgFPRs[NumArgFPRs]; + } +} + +#endif diff --git a/lib/Target/SystemZ/SystemZCallingConv.td b/lib/Target/SystemZ/SystemZCallingConv.td new file mode 100644 index 0000000000..c2d727fe4d --- /dev/null +++ b/lib/Target/SystemZ/SystemZCallingConv.td @@ -0,0 +1,65 @@ +//=- 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 the SystemZ ABI. +//===----------------------------------------------------------------------===// + +class CCIfExtend<CCAction A> + : CCIf<"ArgFlags.isSExt() || ArgFlags.isZExt()", A>; + +//===----------------------------------------------------------------------===// +// SVR4 return value calling convention +//===----------------------------------------------------------------------===// +def RetCC_SystemZ : CallingConv<[ + // Promote i32 to i64 if it has an explicit extension type. + CCIfType<[i32], CCIfExtend<CCPromoteToType<i64>>>, + + // ABI-compliant code returns 64-bit integers in R2. Make the other + // call-clobbered argument registers available for code that doesn't + // care about the ABI. (R6 is an argument register too, but is + // call-saved and therefore not suitable for return values.) + CCIfType<[i32], CCAssignToReg<[R2W, R3W, R4W, R5W]>>, + CCIfType<[i64], CCAssignToReg<[R2D, R3D, R4D, R5D]>>, + + // ABI-complaint code returns float and double in F0. Make the + // other floating-point argument registers available for code that + // doesn't care about the ABI. All floating-point argument registers + // are call-clobbered, so we can use all of them here. + CCIfType<[f32], CCAssignToReg<[F0S, F2S, F4S, F6S]>>, + CCIfType<[f64], CCAssignToReg<[F0D, F2D, F4D, F6D]>> + + // ABI-compliant code returns long double by reference, but that conversion + // is left to higher-level code. Perhaps we could add an f128 definition + // here for code that doesn't care about the ABI? +]>; + +//===----------------------------------------------------------------------===// +// SVR4 argument calling conventions +//===----------------------------------------------------------------------===// +def CC_SystemZ : CallingConv<[ + // Promote i32 to i64 if it has an explicit extension type. + // The convention is that true integer arguments that are smaller + // than 64 bits should be marked as extended, but structures that + // are smaller than 64 bits shouldn't. + CCIfType<[i32], CCIfExtend<CCPromoteToType<i64>>>, + + // Force long double values to the stack and pass i64 pointers to them. + CCIfType<[f128], CCPassIndirect<i64>>, + + // The first 5 integer arguments are passed in R2-R6. Note that R6 + // is call-saved. + CCIfType<[i32], CCAssignToReg<[R2W, R3W, R4W, R5W, R6W]>>, + CCIfType<[i64], CCAssignToReg<[R2D, R3D, R4D, R5D, R6D]>>, + + // The first 4 float and double arguments are passed in even registers F0-F6. + CCIfType<[f32], CCAssignToReg<[F0S, F2S, F4S, F6S]>>, + CCIfType<[f64], CCAssignToReg<[F0D, F2D, F4D, F6D]>>, + + // Other arguments are passed in 8-byte-aligned 8-byte stack slots. + CCIfType<[i32, i64, f32, f64], CCAssignToStack<8, 8>> +]>; diff --git a/lib/Target/SystemZ/SystemZConstantPoolValue.cpp b/lib/Target/SystemZ/SystemZConstantPoolValue.cpp new file mode 100644 index 0000000000..e9c4f6df52 --- /dev/null +++ b/lib/Target/SystemZ/SystemZConstantPoolValue.cpp @@ -0,0 +1,62 @@ +//===-- SystemZConstantPoolValue.cpp - SystemZ constant-pool value --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SystemZConstantPoolValue.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +SystemZConstantPoolValue:: +SystemZConstantPoolValue(const GlobalValue *gv, + SystemZCP::SystemZCPModifier modifier) + : MachineConstantPoolValue(gv->getType()), GV(gv), Modifier(modifier) {} + +SystemZConstantPoolValue * +SystemZConstantPoolValue::Create(const GlobalValue *GV, + SystemZCP::SystemZCPModifier Modifier) { + return new SystemZConstantPoolValue(GV, Modifier); +} + +unsigned SystemZConstantPoolValue::getRelocationInfo() const { + switch (Modifier) { + case SystemZCP::NTPOFF: + // May require a relocation, but the relocations are always resolved + // by the static linker. + return 1; + } + llvm_unreachable("Unknown modifier"); +} + +int SystemZConstantPoolValue:: +getExistingMachineCPValue(MachineConstantPool *CP, unsigned Alignment) { + unsigned AlignMask = Alignment - 1; + const std::vector<MachineConstantPoolEntry> Constants = CP->getConstants(); + for (unsigned I = 0, E = Constants.size(); I != E; ++I) { + if (Constants[I].isMachineConstantPoolEntry() && + (Constants[I].getAlignment() & AlignMask) == 0) { + SystemZConstantPoolValue *ZCPV = + static_cast<SystemZConstantPoolValue *>(Constants[I].Val.MachineCPVal); + if (ZCPV->GV == GV && ZCPV->Modifier == Modifier) + return I; + } + } + return -1; +} + +void SystemZConstantPoolValue::addSelectionDAGCSEId(FoldingSetNodeID &ID) { + ID.AddPointer(GV); + ID.AddInteger(Modifier); +} + +void SystemZConstantPoolValue::print(raw_ostream &O) const { + O << GV << "@" << int(Modifier); +} diff --git a/lib/Target/SystemZ/SystemZConstantPoolValue.h b/lib/Target/SystemZ/SystemZConstantPoolValue.h new file mode 100644 index 0000000000..9927bdb262 --- /dev/null +++ b/lib/Target/SystemZ/SystemZConstantPoolValue.h @@ -0,0 +1,55 @@ +//===- SystemZConstantPoolValue.h - SystemZ constant-pool value -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SYSTEMZCONSTANTPOOLVALUE_H +#define SYSTEMZCONSTANTPOOLVALUE_H + +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/Support/ErrorHandling.h" + +namespace llvm { + +class GlobalValue; + +namespace SystemZCP { + enum SystemZCPModifier { + NTPOFF + }; +} + +/// A SystemZ-specific constant pool value. At present, the only +/// defined constant pool values are offsets of thread-local variables +/// (written x@NTPOFF). +class SystemZConstantPoolValue : public MachineConstantPoolValue { + const GlobalValue *GV; + SystemZCP::SystemZCPModifier Modifier; + +protected: + SystemZConstantPoolValue(const GlobalValue *GV, + SystemZCP::SystemZCPModifier Modifier); + +public: + static SystemZConstantPoolValue * + Create(const GlobalValue *GV, SystemZCP::SystemZCPModifier Modifier); + + // Override MachineConstantPoolValue. + virtual unsigned getRelocationInfo() const LLVM_OVERRIDE; + virtual int getExistingMachineCPValue(MachineConstantPool *CP, + unsigned Alignment) LLVM_OVERRIDE; + virtual void addSelectionDAGCSEId(FoldingSetNodeID &ID) LLVM_OVERRIDE; + virtual void print(raw_ostream &O) const LLVM_OVERRIDE; + + // Access SystemZ-specific fields. + const GlobalValue *getGlobalValue() const { return GV; } + SystemZCP::SystemZCPModifier getModifier() const { return Modifier; } +}; + +} // End llvm namespace + +#endif diff --git a/lib/Target/SystemZ/SystemZFrameLowering.cpp b/lib/Target/SystemZ/SystemZFrameLowering.cpp new file mode 100644 index 0000000000..fda33dee48 --- /dev/null +++ b/lib/Target/SystemZ/SystemZFrameLowering.cpp @@ -0,0 +1,535 @@ +//===-- SystemZFrameLowering.cpp - Frame lowering for SystemZ -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SystemZFrameLowering.h" +#include "SystemZCallingConv.h" +#include "SystemZInstrBuilder.h" +#include "SystemZMachineFunctionInfo.h" +#include "SystemZTargetMachine.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Function.h" + +using namespace llvm; + +SystemZFrameLowering::SystemZFrameLowering(const SystemZTargetMachine &tm, + const SystemZSubtarget &sti) + : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 8, + -SystemZMC::CallFrameSize), + TM(tm), + STI(sti) { + // The ABI-defined register save slots, relative to the incoming stack + // pointer. + static const unsigned SpillOffsetTable[][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 }, + { SystemZ::F0D, 0x80 }, + { SystemZ::F2D, 0x88 }, + { SystemZ::F4D, 0x90 }, + { SystemZ::F6D, 0x98 } + }; + + // Create a mapping from register number to save slot offset. + RegSpillOffsets.grow(SystemZ::NUM_TARGET_REGS); + for (unsigned I = 0, E = array_lengthof(SpillOffsetTable); I != E; ++I) + RegSpillOffsets[SpillOffsetTable[I][0]] = SpillOffsetTable[I][1]; +} + +void SystemZFrameLowering:: +processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS) const { + MachineFrameInfo *MFFrame = MF.getFrameInfo(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + const TargetRegisterInfo *TRI = MF.getTarget().getRegisterInfo(); + bool HasFP = hasFP(MF); + SystemZMachineFunctionInfo *MFI = MF.getInfo<SystemZMachineFunctionInfo>(); + bool IsVarArg = MF.getFunction()->isVarArg(); + + // va_start stores incoming FPR varargs in the normal way, but delegates + // the saving of incoming GPR varargs to spillCalleeSavedRegisters(). + // Record these pending uses, which typically include the call-saved + // argument register R6D. + if (IsVarArg) + for (unsigned I = MFI->getVarArgsFirstGPR(); I < SystemZ::NumArgGPRs; ++I) + MRI.setPhysRegUsed(SystemZ::ArgGPRs[I]); + + // If the function requires a frame pointer, record that the hard + // frame pointer will be clobbered. + if (HasFP) + MRI.setPhysRegUsed(SystemZ::R11D); + + // If the function calls other functions, record that the return + // address register will be clobbered. + if (MFFrame->hasCalls()) + MRI.setPhysRegUsed(SystemZ::R14D); + + // If we are saving GPRs other than the stack pointer, we might as well + // save and restore the stack pointer at the same time, via STMG and LMG. + // This allows the deallocation to be done by the LMG, rather than needing + // a separate %r15 addition. + const uint16_t *CSRegs = TRI->getCalleeSavedRegs(&MF); + for (unsigned I = 0; CSRegs[I]; ++I) { + unsigned Reg = CSRegs[I]; + if (SystemZ::GR64BitRegClass.contains(Reg) && MRI.isPhysRegUsed(Reg)) { + MRI.setPhysRegUsed(SystemZ::R15D); + break; + } + } +} + +// Add GPR64 to the save instruction being built by MIB, which is in basic +// block MBB. IsImplicit says whether this is an explicit operand to the +// instruction, or an implicit one that comes between the explicit start +// and end registers. +static void addSavedGPR(MachineBasicBlock &MBB, MachineInstrBuilder &MIB, + const SystemZTargetMachine &TM, + unsigned GPR64, bool IsImplicit) { + const SystemZRegisterInfo *RI = TM.getRegisterInfo(); + unsigned GPR32 = RI->getSubReg(GPR64, SystemZ::subreg_32bit); + bool IsLive = MBB.isLiveIn(GPR64) || MBB.isLiveIn(GPR32); + if (!IsLive || !IsImplicit) { + MIB.addReg(GPR64, getImplRegState(IsImplicit) | getKillRegState(!IsLive)); + if (!IsLive) + MBB.addLiveIn(GPR64); + } +} + +bool SystemZFrameLowering:: +spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const { + if (CSI.empty()) + return false; + + MachineFunction &MF = *MBB.getParent(); + const TargetInstrInfo *TII = MF.getTarget().getInstrInfo(); + SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); + bool IsVarArg = MF.getFunction()->isVarArg(); + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + + // Scan the call-saved GPRs and find the bounds of the register spill area. + unsigned SavedGPRFrameSize = 0; + unsigned LowGPR = 0; + unsigned HighGPR = SystemZ::R15D; + unsigned StartOffset = -1U; + for (unsigned I = 0, E = CSI.size(); I != E; ++I) { + unsigned Reg = CSI[I].getReg(); + if (SystemZ::GR64BitRegClass.contains(Reg)) { + SavedGPRFrameSize += 8; + unsigned Offset = RegSpillOffsets[Reg]; + assert(Offset && "Unexpected GPR save"); + if (StartOffset > Offset) { + LowGPR = Reg; + StartOffset = Offset; + } + } + } + + // Save information about the range and location of the call-saved + // registers, for use by the epilogue inserter. + ZFI->setSavedGPRFrameSize(SavedGPRFrameSize); + ZFI->setLowSavedGPR(LowGPR); + ZFI->setHighSavedGPR(HighGPR); + + // Include the GPR varargs, if any. R6D is call-saved, so would + // be included by the loop above, but we also need to handle the + // call-clobbered argument registers. + if (IsVarArg) { + unsigned FirstGPR = ZFI->getVarArgsFirstGPR(); + if (FirstGPR < SystemZ::NumArgGPRs) { + unsigned Reg = SystemZ::ArgGPRs[FirstGPR]; + unsigned Offset = RegSpillOffsets[Reg]; + if (StartOffset > Offset) { + LowGPR = Reg; StartOffset = Offset; + } + } + } + + // Save GPRs + if (LowGPR) { + assert(LowGPR != HighGPR && "Should be saving %r15 and something else"); + + // Build an STMG instruction. + MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(SystemZ::STMG)); + + // Add the explicit register operands. + addSavedGPR(MBB, MIB, TM, LowGPR, false); + addSavedGPR(MBB, MIB, TM, HighGPR, false); + + // Add the address. + MIB.addReg(SystemZ::R15D).addImm(StartOffset); + + // Make sure all call-saved GPRs are included as operands and are + // marked as live on entry. + for (unsigned I = 0, E = CSI.size(); I != E; ++I) { + unsigned Reg = CSI[I].getReg(); + if (SystemZ::GR64BitRegClass.contains(Reg)) + addSavedGPR(MBB, MIB, TM, Reg, true); + } + + // ...likewise GPR varargs. + if (IsVarArg) + for (unsigned I = ZFI->getVarArgsFirstGPR(); I < SystemZ::NumArgGPRs; ++I) + addSavedGPR(MBB, MIB, TM, SystemZ::ArgGPRs[I], true); + } + + // Save FPRs in the normal TargetInstrInfo way. + for (unsigned I = 0, E = CSI.size(); I != E; ++I) { + unsigned Reg = CSI[I].getReg(); + if (SystemZ::FP64BitRegClass.contains(Reg)) { + MBB.addLiveIn(Reg); + TII->storeRegToStackSlot(MBB, MBBI, Reg, true, CSI[I].getFrameIdx(), + &SystemZ::FP64BitRegClass, TRI); + } + } + + return true; +} + +bool SystemZFrameLowering:: +restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const { + if (CSI.empty()) + return false; + + MachineFunction &MF = *MBB.getParent(); + const TargetInstrInfo *TII = MF.getTarget().getInstrInfo(); + SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); + bool HasFP = hasFP(MF); + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + + // Restore FPRs in the normal TargetInstrInfo way. + for (unsigned I = 0, E = CSI.size(); I != E; ++I) { + unsigned Reg = CSI[I].getReg(); + if (SystemZ::FP64BitRegClass.contains(Reg)) + TII->loadRegFromStackSlot(MBB, MBBI, Reg, CSI[I].getFrameIdx(), + &SystemZ::FP64BitRegClass, TRI); + } + + // Restore call-saved GPRs (but not call-clobbered varargs, which at + // this point might hold return values). + unsigned LowGPR = ZFI->getLowSavedGPR(); + unsigned HighGPR = ZFI->getHighSavedGPR(); + unsigned StartOffset = RegSpillOffsets[LowGPR]; + if (LowGPR) { + // If we saved any of %r2-%r5 as varargs, we should also be saving + // and restoring %r6. If we're saving %r6 or above, we should be + // restoring it too. + assert(LowGPR != HighGPR && "Should be loading %r15 and something else"); + + // Build an LMG instruction. + MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(SystemZ::LMG)); + + // Add the explicit register operands. + MIB.addReg(LowGPR, RegState::Define); + MIB.addReg(HighGPR, RegState::Define); + + // Add the address. + MIB.addReg(HasFP ? SystemZ::R11D : SystemZ::R15D); + MIB.addImm(StartOffset); + + // 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 != LowGPR && Reg != HighGPR) + MIB.addReg(Reg, RegState::ImplicitDefine); + } + } + + return true; +} + +// Emit instructions before MBBI (in MBB) to add NumBytes to Reg. +static void emitIncrement(MachineBasicBlock &MBB, + MachineBasicBlock::iterator &MBBI, + const DebugLoc &DL, + unsigned Reg, int64_t NumBytes, + const TargetInstrInfo *TII) { + while (NumBytes) { + unsigned Opcode; + int64_t ThisVal = NumBytes; + if (isInt<16>(NumBytes)) + Opcode = SystemZ::AGHI; + else { + Opcode = SystemZ::AGFI; + // Make sure we maintain 8-byte stack alignment. + int64_t MinVal = -int64_t(1) << 31; + int64_t MaxVal = (int64_t(1) << 31) - 8; + if (ThisVal < MinVal) + ThisVal = MinVal; + else if (ThisVal > MaxVal) + ThisVal = MaxVal; + } + MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII->get(Opcode), Reg) + .addReg(Reg).addImm(ThisVal); + // The PSW implicit def is dead. + MI->getOperand(3).setIsDead(); + NumBytes -= ThisVal; + } +} + +void SystemZFrameLowering::emitPrologue(MachineFunction &MF) const { + MachineBasicBlock &MBB = MF.front(); + MachineFrameInfo *MFFrame = MF.getFrameInfo(); + const SystemZInstrInfo *ZII = + static_cast<const SystemZInstrInfo*>(MF.getTarget().getInstrInfo()); + SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); + MachineBasicBlock::iterator MBBI = MBB.begin(); + MachineModuleInfo &MMI = MF.getMMI(); + std::vector<MachineMove> &Moves = MMI.getFrameMoves(); + const std::vector<CalleeSavedInfo> &CSI = MFFrame->getCalleeSavedInfo(); + bool HasFP = hasFP(MF); + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + + // The current offset of the stack pointer from the CFA. + int64_t SPOffsetFromCFA = -SystemZMC::CFAOffsetFromInitialSP; + + if (ZFI->getLowSavedGPR()) { + // Skip over the GPR saves. + if (MBBI != MBB.end() && MBBI->getOpcode() == SystemZ::STMG) + ++MBBI; + else + llvm_unreachable("Couldn't skip over GPR saves"); + + // Add CFI for the GPR saves. + MCSymbol *GPRSaveLabel = MMI.getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, DL, + ZII->get(TargetOpcode::PROLOG_LABEL)).addSym(GPRSaveLabel); + for (std::vector<CalleeSavedInfo>::const_iterator + I = CSI.begin(), E = CSI.end(); I != E; ++I) { + unsigned Reg = I->getReg(); + if (SystemZ::GR64BitRegClass.contains(Reg)) { + int64_t Offset = SPOffsetFromCFA + RegSpillOffsets[Reg]; + MachineLocation StackSlot(MachineLocation::VirtualFP, Offset); + MachineLocation RegValue(Reg); + Moves.push_back(MachineMove(GPRSaveLabel, StackSlot, RegValue)); + } + } + } + + uint64_t StackSize = getAllocatedStackSize(MF); + if (StackSize) { + // Allocate StackSize bytes. + int64_t Delta = -int64_t(StackSize); + emitIncrement(MBB, MBBI, DL, SystemZ::R15D, Delta, ZII); + + // Add CFI for the allocation. + MCSymbol *AdjustSPLabel = MMI.getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::PROLOG_LABEL)) + .addSym(AdjustSPLabel); + MachineLocation FPDest(MachineLocation::VirtualFP); + MachineLocation FPSrc(MachineLocation::VirtualFP, SPOffsetFromCFA + Delta); + Moves.push_back(MachineMove(AdjustSPLabel, FPDest, FPSrc)); + SPOffsetFromCFA += Delta; + } + + if (HasFP) { + // Copy the base of the frame to R11. + BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::LGR), SystemZ::R11D) + .addReg(SystemZ::R15D); + + // Add CFI for the new frame location. + MCSymbol *SetFPLabel = MMI.getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::PROLOG_LABEL)) + .addSym(SetFPLabel); + MachineLocation HardFP(SystemZ::R11D); + MachineLocation VirtualFP(MachineLocation::VirtualFP); + Moves.push_back(MachineMove(SetFPLabel, HardFP, VirtualFP)); + + // Mark the FramePtr as live at the beginning of every block except + // the entry block. (We'll have marked R11 as live on entry when + // saving the GPRs.) + for (MachineFunction::iterator + I = llvm::next(MF.begin()), E = MF.end(); I != E; ++I) + I->addLiveIn(SystemZ::R11D); + } + + // Skip over the FPR saves. + MCSymbol *FPRSaveLabel = 0; + for (std::vector<CalleeSavedInfo>::const_iterator + I = CSI.begin(), E = CSI.end(); I != E; ++I) { + unsigned Reg = I->getReg(); + if (SystemZ::FP64BitRegClass.contains(Reg)) { + if (MBBI != MBB.end() && + (MBBI->getOpcode() == SystemZ::STD || + MBBI->getOpcode() == SystemZ::STDY)) + ++MBBI; + else + llvm_unreachable("Couldn't skip over FPR save"); + + // Add CFI for the this save. + if (!FPRSaveLabel) + FPRSaveLabel = MMI.getContext().CreateTempSymbol(); + unsigned Reg = I->getReg(); + int64_t Offset = getFrameIndexOffset(MF, I->getFrameIdx()); + MachineLocation Slot(MachineLocation::VirtualFP, + SPOffsetFromCFA + Offset); + MachineLocation RegValue(Reg); + Moves.push_back(MachineMove(FPRSaveLabel, Slot, RegValue)); + } + } + // Complete the CFI for the FPR saves, modelling them as taking effect + // after the last save. + if (FPRSaveLabel) + BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::PROLOG_LABEL)) + .addSym(FPRSaveLabel); +} + +void SystemZFrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); + const SystemZInstrInfo *ZII = + static_cast<const SystemZInstrInfo*>(MF.getTarget().getInstrInfo()); + SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); + + // Skip the return instruction. + assert(MBBI->getOpcode() == SystemZ::RET && + "Can only insert epilogue into returning blocks"); + + uint64_t StackSize = getAllocatedStackSize(MF); + if (ZFI->getLowSavedGPR()) { + --MBBI; + unsigned Opcode = MBBI->getOpcode(); + if (Opcode != SystemZ::LMG) + llvm_unreachable("Expected to see callee-save register restore code"); + + unsigned AddrOpNo = 2; + DebugLoc DL = MBBI->getDebugLoc(); + uint64_t Offset = StackSize + MBBI->getOperand(AddrOpNo + 1).getImm(); + unsigned NewOpcode = ZII->getOpcodeForOffset(Opcode, Offset); + + // If the offset is too large, use the largest stack-aligned offset + // and add the rest to the base register (the stack or frame pointer). + if (!NewOpcode) { + uint64_t NumBytes = Offset - 0x7fff8; + emitIncrement(MBB, MBBI, DL, MBBI->getOperand(AddrOpNo).getReg(), + NumBytes, ZII); + Offset -= NumBytes; + NewOpcode = ZII->getOpcodeForOffset(Opcode, Offset); + assert(NewOpcode && "No restore instruction available"); + } + + MBBI->setDesc(ZII->get(NewOpcode)); + MBBI->getOperand(AddrOpNo + 1).ChangeToImmediate(Offset); + } else if (StackSize) { + DebugLoc DL = MBBI->getDebugLoc(); + emitIncrement(MBB, MBBI, DL, SystemZ::R15D, StackSize, ZII); + } +} + +bool SystemZFrameLowering::hasFP(const MachineFunction &MF) const { + return (MF.getTarget().Options.DisableFramePointerElim(MF) || + MF.getFrameInfo()->hasVarSizedObjects() || + MF.getInfo<SystemZMachineFunctionInfo>()->getManipulatesSP()); +} + +int SystemZFrameLowering::getFrameIndexOffset(const MachineFunction &MF, + int FI) const { + const MachineFrameInfo *MFFrame = MF.getFrameInfo(); + + // Start with the offset of FI from the top of the caller-allocated frame + // (i.e. the top of the 160 bytes allocated by the caller). This initial + // offset is therefore negative. + int64_t Offset = (MFFrame->getObjectOffset(FI) + + MFFrame->getOffsetAdjustment()); + if (FI >= 0) + // Non-fixed objects are allocated below the incoming stack pointer. + // Account for the space at the top of the frame that we choose not + // to allocate. + Offset += getUnallocatedTopBytes(MF); + + // Make the offset relative to the incoming stack pointer. + Offset -= getOffsetOfLocalArea(); + + // Make the offset relative to the bottom of the frame. + Offset += getAllocatedStackSize(MF); + + return Offset; +} + +uint64_t SystemZFrameLowering:: +getUnallocatedTopBytes(const MachineFunction &MF) const { + return MF.getInfo<SystemZMachineFunctionInfo>()->getSavedGPRFrameSize(); +} + +uint64_t SystemZFrameLowering:: +getAllocatedStackSize(const MachineFunction &MF) const { + const MachineFrameInfo *MFFrame = MF.getFrameInfo(); + + // Start with the size of the local variables and spill slots. + uint64_t StackSize = MFFrame->getStackSize(); + + // Remove any bytes that we choose not to allocate. + StackSize -= getUnallocatedTopBytes(MF); + + // Include space for an emergency spill slot, if one might be needed. + StackSize += getEmergencySpillSlotSize(MF); + + // We need to allocate the ABI-defined 160-byte base area whenever + // we allocate stack space for our own use and whenever we call another + // function. + if (StackSize || MFFrame->hasVarSizedObjects() || MFFrame->hasCalls()) + StackSize += SystemZMC::CallFrameSize; + + return StackSize; +} + +unsigned SystemZFrameLowering:: +getEmergencySpillSlotSize(const MachineFunction &MF) const { + const MachineFrameInfo *MFFrame = MF.getFrameInfo(); + uint64_t MaxReach = MFFrame->getStackSize() + SystemZMC::CallFrameSize * 2; + return isUInt<12>(MaxReach) ? 0 : 8; +} + +unsigned SystemZFrameLowering:: +getEmergencySpillSlotOffset(const MachineFunction &MF) const { + assert(getEmergencySpillSlotSize(MF) && "No emergency spill slot"); + return SystemZMC::CallFrameSize; +} + +bool +SystemZFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { + // The ABI requires us to allocate 160 bytes of stack space for the callee, + // with any outgoing stack arguments being placed above that. It seems + // better to make that area a permanent feature of the frame even if + // we're using a frame pointer. + return true; +} + +void SystemZFrameLowering:: +eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const { + switch (MI->getOpcode()) { + case SystemZ::ADJCALLSTACKDOWN: + case SystemZ::ADJCALLSTACKUP: + assert(hasReservedCallFrame(MF) && + "ADJSTACKDOWN and ADJSTACKUP should be no-ops"); + MBB.erase(MI); + break; + + default: + llvm_unreachable("Unexpected call frame instruction"); + } +} diff --git a/lib/Target/SystemZ/SystemZFrameLowering.h b/lib/Target/SystemZ/SystemZFrameLowering.h new file mode 100644 index 0000000000..5ca049c486 --- /dev/null +++ b/lib/Target/SystemZ/SystemZFrameLowering.h @@ -0,0 +1,93 @@ +//===-- SystemZFrameLowering.h - Frame lowering for SystemZ -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SYSTEMZFRAMELOWERING_H +#define SYSTEMZFRAMELOWERING_H + +#include "SystemZSubtarget.h" +#include "llvm/ADT/IndexedMap.h" +#include "llvm/Target/TargetFrameLowering.h" + +namespace llvm { +class SystemZTargetMachine; +class SystemZSubtarget; + +class SystemZFrameLowering : public TargetFrameLowering { + IndexedMap<unsigned> RegSpillOffsets; + +protected: + const SystemZTargetMachine &TM; + const SystemZSubtarget &STI; + +public: + SystemZFrameLowering(const SystemZTargetMachine &tm, + const SystemZSubtarget &sti); + + // Override FrameLowering. + virtual void + processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS) const LLVM_OVERRIDE; + virtual bool + spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const + LLVM_OVERRIDE; + virtual bool + restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBII, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const + LLVM_OVERRIDE; + virtual void emitPrologue(MachineFunction &MF) const LLVM_OVERRIDE; + virtual void emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const LLVM_OVERRIDE; + virtual bool hasFP(const MachineFunction &MF) const LLVM_OVERRIDE; + virtual int getFrameIndexOffset(const MachineFunction &MF, + int FI) const LLVM_OVERRIDE; + virtual bool hasReservedCallFrame(const MachineFunction &MF) const + LLVM_OVERRIDE; + virtual void + eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const + LLVM_OVERRIDE; + + // The target-independent code automatically allocates save slots for + // call-saved GPRs. However, we don't need those slots for SystemZ, + // because the ABI sets aside GPR save slots in the caller-allocated part + // of the frame. Since the target-independent code puts this unneeded + // area at the top of the callee-allocated part of frame, we choose not + // to allocate it and adjust the offsets accordingly. Return the + // size of this unallocated area. + // FIXME: seems a bit hackish. + uint64_t getUnallocatedTopBytes(const MachineFunction &MF) const; + + // Return the number of bytes in the callee-allocated part of the frame. + uint64_t getAllocatedStackSize(const MachineFunction &MF) const; + + // Return the number of frame bytes that should be reserved for + // an emergency spill slot, for use by the register scaveneger. + // Return 0 if register scaveging won't be needed. + unsigned getEmergencySpillSlotSize(const MachineFunction &MF) const; + + // Return the offset from the frame pointer of the emergency spill slot, + // which always fits within a 12-bit unsigned displacement field. + // Only valid if getEmergencySpillSlotSize(MF) returns nonzero. + unsigned getEmergencySpillSlotOffset(const MachineFunction &MF) const; + + // Return the byte offset from the incoming stack pointer of Reg's + // ABI-defined save slot. Return 0 if no slot is defined for Reg. + unsigned getRegSpillOffset(unsigned Reg) const { + return RegSpillOffsets[Reg]; + } +}; +} // end namespace llvm + +#endif diff --git a/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp new file mode 100644 index 0000000000..d436ba9dd0 --- /dev/null +++ b/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp @@ -0,0 +1,616 @@ +//===-- 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 "SystemZTargetMachine.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { +// Used to build addressing modes. +struct SystemZAddressingMode { + // The shape of the address. + enum AddrForm { + // base+displacement + FormBD, + + // base+displacement+index for load and store operands + FormBDXNormal, + + // base+displacement+index for load address operands + FormBDXLA, + + // base+displacement+index+ADJDYNALLOC + FormBDXDynAlloc + }; + AddrForm Form; + + // The type of displacement. The enum names here correspond directly + // to the definitions in SystemZOperand.td. We could split them into + // flags -- single/pair, 128-bit, etc. -- but it hardly seems worth it. + enum DispRange { + Disp12Only, + Disp12Pair, + Disp20Only, + Disp20Only128, + Disp20Pair + }; + DispRange DR; + + // The parts of the address. The address is equivalent to: + // + // Base + Disp + Index + (IncludesDynAlloc ? ADJDYNALLOC : 0) + SDValue Base; + int64_t Disp; + SDValue Index; + bool IncludesDynAlloc; + + SystemZAddressingMode(AddrForm form, DispRange dr) + : Form(form), DR(dr), Base(), Disp(0), Index(), + IncludesDynAlloc(false) {} + + // True if the address can have an index register. + bool hasIndexField() { return Form != FormBD; } + + // True if the address can (and must) include ADJDYNALLOC. + bool isDynAlloc() { return Form == FormBDXDynAlloc; } + + void dump() { + errs() << "SystemZAddressingMode " << this << '\n'; + + errs() << " Base "; + if (Base.getNode() != 0) + Base.getNode()->dump(); + else + errs() << "null\n"; + + if (hasIndexField()) { + errs() << " Index "; + if (Index.getNode() != 0) + Index.getNode()->dump(); + else + errs() << "null\n"; + } + + errs() << " Disp " << Disp; + if (IncludesDynAlloc) + errs() << " + ADJDYNALLOC"; + errs() << '\n'; + } +}; + +class SystemZDAGToDAGISel : public SelectionDAGISel { + const SystemZTargetLowering &Lowering; + const SystemZSubtarget &Subtarget; + + // Used by SystemZOperands.td to create integer constants. + inline SDValue getImm(const SDNode *Node, uint64_t Imm) { + return CurDAG->getTargetConstant(Imm, Node->getValueType(0)); + } + + // Try to fold more of the base or index of AM into AM, where IsBase + // selects between the base and index. + bool expandAddress(SystemZAddressingMode &AM, bool IsBase); + + // Try to describe N in AM, returning true on success. + bool selectAddress(SDValue N, SystemZAddressingMode &AM); + + // Extract individual target operands from matched address AM. + void getAddressOperands(const SystemZAddressingMode &AM, EVT VT, + SDValue &Base, SDValue &Disp); + void getAddressOperands(const SystemZAddressingMode &AM, EVT VT, + SDValue &Base, SDValue &Disp, SDValue &Index); + + // Try to match Addr as a FormBD address with displacement type DR. + // Return true on success, storing the base and displacement in + // Base and Disp respectively. + bool selectBDAddr(SystemZAddressingMode::DispRange DR, SDValue Addr, + SDValue &Base, SDValue &Disp); + + // Try to match Addr as a FormBDX* address of form Form with + // displacement type DR. Return true on success, storing the base, + // displacement and index in Base, Disp and Index respectively. + bool selectBDXAddr(SystemZAddressingMode::AddrForm Form, + SystemZAddressingMode::DispRange DR, SDValue Addr, + SDValue &Base, SDValue &Disp, SDValue &Index); + + // PC-relative address matching routines used by SystemZOperands.td. + bool selectPCRelAddress(SDValue Addr, SDValue &Target) { + if (Addr.getOpcode() == SystemZISD::PCREL_WRAPPER) { + Target = Addr.getOperand(0); + return true; + } + return false; + } + + // BD matching routines used by SystemZOperands.td. + bool selectBDAddr12Only(SDValue Addr, SDValue &Base, SDValue &Disp) { + return selectBDAddr(SystemZAddressingMode::Disp12Only, Addr, Base, Disp); + } + bool selectBDAddr12Pair(SDValue Addr, SDValue &Base, SDValue &Disp) { + return selectBDAddr(SystemZAddressingMode::Disp12Pair, Addr, Base, Disp); + } + bool selectBDAddr20Only(SDValue Addr, SDValue &Base, SDValue &Disp) { + return selectBDAddr(SystemZAddressingMode::Disp20Only, Addr, Base, Disp); + } + bool selectBDAddr20Pair(SDValue Addr, SDValue &Base, SDValue &Disp) { + return selectBDAddr(SystemZAddressingMode::Disp20Pair, Addr, Base, Disp); + } + + // BDX matching routines used by SystemZOperands.td. + bool selectBDXAddr12Only(SDValue Addr, SDValue &Base, SDValue &Disp, + SDValue &Index) { + return selectBDXAddr(SystemZAddressingMode::FormBDXNormal, + SystemZAddressingMode::Disp12Only, + Addr, Base, Disp, Index); + } + bool selectBDXAddr12Pair(SDValue Addr, SDValue &Base, SDValue &Disp, + SDValue &Index) { + return selectBDXAddr(SystemZAddressingMode::FormBDXNormal, + SystemZAddressingMode::Disp12Pair, + Addr, Base, Disp, Index); + } + bool selectDynAlloc12Only(SDValue Addr, SDValue &Base, SDValue &Disp, + SDValue &Index) { + return selectBDXAddr(SystemZAddressingMode::FormBDXDynAlloc, + SystemZAddressingMode::Disp12Only, + Addr, Base, Disp, Index); + } + bool selectBDXAddr20Only(SDValue Addr, SDValue &Base, SDValue &Disp, + SDValue &Index) { + return selectBDXAddr(SystemZAddressingMode::FormBDXNormal, + SystemZAddressingMode::Disp20Only, + Addr, Base, Disp, Index); + } + bool selectBDXAddr20Only128(SDValue Addr, SDValue &Base, SDValue &Disp, + SDValue &Index) { + return selectBDXAddr(SystemZAddressingMode::FormBDXNormal, + SystemZAddressingMode::Disp20Only128, + Addr, Base, Disp, Index); + } + bool selectBDXAddr20Pair(SDValue Addr, SDValue &Base, SDValue &Disp, + SDValue &Index) { + return selectBDXAddr(SystemZAddressingMode::FormBDXNormal, + SystemZAddressingMode::Disp20Pair, + Addr, Base, Disp, Index); + } + bool selectLAAddr12Pair(SDValue Addr, SDValue &Base, SDValue &Disp, + SDValue &Index) { + return selectBDXAddr(SystemZAddressingMode::FormBDXLA, + SystemZAddressingMode::Disp12Pair, + Addr, Base, Disp, Index); + } + bool selectLAAddr20Pair(SDValue Addr, SDValue &Base, SDValue &Disp, + SDValue &Index) { + return selectBDXAddr(SystemZAddressingMode::FormBDXLA, + SystemZAddressingMode::Disp20Pair, + Addr, Base, Disp, Index); + } + + // If Op0 is null, then Node is a constant that can be loaded using: + // + // (Opcode UpperVal LowerVal) + // + // If Op0 is nonnull, then Node can be implemented using: + // + // (Opcode (Opcode Op0 UpperVal) LowerVal) + SDNode *splitLargeImmediate(unsigned Opcode, SDNode *Node, SDValue Op0, + uint64_t UpperVal, uint64_t LowerVal); + +public: + SystemZDAGToDAGISel(SystemZTargetMachine &TM, CodeGenOpt::Level OptLevel) + : SelectionDAGISel(TM, OptLevel), + Lowering(*TM.getTargetLowering()), + Subtarget(*TM.getSubtargetImpl()) { } + + // Override MachineFunctionPass. + virtual const char *getPassName() const LLVM_OVERRIDE { + return "SystemZ DAG->DAG Pattern Instruction Selection"; + } + + // Override SelectionDAGISel. + virtual SDNode *Select(SDNode *Node) LLVM_OVERRIDE; + virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, + char ConstraintCode, + std::vector<SDValue> &OutOps) + LLVM_OVERRIDE; + + // Include the pieces autogenerated from the target description. + #include "SystemZGenDAGISel.inc" +}; +} // end anonymous namespace + +FunctionPass *llvm::createSystemZISelDag(SystemZTargetMachine &TM, + CodeGenOpt::Level OptLevel) { + return new SystemZDAGToDAGISel(TM, OptLevel); +} + +// Return true if Val should be selected as a displacement for an address +// with range DR. Here we're interested in the range of both the instruction +// described by DR and of any pairing instruction. +static bool selectDisp(SystemZAddressingMode::DispRange DR, int64_t Val) { + switch (DR) { + case SystemZAddressingMode::Disp12Only: + return isUInt<12>(Val); + + case SystemZAddressingMode::Disp12Pair: + case SystemZAddressingMode::Disp20Only: + case SystemZAddressingMode::Disp20Pair: + return isInt<20>(Val); + + case SystemZAddressingMode::Disp20Only128: + return isInt<20>(Val) && isInt<20>(Val + 8); + } + llvm_unreachable("Unhandled displacement range"); +} + +// Change the base or index in AM to Value, where IsBase selects +// between the base and index. +static void changeComponent(SystemZAddressingMode &AM, bool IsBase, + SDValue Value) { + if (IsBase) + AM.Base = Value; + else + AM.Index = Value; +} + +// The base or index of AM is equivalent to Value + ADJDYNALLOC, +// where IsBase selects between the base and index. Try to fold the +// ADJDYNALLOC into AM. +static bool expandAdjDynAlloc(SystemZAddressingMode &AM, bool IsBase, + SDValue Value) { + if (AM.isDynAlloc() && !AM.IncludesDynAlloc) { + changeComponent(AM, IsBase, Value); + AM.IncludesDynAlloc = true; + return true; + } + return false; +} + +// The base of AM is equivalent to Base + Index. Try to use Index as +// the index register. +static bool expandIndex(SystemZAddressingMode &AM, SDValue Base, + SDValue Index) { + if (AM.hasIndexField() && !AM.Index.getNode()) { + AM.Base = Base; + AM.Index = Index; + return true; + } + return false; +} + +// The base or index of AM is equivalent to Op0 + Op1, where IsBase selects +// between the base and index. Try to fold Op1 into AM's displacement. +static bool expandDisp(SystemZAddressingMode &AM, bool IsBase, + SDValue Op0, ConstantSDNode *Op1) { + // First try adjusting the displacement. + int64_t TestDisp = AM.Disp + Op1->getSExtValue(); + if (selectDisp(AM.DR, TestDisp)) { + changeComponent(AM, IsBase, Op0); + AM.Disp = TestDisp; + return true; + } + + // We could consider forcing the displacement into a register and + // using it as an index, but it would need to be carefully tuned. + return false; +} + +bool SystemZDAGToDAGISel::expandAddress(SystemZAddressingMode &AM, + bool IsBase) { + SDValue N = IsBase ? AM.Base : AM.Index; + unsigned Opcode = N.getOpcode(); + if (Opcode == ISD::TRUNCATE) { + N = N.getOperand(0); + Opcode = N.getOpcode(); + } + if (Opcode == ISD::ADD || CurDAG->isBaseWithConstantOffset(N)) { + SDValue Op0 = N.getOperand(0); + SDValue Op1 = N.getOperand(1); + + unsigned Op0Code = Op0->getOpcode(); + unsigned Op1Code = Op1->getOpcode(); + + if (Op0Code == SystemZISD::ADJDYNALLOC) + return expandAdjDynAlloc(AM, IsBase, Op1); + if (Op1Code == SystemZISD::ADJDYNALLOC) + return expandAdjDynAlloc(AM, IsBase, Op0); + + if (Op0Code == ISD::Constant) + return expandDisp(AM, IsBase, Op1, cast<ConstantSDNode>(Op0)); + if (Op1Code == ISD::Constant) + return expandDisp(AM, IsBase, Op0, cast<ConstantSDNode>(Op1)); + + if (IsBase && expandIndex(AM, Op0, Op1)) + return true; + } + return false; +} + +// Return true if an instruction with displacement range DR should be +// used for displacement value Val. selectDisp(DR, Val) must already hold. +static bool isValidDisp(SystemZAddressingMode::DispRange DR, int64_t Val) { + assert(selectDisp(DR, Val) && "Invalid displacement"); + switch (DR) { + case SystemZAddressingMode::Disp12Only: + case SystemZAddressingMode::Disp20Only: + case SystemZAddressingMode::Disp20Only128: + return true; + + case SystemZAddressingMode::Disp12Pair: + // Use the other instruction if the displacement is too large. + return isUInt<12>(Val); + + case SystemZAddressingMode::Disp20Pair: + // Use the other instruction if the displacement is small enough. + return !isUInt<12>(Val); + } + llvm_unreachable("Unhandled displacement range"); +} + +// Return true if Base + Disp + Index should be performed by LA(Y). +static bool shouldUseLA(SDNode *Base, int64_t Disp, SDNode *Index) { + // Don't use LA(Y) for constants. + if (!Base) + return false; + + // Always use LA(Y) for frame addresses, since we know that the destination + // register is almost always (perhaps always) going to be different from + // the frame register. + if (Base->getOpcode() == ISD::FrameIndex) + return true; + + if (Disp) { + // Always use LA(Y) if there is a base, displacement and index. + if (Index) + return true; + + // Always use LA if the displacement is small enough. It should always + // be no worse than AGHI (and better if it avoids a move). + if (isUInt<12>(Disp)) + return true; + + // For similar reasons, always use LAY if the constant is too big for AGHI. + // LAY should be no worse than AGFI. + if (!isInt<16>(Disp)) + return true; + } else { + // Don't use LA for plain registers. + if (!Index) + return false; + + // Don't use LA for plain addition if the index operand is only used + // once. It should be a natural two-operand addition in that case. + if (Index->hasOneUse()) + return false; + + // Prefer addition if the second operation is sign-extended, in the + // hope of using AGF. + unsigned IndexOpcode = Index->getOpcode(); + if (IndexOpcode == ISD::SIGN_EXTEND || + IndexOpcode == ISD::SIGN_EXTEND_INREG) + return false; + } + + // Don't use LA for two-operand addition if either operand is only + // used once. The addition instructions are better in that case. + if (Base->hasOneUse()) + return false; + + return true; +} + +// Return true if Addr is suitable for AM, updating AM if so. +bool SystemZDAGToDAGISel::selectAddress(SDValue Addr, + SystemZAddressingMode &AM) { + // Start out assuming that the address will need to be loaded separately, + // then try to extend it as much as we can. + AM.Base = Addr; + + // First try treating the address as a constant. + if (Addr.getOpcode() == ISD::Constant && + expandDisp(AM, true, SDValue(), cast<ConstantSDNode>(Addr))) + ; + else + // Otherwise try expanding each component. + while (expandAddress(AM, true) || + (AM.Index.getNode() && expandAddress(AM, false))) + continue; + + // Reject cases where it isn't profitable to use LA(Y). + if (AM.Form == SystemZAddressingMode::FormBDXLA && + !shouldUseLA(AM.Base.getNode(), AM.Disp, AM.Index.getNode())) + return false; + + // Reject cases where the other instruction in a pair should be used. + if (!isValidDisp(AM.DR, AM.Disp)) + return false; + + // Make sure that ADJDYNALLOC is included where necessary. + if (AM.isDynAlloc() && !AM.IncludesDynAlloc) + return false; + + DEBUG(AM.dump()); + return true; +} + +// Insert a node into the DAG at least before Pos. This will reposition +// the node as needed, and will assign it a node ID that is <= Pos's ID. +// Note that this does *not* preserve the uniqueness of node IDs! +// The selection DAG must no longer depend on their uniqueness when this +// function is used. +static void insertDAGNode(SelectionDAG *DAG, SDNode *Pos, SDValue N) { + if (N.getNode()->getNodeId() == -1 || + N.getNode()->getNodeId() > Pos->getNodeId()) { + DAG->RepositionNode(Pos, N.getNode()); + N.getNode()->setNodeId(Pos->getNodeId()); + } +} + +void SystemZDAGToDAGISel::getAddressOperands(const SystemZAddressingMode &AM, + EVT VT, SDValue &Base, + SDValue &Disp) { + Base = AM.Base; + if (!Base.getNode()) + // Register 0 means "no base". This is mostly useful for shifts. + Base = CurDAG->getRegister(0, VT); + else if (Base.getOpcode() == ISD::FrameIndex) { + // Lower a FrameIndex to a TargetFrameIndex. + int64_t FrameIndex = cast<FrameIndexSDNode>(Base)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FrameIndex, VT); + } else if (Base.getValueType() != VT) { + // Truncate values from i64 to i32, for shifts. + assert(VT == MVT::i32 && Base.getValueType() == MVT::i64 && + "Unexpected truncation"); + DebugLoc DL = Base.getDebugLoc(); + SDValue Trunc = CurDAG->getNode(ISD::TRUNCATE, DL, VT, Base); + insertDAGNode(CurDAG, Base.getNode(), Trunc); + Base = Trunc; + } + + // Lower the displacement to a TargetConstant. + Disp = CurDAG->getTargetConstant(AM.Disp, VT); +} + +void SystemZDAGToDAGISel::getAddressOperands(const SystemZAddressingMode &AM, + EVT VT, SDValue &Base, + SDValue &Disp, SDValue &Index) { + getAddressOperands(AM, VT, Base, Disp); + + Index = AM.Index; + if (!Index.getNode()) + // Register 0 means "no index". + Index = CurDAG->getRegister(0, VT); +} + +bool SystemZDAGToDAGISel::selectBDAddr(SystemZAddressingMode::DispRange DR, + SDValue Addr, SDValue &Base, + SDValue &Disp) { + SystemZAddressingMode AM(SystemZAddressingMode::FormBD, DR); + if (!selectAddress(Addr, AM)) + return false; + + getAddressOperands(AM, Addr.getValueType(), Base, Disp); + return true; +} + +bool SystemZDAGToDAGISel::selectBDXAddr(SystemZAddressingMode::AddrForm Form, + SystemZAddressingMode::DispRange DR, + SDValue Addr, SDValue &Base, + SDValue &Disp, SDValue &Index) { + SystemZAddressingMode AM(Form, DR); + if (!selectAddress(Addr, AM)) + return false; + + getAddressOperands(AM, Addr.getValueType(), Base, Disp, Index); + return true; +} + +SDNode *SystemZDAGToDAGISel::splitLargeImmediate(unsigned Opcode, SDNode *Node, + SDValue Op0, uint64_t UpperVal, + uint64_t LowerVal) { + EVT VT = Node->getValueType(0); + DebugLoc DL = Node->getDebugLoc(); + SDValue Upper = CurDAG->getConstant(UpperVal, VT); + if (Op0.getNode()) + Upper = CurDAG->getNode(Opcode, DL, VT, Op0, Upper); + Upper = SDValue(Select(Upper.getNode()), 0); + + SDValue Lower = CurDAG->getConstant(LowerVal, VT); + SDValue Or = CurDAG->getNode(Opcode, DL, VT, Upper, Lower); + return Or.getNode(); +} + +SDNode *SystemZDAGToDAGISel::Select(SDNode *Node) { + // 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 0; + } + + unsigned Opcode = Node->getOpcode(); + switch (Opcode) { + case ISD::OR: + case ISD::XOR: + // If this is a 64-bit operation in which both 32-bit halves are nonzero, + // split the operation into two. + if (Node->getValueType(0) == MVT::i64) + if (ConstantSDNode *Op1 = dyn_cast<ConstantSDNode>(Node->getOperand(1))) { + uint64_t Val = Op1->getZExtValue(); + if (!SystemZ::isImmLF(Val) && !SystemZ::isImmHF(Val)) + Node = splitLargeImmediate(Opcode, Node, Node->getOperand(0), + Val - uint32_t(Val), uint32_t(Val)); + } + break; + + case ISD::Constant: + // If this is a 64-bit constant that is out of the range of LLILF, + // LLIHF and LGFI, split it into two 32-bit pieces. + if (Node->getValueType(0) == MVT::i64) { + uint64_t Val = cast<ConstantSDNode>(Node)->getZExtValue(); + if (!SystemZ::isImmLF(Val) && !SystemZ::isImmHF(Val) && !isInt<32>(Val)) + Node = splitLargeImmediate(ISD::OR, Node, SDValue(), + Val - uint32_t(Val), uint32_t(Val)); + } + break; + + case ISD::ATOMIC_LOAD_SUB: + // Try to convert subtractions of constants to additions. + if (ConstantSDNode *Op2 = dyn_cast<ConstantSDNode>(Node->getOperand(2))) { + uint64_t Value = -Op2->getZExtValue(); + EVT VT = Node->getValueType(0); + if (VT == MVT::i32 || isInt<32>(Value)) { + SDValue Ops[] = { Node->getOperand(0), Node->getOperand(1), + CurDAG->getConstant(int32_t(Value), VT) }; + Node = CurDAG->MorphNodeTo(Node, ISD::ATOMIC_LOAD_ADD, + Node->getVTList(), Ops, array_lengthof(Ops)); + } + } + break; + } + + // 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; +} + +bool SystemZDAGToDAGISel:: +SelectInlineAsmMemoryOperand(const SDValue &Op, + char ConstraintCode, + std::vector<SDValue> &OutOps) { + assert(ConstraintCode == 'm' && "Unexpected constraint code"); + // Accept addresses with short displacements, which are compatible + // with Q, R, S and T. But keep the index operand for future expansion. + SDValue Base, Disp, Index; + if (!selectBDXAddr(SystemZAddressingMode::FormBD, + SystemZAddressingMode::Disp12Only, + Op, Base, Disp, Index)) + return true; + OutOps.push_back(Base); + OutOps.push_back(Disp); + OutOps.push_back(Index); + return false; +} diff --git a/lib/Target/SystemZ/SystemZISelLowering.cpp b/lib/Target/SystemZ/SystemZISelLowering.cpp new file mode 100644 index 0000000000..eb21b31da8 --- /dev/null +++ b/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -0,0 +1,2233 @@ +//===-- 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 "SystemZCallingConv.h" +#include "SystemZConstantPoolValue.h" +#include "SystemZMachineFunctionInfo.h" +#include "SystemZTargetMachine.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" + +using namespace llvm; + +// Classify VT as either 32 or 64 bit. +static bool is32Bit(EVT VT) { + switch (VT.getSimpleVT().SimpleTy) { + case MVT::i32: + return true; + case MVT::i64: + return false; + default: + llvm_unreachable("Unsupported type"); + } +} + +// Return a version of MachineOperand that can be safely used before the +// final use. +static MachineOperand earlyUseOperand(MachineOperand Op) { + if (Op.isReg()) + Op.setIsKill(false); + return Op; +} + +SystemZTargetLowering::SystemZTargetLowering(SystemZTargetMachine &tm) + : TargetLowering(tm, new TargetLoweringObjectFileELF()), + Subtarget(*tm.getSubtargetImpl()), TM(tm) { + MVT PtrVT = getPointerTy(); + + // Set up the register classes. + addRegisterClass(MVT::i32, &SystemZ::GR32BitRegClass); + addRegisterClass(MVT::i64, &SystemZ::GR64BitRegClass); + addRegisterClass(MVT::f32, &SystemZ::FP32BitRegClass); + addRegisterClass(MVT::f64, &SystemZ::FP64BitRegClass); + addRegisterClass(MVT::f128, &SystemZ::FP128BitRegClass); + + // Compute derived properties from the register classes + computeRegisterProperties(); + + // Set up special registers. + setExceptionPointerRegister(SystemZ::R6D); + setExceptionSelectorRegister(SystemZ::R7D); + 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? + + // Instructions are strings of 2-byte aligned 2-byte values. + setMinFunctionAlignment(2); + + // Handle operations that are handled in a similar way for all types. + for (unsigned I = MVT::FIRST_INTEGER_VALUETYPE; + I <= MVT::LAST_FP_VALUETYPE; + ++I) { + MVT VT = MVT::SimpleValueType(I); + if (isTypeLegal(VT)) { + // Expand SETCC(X, Y, COND) into SELECT_CC(X, Y, 1, 0, COND). + setOperationAction(ISD::SETCC, VT, Expand); + + // Expand SELECT(C, A, B) into SELECT_CC(X, 0, A, B, NE). + setOperationAction(ISD::SELECT, VT, Expand); + + // Lower SELECT_CC and BR_CC into separate comparisons and branches. + setOperationAction(ISD::SELECT_CC, VT, Custom); + setOperationAction(ISD::BR_CC, VT, Custom); + } + } + + // Expand jump table branches as address arithmetic followed by an + // indirect jump. + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + + // Expand BRCOND into a BR_CC (see above). + setOperationAction(ISD::BRCOND, MVT::Other, Expand); + + // Handle integer types. + for (unsigned I = MVT::FIRST_INTEGER_VALUETYPE; + I <= MVT::LAST_INTEGER_VALUETYPE; + ++I) { + MVT VT = MVT::SimpleValueType(I); + if (isTypeLegal(VT)) { + // Expand individual DIV and REMs into DIVREMs. + setOperationAction(ISD::SDIV, VT, Expand); + setOperationAction(ISD::UDIV, VT, Expand); + setOperationAction(ISD::SREM, VT, Expand); + setOperationAction(ISD::UREM, VT, Expand); + setOperationAction(ISD::SDIVREM, VT, Custom); + setOperationAction(ISD::UDIVREM, VT, Custom); + + // Expand ATOMIC_LOAD and ATOMIC_STORE using ATOMIC_CMP_SWAP. + // FIXME: probably much too conservative. + setOperationAction(ISD::ATOMIC_LOAD, VT, Expand); + setOperationAction(ISD::ATOMIC_STORE, VT, Expand); + + // No special instructions for these. + setOperationAction(ISD::CTPOP, VT, Expand); + setOperationAction(ISD::CTTZ, VT, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, VT, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, VT, Expand); + setOperationAction(ISD::ROTR, VT, Expand); + + // Use *MUL_LOHI where possible and a wider multiplication otherwise. + setOperationAction(ISD::MULHS, VT, Expand); + setOperationAction(ISD::MULHU, VT, Expand); + + // We have instructions for signed but not unsigned FP conversion. + setOperationAction(ISD::FP_TO_UINT, VT, Expand); + } + } + + // Type legalization will convert 8- and 16-bit atomic operations into + // forms that operate on i32s (but still keeping the original memory VT). + // Lower them into full i32 operations. + setOperationAction(ISD::ATOMIC_SWAP, MVT::i32, Custom); + setOperationAction(ISD::ATOMIC_LOAD_ADD, MVT::i32, Custom); + setOperationAction(ISD::ATOMIC_LOAD_SUB, MVT::i32, Custom); + setOperationAction(ISD::ATOMIC_LOAD_AND, MVT::i32, Custom); + setOperationAction(ISD::ATOMIC_LOAD_OR, MVT::i32, Custom); + setOperationAction(ISD::ATOMIC_LOAD_XOR, MVT::i32, Custom); + setOperationAction(ISD::ATOMIC_LOAD_NAND, MVT::i32, Custom); + setOperationAction(ISD::ATOMIC_LOAD_MIN, MVT::i32, Custom); + setOperationAction(ISD::ATOMIC_LOAD_MAX, MVT::i32, Custom); + setOperationAction(ISD::ATOMIC_LOAD_UMIN, MVT::i32, Custom); + setOperationAction(ISD::ATOMIC_LOAD_UMAX, MVT::i32, Custom); + setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32, Custom); + + // We have instructions for signed but not unsigned FP conversion. + // Handle unsigned 32-bit types as signed 64-bit types. + setOperationAction(ISD::UINT_TO_FP, MVT::i32, Promote); + setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand); + + // We have native support for a 64-bit CTLZ, via FLOGR. + setOperationAction(ISD::CTLZ, MVT::i32, Promote); + setOperationAction(ISD::CTLZ, MVT::i64, Legal); + + // Give LowerOperation the chance to replace 64-bit ORs with subregs. + setOperationAction(ISD::OR, MVT::i64, Custom); + + // The architecture has 32-bit SMUL_LOHI and UMUL_LOHI (MR and MLR), + // but they aren't really worth using. There is no 64-bit SMUL_LOHI, + // but there is a 64-bit UMUL_LOHI: MLGR. + setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i64, Custom); + + // FIXME: Can we support these natively? + setOperationAction(ISD::SRL_PARTS, MVT::i64, Expand); + setOperationAction(ISD::SHL_PARTS, MVT::i64, Expand); + setOperationAction(ISD::SRA_PARTS, MVT::i64, Expand); + + // We have native instructions for i8, i16 and i32 extensions, but not i1. + setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::EXTLOAD, MVT::i1, Promote); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + + // Handle the various types of symbolic address. + setOperationAction(ISD::ConstantPool, PtrVT, Custom); + setOperationAction(ISD::GlobalAddress, PtrVT, Custom); + setOperationAction(ISD::GlobalTLSAddress, PtrVT, Custom); + setOperationAction(ISD::BlockAddress, PtrVT, Custom); + setOperationAction(ISD::JumpTable, PtrVT, Custom); + + // We need to handle dynamic allocations specially because of the + // 160-byte area at the bottom of the stack. + setOperationAction(ISD::DYNAMIC_STACKALLOC, PtrVT, Custom); + + // Use custom expanders so that we can force the function to use + // a frame pointer. + setOperationAction(ISD::STACKSAVE, MVT::Other, Custom); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Custom); + + // Expand these using getExceptionSelectorRegister() and + // getExceptionPointerRegister(). + setOperationAction(ISD::EXCEPTIONADDR, PtrVT, Expand); + setOperationAction(ISD::EHSELECTION, PtrVT, Expand); + + // Handle floating-point types. + for (unsigned I = MVT::FIRST_FP_VALUETYPE; + I <= MVT::LAST_FP_VALUETYPE; + ++I) { + MVT VT = MVT::SimpleValueType(I); + if (isTypeLegal(VT)) { + // We can use FI for FRINT. + setOperationAction(ISD::FRINT, VT, Legal); + + // No special instructions for these. + setOperationAction(ISD::FSIN, VT, Expand); + setOperationAction(ISD::FCOS, VT, Expand); + setOperationAction(ISD::FREM, VT, Expand); + } + } + + // We have fused multiply-addition for f32 and f64 but not f128. + setOperationAction(ISD::FMA, MVT::f32, Legal); + setOperationAction(ISD::FMA, MVT::f64, Legal); + setOperationAction(ISD::FMA, MVT::f128, Expand); + + // Needed so that we don't try to implement f128 constant loads using + // a load-and-extend of a f80 constant (in cases where the constant + // would fit in an f80). + setLoadExtAction(ISD::EXTLOAD, MVT::f80, Expand); + + // Floating-point truncation and stores need to be done separately. + setTruncStoreAction(MVT::f64, MVT::f32, Expand); + setTruncStoreAction(MVT::f128, MVT::f32, Expand); + setTruncStoreAction(MVT::f128, MVT::f64, Expand); + + // We have 64-bit FPR<->GPR moves, but need special handling for + // 32-bit forms. + setOperationAction(ISD::BITCAST, MVT::i32, Custom); + setOperationAction(ISD::BITCAST, MVT::f32, Custom); + + // VASTART and VACOPY need to deal with the SystemZ-specific varargs + // structure, but VAEND is a no-op. + setOperationAction(ISD::VASTART, MVT::Other, Custom); + setOperationAction(ISD::VACOPY, MVT::Other, Custom); + setOperationAction(ISD::VAEND, MVT::Other, Expand); +} + +bool SystemZTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { + // We can load zero using LZ?R and negative zero using LZ?R;LC?BR. + return Imm.isZero() || Imm.isNegZero(); +} + +//===----------------------------------------------------------------------===// +// Inline asm support +//===----------------------------------------------------------------------===// + +TargetLowering::ConstraintType +SystemZTargetLowering::getConstraintType(const std::string &Constraint) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + case 'a': // Address register + case 'd': // Data register (equivalent to 'r') + case 'f': // Floating-point register + case 'r': // General-purpose register + return C_RegisterClass; + + case 'Q': // Memory with base and unsigned 12-bit displacement + case 'R': // Likewise, plus an index + case 'S': // Memory with base and signed 20-bit displacement + case 'T': // Likewise, plus an index + case 'm': // Equivalent to 'T'. + return C_Memory; + + case 'I': // Unsigned 8-bit constant + case 'J': // Unsigned 12-bit constant + case 'K': // Signed 16-bit constant + case 'L': // Signed 20-bit displacement (on all targets we support) + case 'M': // 0x7fffffff + return C_Other; + + default: + break; + } + } + return TargetLowering::getConstraintType(Constraint); +} + +TargetLowering::ConstraintWeight SystemZTargetLowering:: +getSingleConstraintMatchWeight(AsmOperandInfo &info, + const char *constraint) const { + ConstraintWeight weight = CW_Invalid; + Value *CallOperandVal = info.CallOperandVal; + // If we don't have a value, we can't do a match, + // but allow it at the lowest weight. + if (CallOperandVal == NULL) + return CW_Default; + Type *type = CallOperandVal->getType(); + // Look at the constraint type. + switch (*constraint) { + default: + weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint); + break; + + case 'a': // Address register + case 'd': // Data register (equivalent to 'r') + case 'r': // General-purpose register + if (CallOperandVal->getType()->isIntegerTy()) + weight = CW_Register; + break; + + case 'f': // Floating-point register + if (type->isFloatingPointTy()) + weight = CW_Register; + break; + + case 'I': // Unsigned 8-bit constant + if (ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) + if (isUInt<8>(C->getZExtValue())) + weight = CW_Constant; + break; + + case 'J': // Unsigned 12-bit constant + if (ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) + if (isUInt<12>(C->getZExtValue())) + weight = CW_Constant; + break; + + case 'K': // Signed 16-bit constant + if (ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) + if (isInt<16>(C->getSExtValue())) + weight = CW_Constant; + break; + + case 'L': // Signed 20-bit displacement (on all targets we support) + if (ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) + if (isInt<20>(C->getSExtValue())) + weight = CW_Constant; + break; + + case 'M': // 0x7fffffff + if (ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) + if (C->getZExtValue() == 0x7fffffff) + weight = CW_Constant; + break; + } + return weight; +} + +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 'd': // Data register (equivalent to 'r') + case 'r': // General-purpose register + if (VT == MVT::i64) + return std::make_pair(0U, &SystemZ::GR64BitRegClass); + else if (VT == MVT::i128) + return std::make_pair(0U, &SystemZ::GR128BitRegClass); + return std::make_pair(0U, &SystemZ::GR32BitRegClass); + + case 'a': // Address register + if (VT == MVT::i64) + return std::make_pair(0U, &SystemZ::ADDR64BitRegClass); + else if (VT == MVT::i128) + return std::make_pair(0U, &SystemZ::ADDR128BitRegClass); + return std::make_pair(0U, &SystemZ::ADDR32BitRegClass); + + case 'f': // Floating-point register + if (VT == MVT::f64) + return std::make_pair(0U, &SystemZ::FP64BitRegClass); + else if (VT == MVT::f128) + return std::make_pair(0U, &SystemZ::FP128BitRegClass); + return std::make_pair(0U, &SystemZ::FP32BitRegClass); + } + } + return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); +} + +void SystemZTargetLowering:: +LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, + std::vector<SDValue> &Ops, + SelectionDAG &DAG) const { + // Only support length 1 constraints for now. + if (Constraint.length() == 1) { + switch (Constraint[0]) { + case 'I': // Unsigned 8-bit constant + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) + if (isUInt<8>(C->getZExtValue())) + Ops.push_back(DAG.getTargetConstant(C->getZExtValue(), + Op.getValueType())); + return; + + case 'J': // Unsigned 12-bit constant + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) + if (isUInt<12>(C->getZExtValue())) + Ops.push_back(DAG.getTargetConstant(C->getZExtValue(), + Op.getValueType())); + return; + + case 'K': // Signed 16-bit constant + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) + if (isInt<16>(C->getSExtValue())) + Ops.push_back(DAG.getTargetConstant(C->getSExtValue(), + Op.getValueType())); + return; + + case 'L': // Signed 20-bit displacement (on all targets we support) + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) + if (isInt<20>(C->getSExtValue())) + Ops.push_back(DAG.getTargetConstant(C->getSExtValue(), + Op.getValueType())); + return; + + case 'M': // 0x7fffffff + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) + if (C->getZExtValue() == 0x7fffffff) + Ops.push_back(DAG.getTargetConstant(C->getZExtValue(), + Op.getValueType())); + return; + } + } + TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); +} + +//===----------------------------------------------------------------------===// +// Calling conventions +//===----------------------------------------------------------------------===// + +#include "SystemZGenCallingConv.inc" + +// Value is a value that has been passed to us in the location described by VA +// (and so has type VA.getLocVT()). Convert Value to VA.getValVT(), chaining +// any loads onto Chain. +static SDValue convertLocVTToValVT(SelectionDAG &DAG, DebugLoc DL, + CCValAssign &VA, SDValue Chain, + SDValue Value) { + // If the argument has been promoted from a smaller type, insert an + // assertion to capture this. + if (VA.getLocInfo() == CCValAssign::SExt) + Value = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), Value, + DAG.getValueType(VA.getValVT())); + else if (VA.getLocInfo() == CCValAssign::ZExt) + Value = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), Value, + DAG.getValueType(VA.getValVT())); + + if (VA.isExtInLoc()) + Value = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Value); + else if (VA.getLocInfo() == CCValAssign::Indirect) + Value = DAG.getLoad(VA.getValVT(), DL, Chain, Value, + MachinePointerInfo(), false, false, false, 0); + else + assert(VA.getLocInfo() == CCValAssign::Full && "Unsupported getLocInfo"); + return Value; +} + +// Value is a value of type VA.getValVT() that we need to copy into +// the location described by VA. Return a copy of Value converted to +// VA.getValVT(). The caller is responsible for handling indirect values. +static SDValue convertValVTToLocVT(SelectionDAG &DAG, DebugLoc DL, + CCValAssign &VA, SDValue Value) { + switch (VA.getLocInfo()) { + case CCValAssign::SExt: + return DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Value); + case CCValAssign::ZExt: + return DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Value); + case CCValAssign::AExt: + return DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Value); + case CCValAssign::Full: + return Value; + default: + llvm_unreachable("Unhandled getLocInfo()"); + } +} + +SDValue SystemZTargetLowering:: +LowerFormalArguments(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 &MRI = MF.getRegInfo(); + SystemZMachineFunctionInfo *FuncInfo = + MF.getInfo<SystemZMachineFunctionInfo>(); + const SystemZFrameLowering *TFL = + static_cast<const SystemZFrameLowering *>(TM.getFrameLowering()); + + // Assign locations to all of the incoming arguments. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CallConv, IsVarArg, MF, TM, ArgLocs, *DAG.getContext()); + CCInfo.AnalyzeFormalArguments(Ins, CC_SystemZ); + + unsigned NumFixedGPRs = 0; + unsigned NumFixedFPRs = 0; + 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 + const TargetRegisterClass *RC; + switch (LocVT.getSimpleVT().SimpleTy) { + default: + // Integers smaller than i64 should be promoted to i64. + llvm_unreachable("Unexpected argument type"); + case MVT::i32: + NumFixedGPRs += 1; + RC = &SystemZ::GR32BitRegClass; + break; + case MVT::i64: + NumFixedGPRs += 1; + RC = &SystemZ::GR64BitRegClass; + break; + case MVT::f32: + NumFixedFPRs += 1; + RC = &SystemZ::FP32BitRegClass; + break; + case MVT::f64: + NumFixedFPRs += 1; + RC = &SystemZ::FP64BitRegClass; + break; + } + + unsigned VReg = MRI.createVirtualRegister(RC); + MRI.addLiveIn(VA.getLocReg(), VReg); + ArgValue = DAG.getCopyFromReg(Chain, DL, VReg, LocVT); + } else { + assert(VA.isMemLoc() && "Argument not register or memory"); + + // 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. Unpromoted ints and floats are + // passed as right-justified 8-byte values. + EVT PtrVT = getPointerTy(); + SDValue FIN = DAG.getFrameIndex(FI, PtrVT); + if (VA.getLocVT() == MVT::i32 || VA.getLocVT() == MVT::f32) + FIN = DAG.getNode(ISD::ADD, DL, PtrVT, FIN, DAG.getIntPtrConstant(4)); + ArgValue = DAG.getLoad(LocVT, DL, Chain, FIN, + MachinePointerInfo::getFixedStack(FI), + false, false, false, 0); + } + + // Convert the value of the argument register into the value that's + // being passed. + InVals.push_back(convertLocVTToValVT(DAG, DL, VA, Chain, ArgValue)); + } + + if (IsVarArg) { + // Save the number of non-varargs registers for later use by va_start, etc. + FuncInfo->setVarArgsFirstGPR(NumFixedGPRs); + FuncInfo->setVarArgsFirstFPR(NumFixedFPRs); + + // Likewise the address (in the form of a frame index) of where the + // first stack vararg would be. The 1-byte size here is arbitrary. + int64_t StackSize = CCInfo.getNextStackOffset(); + FuncInfo->setVarArgsFrameIndex(MFI->CreateFixedObject(1, StackSize, true)); + + // ...and a similar frame index for the caller-allocated save area + // that will be used to store the incoming registers. + int64_t RegSaveOffset = TFL->getOffsetOfLocalArea(); + unsigned RegSaveIndex = MFI->CreateFixedObject(1, RegSaveOffset, true); + FuncInfo->setRegSaveFrameIndex(RegSaveIndex); + + // Store the FPR varargs in the reserved frame slots. (We store the + // GPRs as part of the prologue.) + if (NumFixedFPRs < SystemZ::NumArgFPRs) { + SDValue MemOps[SystemZ::NumArgFPRs]; + for (unsigned I = NumFixedFPRs; I < SystemZ::NumArgFPRs; ++I) { + unsigned Offset = TFL->getRegSpillOffset(SystemZ::ArgFPRs[I]); + int FI = MFI->CreateFixedObject(8, RegSaveOffset + Offset, true); + SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); + unsigned VReg = MF.addLiveIn(SystemZ::ArgFPRs[I], + &SystemZ::FP64BitRegClass); + SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, VReg, MVT::f64); + MemOps[I] = DAG.getStore(ArgValue.getValue(1), DL, ArgValue, FIN, + MachinePointerInfo::getFixedStack(FI), + false, false, 0); + + } + // Join the stores, which are independent of one another. + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, + &MemOps[NumFixedFPRs], + SystemZ::NumArgFPRs - NumFixedFPRs); + } + } + + return Chain; +} + +SDValue +SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI, + SmallVectorImpl<SDValue> &InVals) const { + SelectionDAG &DAG = CLI.DAG; + DebugLoc &DL = CLI.DL; + SmallVector<ISD::OutputArg, 32> &Outs = CLI.Outs; + SmallVector<SDValue, 32> &OutVals = CLI.OutVals; + SmallVector<ISD::InputArg, 32> &Ins = CLI.Ins; + SDValue Chain = CLI.Chain; + SDValue Callee = CLI.Callee; + bool &isTailCall = CLI.IsTailCall; + CallingConv::ID CallConv = CLI.CallConv; + bool IsVarArg = CLI.IsVarArg; + MachineFunction &MF = DAG.getMachineFunction(); + EVT PtrVT = getPointerTy(); + + // SystemZ target does not yet support tail call optimization. + isTailCall = false; + + // Analyze the operands of the call, assigning locations to each operand. + SmallVector<CCValAssign, 16> ArgLocs; + CCState ArgCCInfo(CallConv, IsVarArg, MF, TM, ArgLocs, *DAG.getContext()); + ArgCCInfo.AnalyzeCallOperands(Outs, CC_SystemZ); + + // Get a count of how many bytes are to be pushed on the stack. + unsigned NumBytes = ArgCCInfo.getNextStackOffset(); + + // Mark the start of the call. + Chain = DAG.getCALLSEQ_START(Chain, DAG.getConstant(NumBytes, PtrVT, true)); + + // Copy argument values to their designated locations. + SmallVector<std::pair<unsigned, SDValue>, 9> RegsToPass; + SmallVector<SDValue, 8> MemOpChains; + SDValue StackPtr; + for (unsigned I = 0, E = ArgLocs.size(); I != E; ++I) { + CCValAssign &VA = ArgLocs[I]; + SDValue ArgValue = OutVals[I]; + + if (VA.getLocInfo() == CCValAssign::Indirect) { + // Store the argument in a stack slot and pass its address. + SDValue SpillSlot = DAG.CreateStackTemporary(VA.getValVT()); + int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex(); + MemOpChains.push_back(DAG.getStore(Chain, DL, ArgValue, SpillSlot, + MachinePointerInfo::getFixedStack(FI), + false, false, 0)); + ArgValue = SpillSlot; + } else + ArgValue = convertValVTToLocVT(DAG, DL, VA, ArgValue); + + if (VA.isRegLoc()) + // Queue up the argument copies and emit them at the end. + RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue)); + else { + assert(VA.isMemLoc() && "Argument not register or memory"); + + // Work out the address of the stack slot. Unpromoted ints and + // floats are passed as right-justified 8-byte values. + if (!StackPtr.getNode()) + StackPtr = DAG.getCopyFromReg(Chain, DL, SystemZ::R15D, PtrVT); + unsigned Offset = SystemZMC::CallFrameSize + VA.getLocMemOffset(); + if (VA.getLocVT() == MVT::i32 || VA.getLocVT() == MVT::f32) + Offset += 4; + SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, + DAG.getIntPtrConstant(Offset)); + + // Emit the store. + MemOpChains.push_back(DAG.getStore(Chain, DL, ArgValue, Address, + MachinePointerInfo(), + false, false, 0)); + } + } + + // Join the stores, which are independent of one another. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, + &MemOpChains[0], MemOpChains.size()); + + // Build a sequence of copy-to-reg nodes, chained and glued together. + SDValue Glue; + for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) { + Chain = DAG.getCopyToReg(Chain, DL, RegsToPass[I].first, + RegsToPass[I].second, Glue); + Glue = Chain.getValue(1); + } + + // Accept direct calls by converting symbolic call addresses to the + // associated Target* opcodes. + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) { + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, PtrVT); + Callee = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Callee); + } else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) { + Callee = DAG.getTargetExternalSymbol(E->getSymbol(), PtrVT); + Callee = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Callee); + } + + // The first call operand is the chain and the second is the target address. + 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())); + + // Glue the call to the argument copies, if any. + if (Glue.getNode()) + Ops.push_back(Glue); + + // Emit the call. + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + Chain = DAG.getNode(SystemZISD::CALL, DL, NodeTys, &Ops[0], Ops.size()); + Glue = Chain.getValue(1); + + // Mark the end of the call, which is glued to the call itself. + Chain = DAG.getCALLSEQ_END(Chain, + DAG.getConstant(NumBytes, PtrVT, true), + DAG.getConstant(0, PtrVT, true), + Glue); + Glue = Chain.getValue(1); + + // Assign locations to each value returned by this call. + SmallVector<CCValAssign, 16> RetLocs; + CCState RetCCInfo(CallConv, IsVarArg, MF, TM, RetLocs, *DAG.getContext()); + RetCCInfo.AnalyzeCallResult(Ins, RetCC_SystemZ); + + // Copy all of the result registers out of their specified physreg. + for (unsigned I = 0, E = RetLocs.size(); I != E; ++I) { + CCValAssign &VA = RetLocs[I]; + + // Copy the value out, gluing the copy to the end of the call sequence. + SDValue RetValue = DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), + VA.getLocVT(), Glue); + Chain = RetValue.getValue(1); + Glue = RetValue.getValue(2); + + // Convert the value of the return register into the value that's + // being returned. + InVals.push_back(convertLocVTToValVT(DAG, DL, VA, Chain, 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 { + MachineFunction &MF = DAG.getMachineFunction(); + + // Assign locations to each returned value. + SmallVector<CCValAssign, 16> RetLocs; + CCState RetCCInfo(CallConv, IsVarArg, MF, TM, RetLocs, *DAG.getContext()); + RetCCInfo.AnalyzeReturn(Outs, RetCC_SystemZ); + + // Quick exit for void returns + if (RetLocs.empty()) + return DAG.getNode(SystemZISD::RET_FLAG, DL, MVT::Other, Chain); + + // Copy the result values into the output registers. + SDValue Glue; + SmallVector<SDValue, 4> RetOps; + RetOps.push_back(Chain); + for (unsigned I = 0, E = RetLocs.size(); I != E; ++I) { + CCValAssign &VA = RetLocs[I]; + SDValue RetValue = OutVals[I]; + + // Make the return register live on exit. + assert(VA.isRegLoc() && "Can only return in registers!"); + + // Promote the value as required. + RetValue = convertValVTToLocVT(DAG, DL, VA, RetValue); + + // Chain and glue the copies together. + unsigned Reg = VA.getLocReg(); + Chain = DAG.getCopyToReg(Chain, DL, Reg, RetValue, Glue); + Glue = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(Reg, VA.getLocVT())); + } + + // Update chain and glue. + RetOps[0] = Chain; + if (Glue.getNode()) + RetOps.push_back(Glue); + + return DAG.getNode(SystemZISD::RET_FLAG, DL, MVT::Other, + RetOps.data(), RetOps.size()); +} + +// CC is a comparison that will be implemented using an integer or +// floating-point comparison. Return the condition code mask for +// a branch on true. In the integer case, CCMASK_CMP_UO is set for +// unsigned comparisons and clear for signed ones. In the floating-point +// case, CCMASK_CMP_UO has its normal mask meaning (unordered). +static unsigned CCMaskForCondCode(ISD::CondCode CC) { +#define CONV(X) \ + case ISD::SET##X: return SystemZ::CCMASK_CMP_##X; \ + case ISD::SETO##X: return SystemZ::CCMASK_CMP_##X; \ + case ISD::SETU##X: return SystemZ::CCMASK_CMP_UO | SystemZ::CCMASK_CMP_##X + + switch (CC) { + default: + llvm_unreachable("Invalid integer condition!"); + + CONV(EQ); + CONV(NE); + CONV(GT); + CONV(GE); + CONV(LT); + CONV(LE); + + case ISD::SETO: return SystemZ::CCMASK_CMP_O; + case ISD::SETUO: return SystemZ::CCMASK_CMP_UO; + } +#undef CONV +} + +// If a comparison described by IsUnsigned, CCMask, CmpOp0 and CmpOp1 +// is suitable for CLI(Y), CHHSI or CLHHSI, adjust the operands as necessary. +static void adjustSubwordCmp(SelectionDAG &DAG, bool &IsUnsigned, + SDValue &CmpOp0, SDValue &CmpOp1, + unsigned &CCMask) { + // For us to make any changes, it must a comparison between a single-use + // load and a constant. + if (!CmpOp0.hasOneUse() || + CmpOp0.getOpcode() != ISD::LOAD || + CmpOp1.getOpcode() != ISD::Constant) + return; + + // We must have an 8- or 16-bit load. + LoadSDNode *Load = cast<LoadSDNode>(CmpOp0); + unsigned NumBits = Load->getMemoryVT().getStoreSizeInBits(); + if (NumBits != 8 && NumBits != 16) + return; + + // The load must be an extending one and the constant must be within the + // range of the unextended value. + ConstantSDNode *Constant = cast<ConstantSDNode>(CmpOp1); + uint64_t Value = Constant->getZExtValue(); + uint64_t Mask = (1 << NumBits) - 1; + if (Load->getExtensionType() == ISD::SEXTLOAD) { + int64_t SignedValue = Constant->getSExtValue(); + if (uint64_t(SignedValue) + (1 << (NumBits - 1)) > Mask) + return; + // Unsigned comparison between two sign-extended values is equivalent + // to unsigned comparison between two zero-extended values. + if (IsUnsigned) + Value &= Mask; + else if (CCMask == SystemZ::CCMASK_CMP_EQ || + CCMask == SystemZ::CCMASK_CMP_NE) + // Any choice of IsUnsigned is OK for equality comparisons. + // We could use either CHHSI or CLHHSI for 16-bit comparisons, + // but since we use CLHHSI for zero extensions, it seems better + // to be consistent and do the same here. + Value &= Mask, IsUnsigned = true; + else if (NumBits == 8) { + // Try to treat the comparison as unsigned, so that we can use CLI. + // Adjust CCMask and Value as necessary. + if (Value == 0 && CCMask == SystemZ::CCMASK_CMP_LT) + // Test whether the high bit of the byte is set. + Value = 127, CCMask = SystemZ::CCMASK_CMP_GT, IsUnsigned = true; + else if (SignedValue == -1 && CCMask == SystemZ::CCMASK_CMP_GT) + // Test whether the high bit of the byte is clear. + Value = 128, CCMask = SystemZ::CCMASK_CMP_LT, IsUnsigned = true; + else + // No instruction exists for this combination. + return; + } + } else if (Load->getExtensionType() == ISD::ZEXTLOAD) { + if (Value > Mask) + return; + // Signed comparison between two zero-extended values is equivalent + // to unsigned comparison. + IsUnsigned = true; + } else + return; + + // Make sure that the first operand is an i32 of the right extension type. + ISD::LoadExtType ExtType = IsUnsigned ? ISD::ZEXTLOAD : ISD::SEXTLOAD; + if (CmpOp0.getValueType() != MVT::i32 || + Load->getExtensionType() != ExtType) + CmpOp0 = DAG.getExtLoad(ExtType, Load->getDebugLoc(), MVT::i32, + Load->getChain(), Load->getBasePtr(), + Load->getPointerInfo(), Load->getMemoryVT(), + Load->isVolatile(), Load->isNonTemporal(), + Load->getAlignment()); + + // Make sure that the second operand is an i32 with the right value. + if (CmpOp1.getValueType() != MVT::i32 || + Value != Constant->getZExtValue()) + CmpOp1 = DAG.getConstant(Value, MVT::i32); +} + +// Return true if a comparison described by CCMask, CmpOp0 and CmpOp1 +// is an equality comparison that is better implemented using unsigned +// rather than signed comparison instructions. +static bool preferUnsignedComparison(SelectionDAG &DAG, SDValue CmpOp0, + SDValue CmpOp1, unsigned CCMask) { + // The test must be for equality or inequality. + if (CCMask != SystemZ::CCMASK_CMP_EQ && CCMask != SystemZ::CCMASK_CMP_NE) + return false; + + if (CmpOp1.getOpcode() == ISD::Constant) { + uint64_t Value = cast<ConstantSDNode>(CmpOp1)->getSExtValue(); + + // If we're comparing with memory, prefer unsigned comparisons for + // values that are in the unsigned 16-bit range but not the signed + // 16-bit range. We want to use CLFHSI and CLGHSI. + if (CmpOp0.hasOneUse() && + ISD::isNormalLoad(CmpOp0.getNode()) && + (Value >= 32768 && Value < 65536)) + return true; + + // Use unsigned comparisons for values that are in the CLGFI range + // but not in the CGFI range. + if (CmpOp0.getValueType() == MVT::i64 && (Value >> 31) == 1) + return true; + + return false; + } + + // Prefer CL for zero-extended loads. + if (CmpOp1.getOpcode() == ISD::ZERO_EXTEND || + ISD::isZEXTLoad(CmpOp1.getNode())) + return true; + + // ...and for "in-register" zero extensions. + if (CmpOp1.getOpcode() == ISD::AND && CmpOp1.getValueType() == MVT::i64) { + SDValue Mask = CmpOp1.getOperand(1); + if (Mask.getOpcode() == ISD::Constant && + cast<ConstantSDNode>(Mask)->getZExtValue() == 0xffffffff) + return true; + } + + return false; +} + +// Return a target node that compares CmpOp0 and CmpOp1. Set CCMask to the +// 4-bit condition-code mask for CC. +static SDValue emitCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1, + ISD::CondCode CC, unsigned &CCMask) { + bool IsUnsigned = false; + CCMask = CCMaskForCondCode(CC); + if (!CmpOp0.getValueType().isFloatingPoint()) { + IsUnsigned = CCMask & SystemZ::CCMASK_CMP_UO; + CCMask &= ~SystemZ::CCMASK_CMP_UO; + adjustSubwordCmp(DAG, IsUnsigned, CmpOp0, CmpOp1, CCMask); + if (preferUnsignedComparison(DAG, CmpOp0, CmpOp1, CCMask)) + IsUnsigned = true; + } + + DebugLoc DL = CmpOp0.getDebugLoc(); + return DAG.getNode((IsUnsigned ? SystemZISD::UCMP : SystemZISD::CMP), + DL, MVT::Glue, CmpOp0, CmpOp1); +} + +// Lower a binary operation that produces two VT results, one in each +// half of a GR128 pair. Op0 and Op1 are the VT operands to the operation, +// Extend extends Op0 to a GR128, and Opcode performs the GR128 operation +// on the extended Op0 and (unextended) Op1. Store the even register result +// in Even and the odd register result in Odd. +static void lowerGR128Binary(SelectionDAG &DAG, DebugLoc DL, EVT VT, + unsigned Extend, unsigned Opcode, + SDValue Op0, SDValue Op1, + SDValue &Even, SDValue &Odd) { + SDNode *In128 = DAG.getMachineNode(Extend, DL, MVT::Untyped, Op0); + SDValue Result = DAG.getNode(Opcode, DL, MVT::Untyped, + SDValue(In128, 0), Op1); + bool Is32Bit = is32Bit(VT); + SDValue SubReg0 = DAG.getTargetConstant(SystemZ::even128(Is32Bit), VT); + SDValue SubReg1 = DAG.getTargetConstant(SystemZ::odd128(Is32Bit), VT); + SDNode *Reg0 = DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL, + VT, Result, SubReg0); + SDNode *Reg1 = DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL, + VT, Result, SubReg1); + Even = SDValue(Reg0, 0); + Odd = SDValue(Reg1, 0); +} + +SDValue SystemZTargetLowering::lowerBR_CC(SDValue Op, SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get(); + SDValue CmpOp0 = Op.getOperand(2); + SDValue CmpOp1 = Op.getOperand(3); + SDValue Dest = Op.getOperand(4); + DebugLoc DL = Op.getDebugLoc(); + + unsigned CCMask; + SDValue Flags = emitCmp(DAG, CmpOp0, CmpOp1, CC, CCMask); + return DAG.getNode(SystemZISD::BR_CCMASK, DL, Op.getValueType(), + Chain, DAG.getConstant(CCMask, MVT::i32), Dest, Flags); +} + +SDValue SystemZTargetLowering::lowerSELECT_CC(SDValue Op, + SelectionDAG &DAG) const { + SDValue CmpOp0 = Op.getOperand(0); + SDValue CmpOp1 = Op.getOperand(1); + SDValue TrueOp = Op.getOperand(2); + SDValue FalseOp = Op.getOperand(3); + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get(); + DebugLoc DL = Op.getDebugLoc(); + + unsigned CCMask; + SDValue Flags = emitCmp(DAG, CmpOp0, CmpOp1, CC, CCMask); + + SmallVector<SDValue, 4> Ops; + Ops.push_back(TrueOp); + Ops.push_back(FalseOp); + Ops.push_back(DAG.getConstant(CCMask, MVT::i32)); + Ops.push_back(Flags); + + SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue); + return DAG.getNode(SystemZISD::SELECT_CCMASK, DL, VTs, &Ops[0], Ops.size()); +} + +SDValue SystemZTargetLowering::lowerGlobalAddress(GlobalAddressSDNode *Node, + SelectionDAG &DAG) const { + DebugLoc DL = Node->getDebugLoc(); + const GlobalValue *GV = Node->getGlobal(); + int64_t Offset = Node->getOffset(); + EVT PtrVT = getPointerTy(); + Reloc::Model RM = TM.getRelocationModel(); + CodeModel::Model CM = TM.getCodeModel(); + + SDValue Result; + if (Subtarget.isPC32DBLSymbol(GV, RM, CM)) { + // Make sure that the offset is aligned to a halfword. If it isn't, + // create an "anchor" at the previous 12-bit boundary. + // FIXME check whether there is a better way of handling this. + if (Offset & 1) { + Result = DAG.getTargetGlobalAddress(GV, DL, PtrVT, + Offset & ~uint64_t(0xfff)); + Offset &= 0xfff; + } else { + Result = DAG.getTargetGlobalAddress(GV, DL, PtrVT, Offset); + Offset = 0; + } + Result = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result); + } else { + Result = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, SystemZII::MO_GOT); + Result = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result); + Result = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Result, + MachinePointerInfo::getGOT(), false, 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, PtrVT, Result, + DAG.getConstant(Offset, PtrVT)); + + return Result; +} + +SDValue SystemZTargetLowering::lowerGlobalTLSAddress(GlobalAddressSDNode *Node, + SelectionDAG &DAG) const { + DebugLoc DL = Node->getDebugLoc(); + const GlobalValue *GV = Node->getGlobal(); + EVT PtrVT = getPointerTy(); + TLSModel::Model model = TM.getTLSModel(GV); + + if (model != TLSModel::LocalExec) + llvm_unreachable("only local-exec TLS mode supported"); + + // The high part of the thread pointer is in access register 0. + SDValue TPHi = DAG.getNode(SystemZISD::EXTRACT_ACCESS, DL, MVT::i32, + DAG.getConstant(0, MVT::i32)); + TPHi = DAG.getNode(ISD::ANY_EXTEND, DL, PtrVT, TPHi); + + // The low part of the thread pointer is in access register 1. + SDValue TPLo = DAG.getNode(SystemZISD::EXTRACT_ACCESS, DL, MVT::i32, + DAG.getConstant(1, MVT::i32)); + TPLo = DAG.getNode(ISD::ZERO_EXTEND, DL, PtrVT, TPLo); + + // Merge them into a single 64-bit address. + SDValue TPHiShifted = DAG.getNode(ISD::SHL, DL, PtrVT, TPHi, + DAG.getConstant(32, PtrVT)); + SDValue TP = DAG.getNode(ISD::OR, DL, PtrVT, TPHiShifted, TPLo); + + // Get the offset of GA from the thread pointer. + SystemZConstantPoolValue *CPV = + SystemZConstantPoolValue::Create(GV, SystemZCP::NTPOFF); + + // Force the offset into the constant pool and load it from there. + SDValue CPAddr = DAG.getConstantPool(CPV, PtrVT, 8); + SDValue Offset = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), + CPAddr, MachinePointerInfo::getConstantPool(), + false, false, false, 0); + + // Add the base and offset together. + return DAG.getNode(ISD::ADD, DL, PtrVT, TP, Offset); +} + +SDValue SystemZTargetLowering::lowerBlockAddress(BlockAddressSDNode *Node, + SelectionDAG &DAG) const { + DebugLoc DL = Node->getDebugLoc(); + const BlockAddress *BA = Node->getBlockAddress(); + int64_t Offset = Node->getOffset(); + EVT PtrVT = getPointerTy(); + + SDValue Result = DAG.getTargetBlockAddress(BA, PtrVT, Offset); + Result = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result); + return Result; +} + +SDValue SystemZTargetLowering::lowerJumpTable(JumpTableSDNode *JT, + SelectionDAG &DAG) const { + DebugLoc DL = JT->getDebugLoc(); + EVT PtrVT = getPointerTy(); + SDValue Result = DAG.getTargetJumpTable(JT->getIndex(), PtrVT); + + // Use LARL to load the address of the table. + return DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result); +} + +SDValue SystemZTargetLowering::lowerConstantPool(ConstantPoolSDNode *CP, + SelectionDAG &DAG) const { + DebugLoc DL = CP->getDebugLoc(); + EVT PtrVT = getPointerTy(); + + SDValue Result; + if (CP->isMachineConstantPoolEntry()) + Result = DAG.getTargetConstantPool(CP->getMachineCPVal(), PtrVT, + CP->getAlignment()); + else + Result = DAG.getTargetConstantPool(CP->getConstVal(), PtrVT, + CP->getAlignment(), CP->getOffset()); + + // Use LARL to load the address of the constant pool entry. + return DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result); +} + +SDValue SystemZTargetLowering::lowerBITCAST(SDValue Op, + SelectionDAG &DAG) const { + DebugLoc DL = Op.getDebugLoc(); + SDValue In = Op.getOperand(0); + EVT InVT = In.getValueType(); + EVT ResVT = Op.getValueType(); + + SDValue SubReg32 = DAG.getTargetConstant(SystemZ::subreg_32bit, MVT::i64); + SDValue Shift32 = DAG.getConstant(32, MVT::i64); + if (InVT == MVT::i32 && ResVT == MVT::f32) { + SDValue In64 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, In); + SDValue Shift = DAG.getNode(ISD::SHL, DL, MVT::i64, In64, Shift32); + SDValue Out64 = DAG.getNode(ISD::BITCAST, DL, MVT::f64, Shift); + SDNode *Out = DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL, + MVT::f32, Out64, SubReg32); + return SDValue(Out, 0); + } + if (InVT == MVT::f32 && ResVT == MVT::i32) { + SDNode *U64 = DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, MVT::f64); + SDNode *In64 = DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, DL, + MVT::f64, SDValue(U64, 0), In, SubReg32); + SDValue Out64 = DAG.getNode(ISD::BITCAST, DL, MVT::i64, SDValue(In64, 0)); + SDValue Shift = DAG.getNode(ISD::SRL, DL, MVT::i64, Out64, Shift32); + SDValue Out = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Shift); + return Out; + } + llvm_unreachable("Unexpected bitcast combination"); +} + +SDValue SystemZTargetLowering::lowerVASTART(SDValue Op, + SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + SystemZMachineFunctionInfo *FuncInfo = + MF.getInfo<SystemZMachineFunctionInfo>(); + EVT PtrVT = getPointerTy(); + + SDValue Chain = Op.getOperand(0); + SDValue Addr = Op.getOperand(1); + const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); + DebugLoc DL = Op.getDebugLoc(); + + // The initial values of each field. + const unsigned NumFields = 4; + SDValue Fields[NumFields] = { + DAG.getConstant(FuncInfo->getVarArgsFirstGPR(), PtrVT), + DAG.getConstant(FuncInfo->getVarArgsFirstFPR(), PtrVT), + DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), PtrVT), + DAG.getFrameIndex(FuncInfo->getRegSaveFrameIndex(), PtrVT) + }; + + // Store each field into its respective slot. + SDValue MemOps[NumFields]; + unsigned Offset = 0; + for (unsigned I = 0; I < NumFields; ++I) { + SDValue FieldAddr = Addr; + if (Offset != 0) + FieldAddr = DAG.getNode(ISD::ADD, DL, PtrVT, FieldAddr, + DAG.getIntPtrConstant(Offset)); + MemOps[I] = DAG.getStore(Chain, DL, Fields[I], FieldAddr, + MachinePointerInfo(SV, Offset), + false, false, 0); + Offset += 8; + } + return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOps, NumFields); +} + +SDValue SystemZTargetLowering::lowerVACOPY(SDValue Op, + SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + SDValue DstPtr = Op.getOperand(1); + SDValue SrcPtr = Op.getOperand(2); + const Value *DstSV = cast<SrcValueSDNode>(Op.getOperand(3))->getValue(); + const Value *SrcSV = cast<SrcValueSDNode>(Op.getOperand(4))->getValue(); + DebugLoc DL = Op.getDebugLoc(); + + return DAG.getMemcpy(Chain, DL, DstPtr, SrcPtr, DAG.getIntPtrConstant(32), + /*Align*/8, /*isVolatile*/false, /*AlwaysInline*/false, + MachinePointerInfo(DstSV), MachinePointerInfo(SrcSV)); +} + +SDValue SystemZTargetLowering:: +lowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + SDValue Size = Op.getOperand(1); + DebugLoc DL = Op.getDebugLoc(); + + unsigned SPReg = getStackPointerRegisterToSaveRestore(); + + // Get a reference to the stack pointer. + SDValue OldSP = DAG.getCopyFromReg(Chain, DL, SPReg, MVT::i64); + + // Get the new stack pointer value. + SDValue NewSP = DAG.getNode(ISD::SUB, DL, MVT::i64, OldSP, Size); + + // Copy the new stack pointer back. + Chain = DAG.getCopyToReg(Chain, DL, SPReg, NewSP); + + // The allocated data lives above the 160 bytes allocated for the standard + // frame, plus any outgoing stack arguments. We don't know how much that + // amounts to yet, so emit a special ADJDYNALLOC placeholder. + SDValue ArgAdjust = DAG.getNode(SystemZISD::ADJDYNALLOC, DL, MVT::i64); + SDValue Result = DAG.getNode(ISD::ADD, DL, MVT::i64, NewSP, ArgAdjust); + + SDValue Ops[2] = { Result, Chain }; + return DAG.getMergeValues(Ops, 2, DL); +} + +SDValue SystemZTargetLowering::lowerUMUL_LOHI(SDValue Op, + SelectionDAG &DAG) const { + EVT VT = Op.getValueType(); + DebugLoc DL = Op.getDebugLoc(); + assert(!is32Bit(VT) && "Only support 64-bit UMUL_LOHI"); + + // UMUL_LOHI64 returns the low result in the odd register and the high + // result in the even register. UMUL_LOHI is defined to return the + // low half first, so the results are in reverse order. + SDValue Ops[2]; + lowerGR128Binary(DAG, DL, VT, SystemZ::AEXT128_64, SystemZISD::UMUL_LOHI64, + Op.getOperand(0), Op.getOperand(1), Ops[1], Ops[0]); + return DAG.getMergeValues(Ops, 2, DL); +} + +SDValue SystemZTargetLowering::lowerSDIVREM(SDValue Op, + SelectionDAG &DAG) const { + SDValue Op0 = Op.getOperand(0); + SDValue Op1 = Op.getOperand(1); + EVT VT = Op.getValueType(); + DebugLoc DL = Op.getDebugLoc(); + + // We use DSGF for 32-bit division. + if (is32Bit(VT)) { + Op0 = DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, Op0); + Op1 = DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, Op1); + } + + // DSG(F) takes a 64-bit dividend, so the even register in the GR128 + // input is "don't care". The instruction returns the remainder in + // the even register and the quotient in the odd register. + SDValue Ops[2]; + lowerGR128Binary(DAG, DL, VT, SystemZ::AEXT128_64, SystemZISD::SDIVREM64, + Op0, Op1, Ops[1], Ops[0]); + return DAG.getMergeValues(Ops, 2, DL); +} + +SDValue SystemZTargetLowering::lowerUDIVREM(SDValue Op, + SelectionDAG &DAG) const { + EVT VT = Op.getValueType(); + DebugLoc DL = Op.getDebugLoc(); + + // DL(G) uses a double-width dividend, so we need to clear the even + // register in the GR128 input. The instruction returns the remainder + // in the even register and the quotient in the odd register. + SDValue Ops[2]; + if (is32Bit(VT)) + lowerGR128Binary(DAG, DL, VT, SystemZ::ZEXT128_32, SystemZISD::UDIVREM32, + Op.getOperand(0), Op.getOperand(1), Ops[1], Ops[0]); + else + lowerGR128Binary(DAG, DL, VT, SystemZ::ZEXT128_64, SystemZISD::UDIVREM64, + Op.getOperand(0), Op.getOperand(1), Ops[1], Ops[0]); + return DAG.getMergeValues(Ops, 2, DL); +} + +SDValue SystemZTargetLowering::lowerOR(SDValue Op, SelectionDAG &DAG) const { + assert(Op.getValueType() == MVT::i64 && "Should be 64-bit operation"); + + // Get the known-zero masks for each operand. + SDValue Ops[] = { Op.getOperand(0), Op.getOperand(1) }; + APInt KnownZero[2], KnownOne[2]; + DAG.ComputeMaskedBits(Ops[0], KnownZero[0], KnownOne[0]); + DAG.ComputeMaskedBits(Ops[1], KnownZero[1], KnownOne[1]); + + // See if the upper 32 bits of one operand and the lower 32 bits of the + // other are known zero. They are the low and high operands respectively. + uint64_t Masks[] = { KnownZero[0].getZExtValue(), + KnownZero[1].getZExtValue() }; + unsigned High, Low; + if ((Masks[0] >> 32) == 0xffffffff && uint32_t(Masks[1]) == 0xffffffff) + High = 1, Low = 0; + else if ((Masks[1] >> 32) == 0xffffffff && uint32_t(Masks[0]) == 0xffffffff) + High = 0, Low = 1; + else + return Op; + + SDValue LowOp = Ops[Low]; + SDValue HighOp = Ops[High]; + + // If the high part is a constant, we're better off using IILH. + if (HighOp.getOpcode() == ISD::Constant) + return Op; + + // If the low part is a constant that is outside the range of LHI, + // then we're better off using IILF. + if (LowOp.getOpcode() == ISD::Constant) { + int64_t Value = int32_t(cast<ConstantSDNode>(LowOp)->getZExtValue()); + if (!isInt<16>(Value)) + return Op; + } + + // Check whether the high part is an AND that doesn't change the + // high 32 bits and just masks out low bits. We can skip it if so. + if (HighOp.getOpcode() == ISD::AND && + HighOp.getOperand(1).getOpcode() == ISD::Constant) { + ConstantSDNode *MaskNode = cast<ConstantSDNode>(HighOp.getOperand(1)); + uint64_t Mask = MaskNode->getZExtValue() | Masks[High]; + if ((Mask >> 32) == 0xffffffff) + HighOp = HighOp.getOperand(0); + } + + // Take advantage of the fact that all GR32 operations only change the + // low 32 bits by truncating Low to an i32 and inserting it directly + // using a subreg. The interesting cases are those where the truncation + // can be folded. + DebugLoc DL = Op.getDebugLoc(); + SDValue Low32 = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, LowOp); + SDValue SubReg32 = DAG.getTargetConstant(SystemZ::subreg_32bit, MVT::i64); + SDNode *Result = DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, DL, + MVT::i64, HighOp, Low32, SubReg32); + return SDValue(Result, 0); +} + +// Op is an 8-, 16-bit or 32-bit ATOMIC_LOAD_* operation. Lower the first +// two into the fullword ATOMIC_LOADW_* operation given by Opcode. +SDValue SystemZTargetLowering::lowerATOMIC_LOAD(SDValue Op, + SelectionDAG &DAG, + unsigned Opcode) const { + AtomicSDNode *Node = cast<AtomicSDNode>(Op.getNode()); + + // 32-bit operations need no code outside the main loop. + EVT NarrowVT = Node->getMemoryVT(); + EVT WideVT = MVT::i32; + if (NarrowVT == WideVT) + return Op; + + int64_t BitSize = NarrowVT.getSizeInBits(); + SDValue ChainIn = Node->getChain(); + SDValue Addr = Node->getBasePtr(); + SDValue Src2 = Node->getVal(); + MachineMemOperand *MMO = Node->getMemOperand(); + DebugLoc DL = Node->getDebugLoc(); + EVT PtrVT = Addr.getValueType(); + + // Convert atomic subtracts of constants into additions. + if (Opcode == SystemZISD::ATOMIC_LOADW_SUB) + if (ConstantSDNode *Const = dyn_cast<ConstantSDNode>(Src2)) { + Opcode = SystemZISD::ATOMIC_LOADW_ADD; + Src2 = DAG.getConstant(-Const->getSExtValue(), Src2.getValueType()); + } + + // Get the address of the containing word. + SDValue AlignedAddr = DAG.getNode(ISD::AND, DL, PtrVT, Addr, + DAG.getConstant(-4, PtrVT)); + + // Get the number of bits that the word must be rotated left in order + // to bring the field to the top bits of a GR32. + SDValue BitShift = DAG.getNode(ISD::SHL, DL, PtrVT, Addr, + DAG.getConstant(3, PtrVT)); + BitShift = DAG.getNode(ISD::TRUNCATE, DL, WideVT, BitShift); + + // Get the complementing shift amount, for rotating a field in the top + // bits back to its proper position. + SDValue NegBitShift = DAG.getNode(ISD::SUB, DL, WideVT, + DAG.getConstant(0, WideVT), BitShift); + + // Extend the source operand to 32 bits and prepare it for the inner loop. + // ATOMIC_SWAPW uses RISBG to rotate the field left, but all other + // operations require the source to be shifted in advance. (This shift + // can be folded if the source is constant.) For AND and NAND, the lower + // bits must be set, while for other opcodes they should be left clear. + if (Opcode != SystemZISD::ATOMIC_SWAPW) + Src2 = DAG.getNode(ISD::SHL, DL, WideVT, Src2, + DAG.getConstant(32 - BitSize, WideVT)); + if (Opcode == SystemZISD::ATOMIC_LOADW_AND || + Opcode == SystemZISD::ATOMIC_LOADW_NAND) + Src2 = DAG.getNode(ISD::OR, DL, WideVT, Src2, + DAG.getConstant(uint32_t(-1) >> BitSize, WideVT)); + + // Construct the ATOMIC_LOADW_* node. + SDVTList VTList = DAG.getVTList(WideVT, MVT::Other); + SDValue Ops[] = { ChainIn, AlignedAddr, Src2, BitShift, NegBitShift, + DAG.getConstant(BitSize, WideVT) }; + SDValue AtomicOp = DAG.getMemIntrinsicNode(Opcode, DL, VTList, Ops, + array_lengthof(Ops), + NarrowVT, MMO); + + // Rotate the result of the final CS so that the field is in the lower + // bits of a GR32, then truncate it. + SDValue ResultShift = DAG.getNode(ISD::ADD, DL, WideVT, BitShift, + DAG.getConstant(BitSize, WideVT)); + SDValue Result = DAG.getNode(ISD::ROTL, DL, WideVT, AtomicOp, ResultShift); + + SDValue RetOps[2] = { Result, AtomicOp.getValue(1) }; + return DAG.getMergeValues(RetOps, 2, DL); +} + +// Node is an 8- or 16-bit ATOMIC_CMP_SWAP operation. Lower the first two +// into a fullword ATOMIC_CMP_SWAPW operation. +SDValue SystemZTargetLowering::lowerATOMIC_CMP_SWAP(SDValue Op, + SelectionDAG &DAG) const { + AtomicSDNode *Node = cast<AtomicSDNode>(Op.getNode()); + + // We have native support for 32-bit compare and swap. + EVT NarrowVT = Node->getMemoryVT(); + EVT WideVT = MVT::i32; + if (NarrowVT == WideVT) + return Op; + + int64_t BitSize = NarrowVT.getSizeInBits(); + SDValue ChainIn = Node->getOperand(0); + SDValue Addr = Node->getOperand(1); + SDValue CmpVal = Node->getOperand(2); + SDValue SwapVal = Node->getOperand(3); + MachineMemOperand *MMO = Node->getMemOperand(); + DebugLoc DL = Node->getDebugLoc(); + EVT PtrVT = Addr.getValueType(); + + // Get the address of the containing word. + SDValue AlignedAddr = DAG.getNode(ISD::AND, DL, PtrVT, Addr, + DAG.getConstant(-4, PtrVT)); + + // Get the number of bits that the word must be rotated left in order + // to bring the field to the top bits of a GR32. + SDValue BitShift = DAG.getNode(ISD::SHL, DL, PtrVT, Addr, + DAG.getConstant(3, PtrVT)); + BitShift = DAG.getNode(ISD::TRUNCATE, DL, WideVT, BitShift); + + // Get the complementing shift amount, for rotating a field in the top + // bits back to its proper position. + SDValue NegBitShift = DAG.getNode(ISD::SUB, DL, WideVT, + DAG.getConstant(0, WideVT), BitShift); + + // Construct the ATOMIC_CMP_SWAPW node. + SDVTList VTList = DAG.getVTList(WideVT, MVT::Other); + SDValue Ops[] = { ChainIn, AlignedAddr, CmpVal, SwapVal, BitShift, + NegBitShift, DAG.getConstant(BitSize, WideVT) }; + SDValue AtomicOp = DAG.getMemIntrinsicNode(SystemZISD::ATOMIC_CMP_SWAPW, DL, + VTList, Ops, array_lengthof(Ops), + NarrowVT, MMO); + return AtomicOp; +} + +SDValue SystemZTargetLowering::lowerSTACKSAVE(SDValue Op, + SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + MF.getInfo<SystemZMachineFunctionInfo>()->setManipulatesSP(true); + return DAG.getCopyFromReg(Op.getOperand(0), Op.getDebugLoc(), + SystemZ::R15D, Op.getValueType()); +} + +SDValue SystemZTargetLowering::lowerSTACKRESTORE(SDValue Op, + SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + MF.getInfo<SystemZMachineFunctionInfo>()->setManipulatesSP(true); + return DAG.getCopyToReg(Op.getOperand(0), Op.getDebugLoc(), + SystemZ::R15D, Op.getOperand(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(cast<GlobalAddressSDNode>(Op), DAG); + case ISD::GlobalTLSAddress: + return lowerGlobalTLSAddress(cast<GlobalAddressSDNode>(Op), DAG); + case ISD::BlockAddress: + return lowerBlockAddress(cast<BlockAddressSDNode>(Op), DAG); + case ISD::JumpTable: + return lowerJumpTable(cast<JumpTableSDNode>(Op), DAG); + case ISD::ConstantPool: + return lowerConstantPool(cast<ConstantPoolSDNode>(Op), DAG); + case ISD::BITCAST: + return lowerBITCAST(Op, DAG); + case ISD::VASTART: + return lowerVASTART(Op, DAG); + case ISD::VACOPY: + return lowerVACOPY(Op, DAG); + case ISD::DYNAMIC_STACKALLOC: + return lowerDYNAMIC_STACKALLOC(Op, DAG); + case ISD::UMUL_LOHI: + return lowerUMUL_LOHI(Op, DAG); + case ISD::SDIVREM: + return lowerSDIVREM(Op, DAG); + case ISD::UDIVREM: + return lowerUDIVREM(Op, DAG); + case ISD::OR: + return lowerOR(Op, DAG); + case ISD::ATOMIC_SWAP: + return lowerATOMIC_LOAD(Op, DAG, SystemZISD::ATOMIC_SWAPW); + case ISD::ATOMIC_LOAD_ADD: + return lowerATOMIC_LOAD(Op, DAG, SystemZISD::ATOMIC_LOADW_ADD); + case ISD::ATOMIC_LOAD_SUB: + return lowerATOMIC_LOAD(Op, DAG, SystemZISD::ATOMIC_LOADW_SUB); + case ISD::ATOMIC_LOAD_AND: + return lowerATOMIC_LOAD(Op, DAG, SystemZISD::ATOMIC_LOADW_AND); + case ISD::ATOMIC_LOAD_OR: + return lowerATOMIC_LOAD(Op, DAG, SystemZISD::ATOMIC_LOADW_OR); + case ISD::ATOMIC_LOAD_XOR: + return lowerATOMIC_LOAD(Op, DAG, SystemZISD::ATOMIC_LOADW_XOR); + case ISD::ATOMIC_LOAD_NAND: + return lowerATOMIC_LOAD(Op, DAG, SystemZISD::ATOMIC_LOADW_NAND); + case ISD::ATOMIC_LOAD_MIN: + return lowerATOMIC_LOAD(Op, DAG, SystemZISD::ATOMIC_LOADW_MIN); + case ISD::ATOMIC_LOAD_MAX: + return lowerATOMIC_LOAD(Op, DAG, SystemZISD::ATOMIC_LOADW_MAX); + case ISD::ATOMIC_LOAD_UMIN: + return lowerATOMIC_LOAD(Op, DAG, SystemZISD::ATOMIC_LOADW_UMIN); + case ISD::ATOMIC_LOAD_UMAX: + return lowerATOMIC_LOAD(Op, DAG, SystemZISD::ATOMIC_LOADW_UMAX); + case ISD::ATOMIC_CMP_SWAP: + return lowerATOMIC_CMP_SWAP(Op, DAG); + case ISD::STACKSAVE: + return lowerSTACKSAVE(Op, DAG); + case ISD::STACKRESTORE: + return lowerSTACKRESTORE(Op, DAG); + default: + llvm_unreachable("Unexpected node to lower"); + } +} + +const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const { +#define OPCODE(NAME) case SystemZISD::NAME: return "SystemZISD::" #NAME + switch (Opcode) { + OPCODE(RET_FLAG); + OPCODE(CALL); + OPCODE(PCREL_WRAPPER); + OPCODE(CMP); + OPCODE(UCMP); + OPCODE(BR_CCMASK); + OPCODE(SELECT_CCMASK); + OPCODE(ADJDYNALLOC); + OPCODE(EXTRACT_ACCESS); + OPCODE(UMUL_LOHI64); + OPCODE(SDIVREM64); + OPCODE(UDIVREM32); + OPCODE(UDIVREM64); + OPCODE(ATOMIC_SWAPW); + OPCODE(ATOMIC_LOADW_ADD); + OPCODE(ATOMIC_LOADW_SUB); + OPCODE(ATOMIC_LOADW_AND); + OPCODE(ATOMIC_LOADW_OR); + OPCODE(ATOMIC_LOADW_XOR); + OPCODE(ATOMIC_LOADW_NAND); + OPCODE(ATOMIC_LOADW_MIN); + OPCODE(ATOMIC_LOADW_MAX); + OPCODE(ATOMIC_LOADW_UMIN); + OPCODE(ATOMIC_LOADW_UMAX); + OPCODE(ATOMIC_CMP_SWAPW); + } + return NULL; +#undef OPCODE +} + +//===----------------------------------------------------------------------===// +// Custom insertion +//===----------------------------------------------------------------------===// + +// Create a new basic block after MBB. +static MachineBasicBlock *emitBlockAfter(MachineBasicBlock *MBB) { + MachineFunction &MF = *MBB->getParent(); + MachineBasicBlock *NewMBB = MF.CreateMachineBasicBlock(MBB->getBasicBlock()); + MF.insert(llvm::next(MachineFunction::iterator(MBB)), NewMBB); + return NewMBB; +} + +// Split MBB after MI and return the new block (the one that contains +// instructions after MI). +static MachineBasicBlock *splitBlockAfter(MachineInstr *MI, + MachineBasicBlock *MBB) { + MachineBasicBlock *NewMBB = emitBlockAfter(MBB); + NewMBB->splice(NewMBB->begin(), MBB, + llvm::next(MachineBasicBlock::iterator(MI)), + MBB->end()); + NewMBB->transferSuccessorsAndUpdatePHIs(MBB); + return NewMBB; +} + +// Implement EmitInstrWithCustomInserter for pseudo Select* instruction MI. +MachineBasicBlock * +SystemZTargetLowering::emitSelect(MachineInstr *MI, + MachineBasicBlock *MBB) const { + const SystemZInstrInfo *TII = TM.getInstrInfo(); + + unsigned DestReg = MI->getOperand(0).getReg(); + unsigned TrueReg = MI->getOperand(1).getReg(); + unsigned FalseReg = MI->getOperand(2).getReg(); + unsigned CCMask = MI->getOperand(3).getImm(); + DebugLoc DL = MI->getDebugLoc(); + + MachineBasicBlock *StartMBB = MBB; + MachineBasicBlock *JoinMBB = splitBlockAfter(MI, MBB); + MachineBasicBlock *FalseMBB = emitBlockAfter(StartMBB); + + // StartMBB: + // ... + // TrueVal = ... + // cmpTY ccX, r1, r2 + // jCC JoinMBB + // # fallthrough to FalseMBB + MBB = StartMBB; + BuildMI(MBB, DL, TII->get(SystemZ::BRCL)).addImm(CCMask).addMBB(JoinMBB); + MBB->addSuccessor(JoinMBB); + MBB->addSuccessor(FalseMBB); + + // FalseMBB: + // # fallthrough to JoinMBB + MBB = FalseMBB; + MBB->addSuccessor(JoinMBB); + + // JoinMBB: + // %Result = phi [ %FalseReg, FalseMBB ], [ %TrueReg, StartMBB ] + // ... + MBB = JoinMBB; + BuildMI(*MBB, MBB->begin(), DL, TII->get(SystemZ::PHI), DestReg) + .addReg(TrueReg).addMBB(StartMBB) + .addReg(FalseReg).addMBB(FalseMBB); + + MI->eraseFromParent(); + return JoinMBB; +} + +// Implement EmitInstrWithCustomInserter for pseudo ATOMIC_LOAD{,W}_* +// or ATOMIC_SWAP{,W} instruction MI. BinOpcode is the instruction that +// performs the binary operation elided by "*", or 0 for ATOMIC_SWAP{,W}. +// BitSize is the width of the field in bits, or 0 if this is a partword +// ATOMIC_LOADW_* or ATOMIC_SWAPW instruction, in which case the bitsize +// is one of the operands. Invert says whether the field should be +// inverted after performing BinOpcode (e.g. for NAND). +MachineBasicBlock * +SystemZTargetLowering::emitAtomicLoadBinary(MachineInstr *MI, + MachineBasicBlock *MBB, + unsigned BinOpcode, + unsigned BitSize, + bool Invert) const { + const SystemZInstrInfo *TII = TM.getInstrInfo(); + MachineFunction &MF = *MBB->getParent(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + unsigned MaskNE = CCMaskForCondCode(ISD::SETNE); + bool IsSubWord = (BitSize < 32); + + // Extract the operands. Base can be a register or a frame index. + // Src2 can be a register or immediate. + unsigned Dest = MI->getOperand(0).getReg(); + MachineOperand Base = earlyUseOperand(MI->getOperand(1)); + int64_t Disp = MI->getOperand(2).getImm(); + MachineOperand Src2 = earlyUseOperand(MI->getOperand(3)); + unsigned BitShift = (IsSubWord ? MI->getOperand(4).getReg() : 0); + unsigned NegBitShift = (IsSubWord ? MI->getOperand(5).getReg() : 0); + DebugLoc DL = MI->getDebugLoc(); + if (IsSubWord) + BitSize = MI->getOperand(6).getImm(); + + // Subword operations use 32-bit registers. + const TargetRegisterClass *RC = (BitSize <= 32 ? + &SystemZ::GR32BitRegClass : + &SystemZ::GR64BitRegClass); + unsigned LOpcode = BitSize <= 32 ? SystemZ::L : SystemZ::LG; + unsigned CSOpcode = BitSize <= 32 ? SystemZ::CS : SystemZ::CSG; + + // Get the right opcodes for the displacement. + LOpcode = TII->getOpcodeForOffset(LOpcode, Disp); + CSOpcode = TII->getOpcodeForOffset(CSOpcode, Disp); + assert(LOpcode && CSOpcode && "Displacement out of range"); + + // Create virtual registers for temporary results. + unsigned OrigVal = MRI.createVirtualRegister(RC); + unsigned OldVal = MRI.createVirtualRegister(RC); + unsigned NewVal = (BinOpcode || IsSubWord ? + MRI.createVirtualRegister(RC) : Src2.getReg()); + unsigned RotatedOldVal = (IsSubWord ? MRI.createVirtualRegister(RC) : OldVal); + unsigned RotatedNewVal = (IsSubWord ? MRI.createVirtualRegister(RC) : NewVal); + + // Insert a basic block for the main loop. + MachineBasicBlock *StartMBB = MBB; + MachineBasicBlock *DoneMBB = splitBlockAfter(MI, MBB); + MachineBasicBlock *LoopMBB = emitBlockAfter(StartMBB); + + // StartMBB: + // ... + // %OrigVal = L Disp(%Base) + // # fall through to LoopMMB + MBB = StartMBB; + BuildMI(MBB, DL, TII->get(LOpcode), OrigVal) + .addOperand(Base).addImm(Disp).addReg(0); + MBB->addSuccessor(LoopMBB); + + // LoopMBB: + // %OldVal = phi [ %OrigVal, StartMBB ], [ %Dest, LoopMBB ] + // %RotatedOldVal = RLL %OldVal, 0(%BitShift) + // %RotatedNewVal = OP %RotatedOldVal, %Src2 + // %NewVal = RLL %RotatedNewVal, 0(%NegBitShift) + // %Dest = CS %OldVal, %NewVal, Disp(%Base) + // JNE LoopMBB + // # fall through to DoneMMB + MBB = LoopMBB; + BuildMI(MBB, DL, TII->get(SystemZ::PHI), OldVal) + .addReg(OrigVal).addMBB(StartMBB) + .addReg(Dest).addMBB(LoopMBB); + if (IsSubWord) + BuildMI(MBB, DL, TII->get(SystemZ::RLL), RotatedOldVal) + .addReg(OldVal).addReg(BitShift).addImm(0); + if (Invert) { + // Perform the operation normally and then invert every bit of the field. + unsigned Tmp = MRI.createVirtualRegister(RC); + BuildMI(MBB, DL, TII->get(BinOpcode), Tmp) + .addReg(RotatedOldVal).addOperand(Src2); + if (BitSize < 32) + // XILF with the upper BitSize bits set. + BuildMI(MBB, DL, TII->get(SystemZ::XILF32), RotatedNewVal) + .addReg(Tmp).addImm(uint32_t(~0 << (32 - BitSize))); + else if (BitSize == 32) + // XILF with every bit set. + BuildMI(MBB, DL, TII->get(SystemZ::XILF32), RotatedNewVal) + .addReg(Tmp).addImm(~uint32_t(0)); + else { + // Use LCGR and add -1 to the result, which is more compact than + // an XILF, XILH pair. + unsigned Tmp2 = MRI.createVirtualRegister(RC); + BuildMI(MBB, DL, TII->get(SystemZ::LCGR), Tmp2).addReg(Tmp); + BuildMI(MBB, DL, TII->get(SystemZ::AGHI), RotatedNewVal) + .addReg(Tmp2).addImm(-1); + } + } else if (BinOpcode) + // A simply binary operation. + BuildMI(MBB, DL, TII->get(BinOpcode), RotatedNewVal) + .addReg(RotatedOldVal).addOperand(Src2); + else if (IsSubWord) + // Use RISBG to rotate Src2 into position and use it to replace the + // field in RotatedOldVal. + BuildMI(MBB, DL, TII->get(SystemZ::RISBG32), RotatedNewVal) + .addReg(RotatedOldVal).addReg(Src2.getReg()) + .addImm(32).addImm(31 + BitSize).addImm(32 - BitSize); + if (IsSubWord) + BuildMI(MBB, DL, TII->get(SystemZ::RLL), NewVal) + .addReg(RotatedNewVal).addReg(NegBitShift).addImm(0); + BuildMI(MBB, DL, TII->get(CSOpcode), Dest) + .addReg(OldVal).addReg(NewVal).addOperand(Base).addImm(Disp); + BuildMI(MBB, DL, TII->get(SystemZ::BRCL)).addImm(MaskNE).addMBB(LoopMBB); + MBB->addSuccessor(LoopMBB); + MBB->addSuccessor(DoneMBB); + + MI->eraseFromParent(); + return DoneMBB; +} + +// Implement EmitInstrWithCustomInserter for pseudo +// ATOMIC_LOAD{,W}_{,U}{MIN,MAX} instruction MI. CompareOpcode is the +// instruction that should be used to compare the current field with the +// minimum or maximum value. KeepOldMask is the BRC condition-code mask +// for when the current field should be kept. BitSize is the width of +// the field in bits, or 0 if this is a partword ATOMIC_LOADW_* instruction. +MachineBasicBlock * +SystemZTargetLowering::emitAtomicLoadMinMax(MachineInstr *MI, + MachineBasicBlock *MBB, + unsigned CompareOpcode, + unsigned KeepOldMask, + unsigned BitSize) const { + const SystemZInstrInfo *TII = TM.getInstrInfo(); + MachineFunction &MF = *MBB->getParent(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + unsigned MaskNE = CCMaskForCondCode(ISD::SETNE); + bool IsSubWord = (BitSize < 32); + + // Extract the operands. Base can be a register or a frame index. + unsigned Dest = MI->getOperand(0).getReg(); + MachineOperand Base = earlyUseOperand(MI->getOperand(1)); + int64_t Disp = MI->getOperand(2).getImm(); + unsigned Src2 = MI->getOperand(3).getReg(); + unsigned BitShift = (IsSubWord ? MI->getOperand(4).getReg() : 0); + unsigned NegBitShift = (IsSubWord ? MI->getOperand(5).getReg() : 0); + DebugLoc DL = MI->getDebugLoc(); + if (IsSubWord) + BitSize = MI->getOperand(6).getImm(); + + // Subword operations use 32-bit registers. + const TargetRegisterClass *RC = (BitSize <= 32 ? + &SystemZ::GR32BitRegClass : + &SystemZ::GR64BitRegClass); + unsigned LOpcode = BitSize <= 32 ? SystemZ::L : SystemZ::LG; + unsigned CSOpcode = BitSize <= 32 ? SystemZ::CS : SystemZ::CSG; + + // Get the right opcodes for the displacement. + LOpcode = TII->getOpcodeForOffset(LOpcode, Disp); + CSOpcode = TII->getOpcodeForOffset(CSOpcode, Disp); + assert(LOpcode && CSOpcode && "Displacement out of range"); + + // Create virtual registers for temporary results. + unsigned OrigVal = MRI.createVirtualRegister(RC); + unsigned OldVal = MRI.createVirtualRegister(RC); + unsigned NewVal = MRI.createVirtualRegister(RC); + unsigned RotatedOldVal = (IsSubWord ? MRI.createVirtualRegister(RC) : OldVal); + unsigned RotatedAltVal = (IsSubWord ? MRI.createVirtualRegister(RC) : Src2); + unsigned RotatedNewVal = (IsSubWord ? MRI.createVirtualRegister(RC) : NewVal); + + // Insert 3 basic blocks for the loop. + MachineBasicBlock *StartMBB = MBB; + MachineBasicBlock *DoneMBB = splitBlockAfter(MI, MBB); + MachineBasicBlock *LoopMBB = emitBlockAfter(StartMBB); + MachineBasicBlock *UseAltMBB = emitBlockAfter(LoopMBB); + MachineBasicBlock *UpdateMBB = emitBlockAfter(UseAltMBB); + + // StartMBB: + // ... + // %OrigVal = L Disp(%Base) + // # fall through to LoopMMB + MBB = StartMBB; + BuildMI(MBB, DL, TII->get(LOpcode), OrigVal) + .addOperand(Base).addImm(Disp).addReg(0); + MBB->addSuccessor(LoopMBB); + + // LoopMBB: + // %OldVal = phi [ %OrigVal, StartMBB ], [ %Dest, UpdateMBB ] + // %RotatedOldVal = RLL %OldVal, 0(%BitShift) + // CompareOpcode %RotatedOldVal, %Src2 + // BRCL KeepOldMask, UpdateMBB + MBB = LoopMBB; + BuildMI(MBB, DL, TII->get(SystemZ::PHI), OldVal) + .addReg(OrigVal).addMBB(StartMBB) + .addReg(Dest).addMBB(UpdateMBB); + if (IsSubWord) + BuildMI(MBB, DL, TII->get(SystemZ::RLL), RotatedOldVal) + .addReg(OldVal).addReg(BitShift).addImm(0); + BuildMI(MBB, DL, TII->get(CompareOpcode)) + .addReg(RotatedOldVal).addReg(Src2); + BuildMI(MBB, DL, TII->get(SystemZ::BRCL)) + .addImm(KeepOldMask).addMBB(UpdateMBB); + MBB->addSuccessor(UpdateMBB); + MBB->addSuccessor(UseAltMBB); + + // UseAltMBB: + // %RotatedAltVal = RISBG %RotatedOldVal, %Src2, 32, 31 + BitSize, 0 + // # fall through to UpdateMMB + MBB = UseAltMBB; + if (IsSubWord) + BuildMI(MBB, DL, TII->get(SystemZ::RISBG32), RotatedAltVal) + .addReg(RotatedOldVal).addReg(Src2) + .addImm(32).addImm(31 + BitSize).addImm(0); + MBB->addSuccessor(UpdateMBB); + + // UpdateMBB: + // %RotatedNewVal = PHI [ %RotatedOldVal, LoopMBB ], + // [ %RotatedAltVal, UseAltMBB ] + // %NewVal = RLL %RotatedNewVal, 0(%NegBitShift) + // %Dest = CS %OldVal, %NewVal, Disp(%Base) + // JNE LoopMBB + // # fall through to DoneMMB + MBB = UpdateMBB; + BuildMI(MBB, DL, TII->get(SystemZ::PHI), RotatedNewVal) + .addReg(RotatedOldVal).addMBB(LoopMBB) + .addReg(RotatedAltVal).addMBB(UseAltMBB); + if (IsSubWord) + BuildMI(MBB, DL, TII->get(SystemZ::RLL), NewVal) + .addReg(RotatedNewVal).addReg(NegBitShift).addImm(0); + BuildMI(MBB, DL, TII->get(CSOpcode), Dest) + .addReg(OldVal).addReg(NewVal).addOperand(Base).addImm(Disp); + BuildMI(MBB, DL, TII->get(SystemZ::BRCL)).addImm(MaskNE).addMBB(LoopMBB); + MBB->addSuccessor(LoopMBB); + MBB->addSuccessor(DoneMBB); + + MI->eraseFromParent(); + return DoneMBB; +} + +// Implement EmitInstrWithCustomInserter for pseudo ATOMIC_CMP_SWAPW +// instruction MI. +MachineBasicBlock * +SystemZTargetLowering::emitAtomicCmpSwapW(MachineInstr *MI, + MachineBasicBlock *MBB) const { + const SystemZInstrInfo *TII = TM.getInstrInfo(); + MachineFunction &MF = *MBB->getParent(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + unsigned MaskNE = CCMaskForCondCode(ISD::SETNE); + + // Extract the operands. Base can be a register or a frame index. + unsigned Dest = MI->getOperand(0).getReg(); + MachineOperand Base = earlyUseOperand(MI->getOperand(1)); + int64_t Disp = MI->getOperand(2).getImm(); + unsigned OrigCmpVal = MI->getOperand(3).getReg(); + unsigned OrigSwapVal = MI->getOperand(4).getReg(); + unsigned BitShift = MI->getOperand(5).getReg(); + unsigned NegBitShift = MI->getOperand(6).getReg(); + int64_t BitSize = MI->getOperand(7).getImm(); + DebugLoc DL = MI->getDebugLoc(); + + const TargetRegisterClass *RC = &SystemZ::GR32BitRegClass; + + // Get the right opcodes for the displacement. + unsigned LOpcode = TII->getOpcodeForOffset(SystemZ::L, Disp); + unsigned CSOpcode = TII->getOpcodeForOffset(SystemZ::CS, Disp); + assert(LOpcode && CSOpcode && "Displacement out of range"); + + // Create virtual registers for temporary results. + unsigned OrigOldVal = MRI.createVirtualRegister(RC); + unsigned OldVal = MRI.createVirtualRegister(RC); + unsigned CmpVal = MRI.createVirtualRegister(RC); + unsigned SwapVal = MRI.createVirtualRegister(RC); + unsigned StoreVal = MRI.createVirtualRegister(RC); + unsigned RetryOldVal = MRI.createVirtualRegister(RC); + unsigned RetryCmpVal = MRI.createVirtualRegister(RC); + unsigned RetrySwapVal = MRI.createVirtualRegister(RC); + + // Insert 2 basic blocks for the loop. + MachineBasicBlock *StartMBB = MBB; + MachineBasicBlock *DoneMBB = splitBlockAfter(MI, MBB); + MachineBasicBlock *LoopMBB = emitBlockAfter(StartMBB); + MachineBasicBlock *SetMBB = emitBlockAfter(LoopMBB); + + // StartMBB: + // ... + // %OrigOldVal = L Disp(%Base) + // # fall through to LoopMMB + MBB = StartMBB; + BuildMI(MBB, DL, TII->get(LOpcode), OrigOldVal) + .addOperand(Base).addImm(Disp).addReg(0); + MBB->addSuccessor(LoopMBB); + + // LoopMBB: + // %OldVal = phi [ %OrigOldVal, EntryBB ], [ %RetryOldVal, SetMBB ] + // %CmpVal = phi [ %OrigCmpVal, EntryBB ], [ %RetryCmpVal, SetMBB ] + // %SwapVal = phi [ %OrigSwapVal, EntryBB ], [ %RetrySwapVal, SetMBB ] + // %Dest = RLL %OldVal, BitSize(%BitShift) + // ^^ The low BitSize bits contain the field + // of interest. + // %RetryCmpVal = RISBG32 %CmpVal, %Dest, 32, 63-BitSize, 0 + // ^^ Replace the upper 32-BitSize bits of the + // comparison value with those that we loaded, + // so that we can use a full word comparison. + // CR %Dest, %RetryCmpVal + // JNE DoneMBB + // # Fall through to SetMBB + MBB = LoopMBB; + BuildMI(MBB, DL, TII->get(SystemZ::PHI), OldVal) + .addReg(OrigOldVal).addMBB(StartMBB) + .addReg(RetryOldVal).addMBB(SetMBB); + BuildMI(MBB, DL, TII->get(SystemZ::PHI), CmpVal) + .addReg(OrigCmpVal).addMBB(StartMBB) + .addReg(RetryCmpVal).addMBB(SetMBB); + BuildMI(MBB, DL, TII->get(SystemZ::PHI), SwapVal) + .addReg(OrigSwapVal).addMBB(StartMBB) + .addReg(RetrySwapVal).addMBB(SetMBB); + BuildMI(MBB, DL, TII->get(SystemZ::RLL), Dest) + .addReg(OldVal).addReg(BitShift).addImm(BitSize); + BuildMI(MBB, DL, TII->get(SystemZ::RISBG32), RetryCmpVal) + .addReg(CmpVal).addReg(Dest).addImm(32).addImm(63 - BitSize).addImm(0); + BuildMI(MBB, DL, TII->get(SystemZ::CR)) + .addReg(Dest).addReg(RetryCmpVal); + BuildMI(MBB, DL, TII->get(SystemZ::BRCL)).addImm(MaskNE).addMBB(DoneMBB); + MBB->addSuccessor(DoneMBB); + MBB->addSuccessor(SetMBB); + + // SetMBB: + // %RetrySwapVal = RISBG32 %SwapVal, %Dest, 32, 63-BitSize, 0 + // ^^ Replace the upper 32-BitSize bits of the new + // value with those that we loaded. + // %StoreVal = RLL %RetrySwapVal, -BitSize(%NegBitShift) + // ^^ Rotate the new field to its proper position. + // %RetryOldVal = CS %Dest, %StoreVal, Disp(%Base) + // JNE LoopMBB + // # fall through to ExitMMB + MBB = SetMBB; + BuildMI(MBB, DL, TII->get(SystemZ::RISBG32), RetrySwapVal) + .addReg(SwapVal).addReg(Dest).addImm(32).addImm(63 - BitSize).addImm(0); + BuildMI(MBB, DL, TII->get(SystemZ::RLL), StoreVal) + .addReg(RetrySwapVal).addReg(NegBitShift).addImm(-BitSize); + BuildMI(MBB, DL, TII->get(CSOpcode), RetryOldVal) + .addReg(OldVal).addReg(StoreVal).addOperand(Base).addImm(Disp); + BuildMI(MBB, DL, TII->get(SystemZ::BRCL)).addImm(MaskNE).addMBB(LoopMBB); + MBB->addSuccessor(LoopMBB); + MBB->addSuccessor(DoneMBB); + + MI->eraseFromParent(); + return DoneMBB; +} + +// Emit an extension from a GR32 or GR64 to a GR128. ClearEven is true +// if the high register of the GR128 value must be cleared or false if +// it's "don't care". SubReg is subreg_odd32 when extending a GR32 +// and subreg_odd when extending a GR64. +MachineBasicBlock * +SystemZTargetLowering::emitExt128(MachineInstr *MI, + MachineBasicBlock *MBB, + bool ClearEven, unsigned SubReg) const { + const SystemZInstrInfo *TII = TM.getInstrInfo(); + MachineFunction &MF = *MBB->getParent(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + + unsigned Dest = MI->getOperand(0).getReg(); + unsigned Src = MI->getOperand(1).getReg(); + unsigned In128 = MRI.createVirtualRegister(&SystemZ::GR128BitRegClass); + + BuildMI(*MBB, MI, DL, TII->get(TargetOpcode::IMPLICIT_DEF), In128); + if (ClearEven) { + unsigned NewIn128 = MRI.createVirtualRegister(&SystemZ::GR128BitRegClass); + unsigned Zero64 = MRI.createVirtualRegister(&SystemZ::GR64BitRegClass); + + BuildMI(*MBB, MI, DL, TII->get(SystemZ::LLILL), Zero64) + .addImm(0); + BuildMI(*MBB, MI, DL, TII->get(TargetOpcode::INSERT_SUBREG), NewIn128) + .addReg(In128).addReg(Zero64).addImm(SystemZ::subreg_high); + In128 = NewIn128; + } + BuildMI(*MBB, MI, DL, TII->get(TargetOpcode::INSERT_SUBREG), Dest) + .addReg(In128).addReg(Src).addImm(SubReg); + + MI->eraseFromParent(); + return MBB; +} + +MachineBasicBlock *SystemZTargetLowering:: +EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const { + switch (MI->getOpcode()) { + case SystemZ::Select32: + case SystemZ::SelectF32: + case SystemZ::Select64: + case SystemZ::SelectF64: + case SystemZ::SelectF128: + return emitSelect(MI, MBB); + + case SystemZ::AEXT128_64: + return emitExt128(MI, MBB, false, SystemZ::subreg_low); + case SystemZ::ZEXT128_32: + return emitExt128(MI, MBB, true, SystemZ::subreg_low32); + case SystemZ::ZEXT128_64: + return emitExt128(MI, MBB, true, SystemZ::subreg_low); + + case SystemZ::ATOMIC_SWAPW: + return emitAtomicLoadBinary(MI, MBB, 0, 0); + case SystemZ::ATOMIC_SWAP_32: + return emitAtomicLoadBinary(MI, MBB, 0, 32); + case SystemZ::ATOMIC_SWAP_64: + return emitAtomicLoadBinary(MI, MBB, 0, 64); + + case SystemZ::ATOMIC_LOADW_AR: + return emitAtomicLoadBinary(MI, MBB, SystemZ::AR, 0); + case SystemZ::ATOMIC_LOADW_AFI: + return emitAtomicLoadBinary(MI, MBB, SystemZ::AFI, 0); + case SystemZ::ATOMIC_LOAD_AR: + return emitAtomicLoadBinary(MI, MBB, SystemZ::AR, 32); + case SystemZ::ATOMIC_LOAD_AHI: + return emitAtomicLoadBinary(MI, MBB, SystemZ::AHI, 32); + case SystemZ::ATOMIC_LOAD_AFI: + return emitAtomicLoadBinary(MI, MBB, SystemZ::AFI, 32); + case SystemZ::ATOMIC_LOAD_AGR: + return emitAtomicLoadBinary(MI, MBB, SystemZ::AGR, 64); + case SystemZ::ATOMIC_LOAD_AGHI: + return emitAtomicLoadBinary(MI, MBB, SystemZ::AGHI, 64); + case SystemZ::ATOMIC_LOAD_AGFI: + return emitAtomicLoadBinary(MI, MBB, SystemZ::AGFI, 64); + + case SystemZ::ATOMIC_LOADW_SR: + return emitAtomicLoadBinary(MI, MBB, SystemZ::SR, 0); + case SystemZ::ATOMIC_LOAD_SR: + return emitAtomicLoadBinary(MI, MBB, SystemZ::SR, 32); + case SystemZ::ATOMIC_LOAD_SGR: + return emitAtomicLoadBinary(MI, MBB, SystemZ::SGR, 64); + + case SystemZ::ATOMIC_LOADW_NR: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NR, 0); + case SystemZ::ATOMIC_LOADW_NILH: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NILH32, 0); + case SystemZ::ATOMIC_LOAD_NR: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NR, 32); + case SystemZ::ATOMIC_LOAD_NILL32: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NILL32, 32); + case SystemZ::ATOMIC_LOAD_NILH32: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NILH32, 32); + case SystemZ::ATOMIC_LOAD_NILF32: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NILF32, 32); + case SystemZ::ATOMIC_LOAD_NGR: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NGR, 64); + case SystemZ::ATOMIC_LOAD_NILL: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NILL, 64); + case SystemZ::ATOMIC_LOAD_NILH: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NILH, 64); + case SystemZ::ATOMIC_LOAD_NIHL: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHL, 64); + case SystemZ::ATOMIC_LOAD_NIHH: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHH, 64); + case SystemZ::ATOMIC_LOAD_NILF: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NILF, 64); + case SystemZ::ATOMIC_LOAD_NIHF: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHF, 64); + + case SystemZ::ATOMIC_LOADW_OR: + return emitAtomicLoadBinary(MI, MBB, SystemZ::OR, 0); + case SystemZ::ATOMIC_LOADW_OILH: + return emitAtomicLoadBinary(MI, MBB, SystemZ::OILH32, 0); + case SystemZ::ATOMIC_LOAD_OR: + return emitAtomicLoadBinary(MI, MBB, SystemZ::OR, 32); + case SystemZ::ATOMIC_LOAD_OILL32: + return emitAtomicLoadBinary(MI, MBB, SystemZ::OILL32, 32); + case SystemZ::ATOMIC_LOAD_OILH32: + return emitAtomicLoadBinary(MI, MBB, SystemZ::OILH32, 32); + case SystemZ::ATOMIC_LOAD_OILF32: + return emitAtomicLoadBinary(MI, MBB, SystemZ::OILF32, 32); + case SystemZ::ATOMIC_LOAD_OGR: + return emitAtomicLoadBinary(MI, MBB, SystemZ::OGR, 64); + case SystemZ::ATOMIC_LOAD_OILL: + return emitAtomicLoadBinary(MI, MBB, SystemZ::OILL, 64); + case SystemZ::ATOMIC_LOAD_OILH: + return emitAtomicLoadBinary(MI, MBB, SystemZ::OILH, 64); + case SystemZ::ATOMIC_LOAD_OIHL: + return emitAtomicLoadBinary(MI, MBB, SystemZ::OIHL, 64); + case SystemZ::ATOMIC_LOAD_OIHH: + return emitAtomicLoadBinary(MI, MBB, SystemZ::OIHH, 64); + case SystemZ::ATOMIC_LOAD_OILF: + return emitAtomicLoadBinary(MI, MBB, SystemZ::OILF, 64); + case SystemZ::ATOMIC_LOAD_OIHF: + return emitAtomicLoadBinary(MI, MBB, SystemZ::OIHF, 64); + + case SystemZ::ATOMIC_LOADW_XR: + return emitAtomicLoadBinary(MI, MBB, SystemZ::XR, 0); + case SystemZ::ATOMIC_LOADW_XILF: + return emitAtomicLoadBinary(MI, MBB, SystemZ::XILF32, 0); + case SystemZ::ATOMIC_LOAD_XR: + return emitAtomicLoadBinary(MI, MBB, SystemZ::XR, 32); + case SystemZ::ATOMIC_LOAD_XILF32: + return emitAtomicLoadBinary(MI, MBB, SystemZ::XILF32, 32); + case SystemZ::ATOMIC_LOAD_XGR: + return emitAtomicLoadBinary(MI, MBB, SystemZ::XGR, 64); + case SystemZ::ATOMIC_LOAD_XILF: + return emitAtomicLoadBinary(MI, MBB, SystemZ::XILF, 64); + case SystemZ::ATOMIC_LOAD_XIHF: + return emitAtomicLoadBinary(MI, MBB, SystemZ::XIHF, 64); + + case SystemZ::ATOMIC_LOADW_NRi: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NR, 0, true); + case SystemZ::ATOMIC_LOADW_NILHi: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NILH32, 0, true); + case SystemZ::ATOMIC_LOAD_NRi: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NR, 32, true); + case SystemZ::ATOMIC_LOAD_NILL32i: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NILL32, 32, true); + case SystemZ::ATOMIC_LOAD_NILH32i: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NILH32, 32, true); + case SystemZ::ATOMIC_LOAD_NILF32i: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NILF32, 32, true); + case SystemZ::ATOMIC_LOAD_NGRi: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NGR, 64, true); + case SystemZ::ATOMIC_LOAD_NILLi: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NILL, 64, true); + case SystemZ::ATOMIC_LOAD_NILHi: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NILH, 64, true); + case SystemZ::ATOMIC_LOAD_NIHLi: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHL, 64, true); + case SystemZ::ATOMIC_LOAD_NIHHi: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHH, 64, true); + case SystemZ::ATOMIC_LOAD_NILFi: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NILF, 64, true); + case SystemZ::ATOMIC_LOAD_NIHFi: + return emitAtomicLoadBinary(MI, MBB, SystemZ::NIHF, 64, true); + + case SystemZ::ATOMIC_LOADW_MIN: + return emitAtomicLoadMinMax(MI, MBB, SystemZ::CR, + SystemZ::CCMASK_CMP_LE, 0); + case SystemZ::ATOMIC_LOAD_MIN_32: + return emitAtomicLoadMinMax(MI, MBB, SystemZ::CR, + SystemZ::CCMASK_CMP_LE, 32); + case SystemZ::ATOMIC_LOAD_MIN_64: + return emitAtomicLoadMinMax(MI, MBB, SystemZ::CGR, + SystemZ::CCMASK_CMP_LE, 64); + + case SystemZ::ATOMIC_LOADW_MAX: + return emitAtomicLoadMinMax(MI, MBB, SystemZ::CR, + SystemZ::CCMASK_CMP_GE, 0); + case SystemZ::ATOMIC_LOAD_MAX_32: + return emitAtomicLoadMinMax(MI, MBB, SystemZ::CR, + SystemZ::CCMASK_CMP_GE, 32); + case SystemZ::ATOMIC_LOAD_MAX_64: + return emitAtomicLoadMinMax(MI, MBB, SystemZ::CGR, + SystemZ::CCMASK_CMP_GE, 64); + + case SystemZ::ATOMIC_LOADW_UMIN: + return emitAtomicLoadMinMax(MI, MBB, SystemZ::CLR, + SystemZ::CCMASK_CMP_LE, 0); + case SystemZ::ATOMIC_LOAD_UMIN_32: + return emitAtomicLoadMinMax(MI, MBB, SystemZ::CLR, + SystemZ::CCMASK_CMP_LE, 32); + case SystemZ::ATOMIC_LOAD_UMIN_64: + return emitAtomicLoadMinMax(MI, MBB, SystemZ::CLGR, + SystemZ::CCMASK_CMP_LE, 64); + + case SystemZ::ATOMIC_LOADW_UMAX: + return emitAtomicLoadMinMax(MI, MBB, SystemZ::CLR, + SystemZ::CCMASK_CMP_GE, 0); + case SystemZ::ATOMIC_LOAD_UMAX_32: + return emitAtomicLoadMinMax(MI, MBB, SystemZ::CLR, + SystemZ::CCMASK_CMP_GE, 32); + case SystemZ::ATOMIC_LOAD_UMAX_64: + return emitAtomicLoadMinMax(MI, MBB, SystemZ::CLGR, + SystemZ::CCMASK_CMP_GE, 64); + + case SystemZ::ATOMIC_CMP_SWAPW: + return emitAtomicCmpSwapW(MI, MBB); + default: + llvm_unreachable("Unexpected instr type to insert"); + } +} diff --git a/lib/Target/SystemZ/SystemZISelLowering.h b/lib/Target/SystemZ/SystemZISelLowering.h new file mode 100644 index 0000000000..eea820c8e5 --- /dev/null +++ b/lib/Target/SystemZ/SystemZISelLowering.h @@ -0,0 +1,212 @@ +//===-- 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 "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, + + // Calls a function. Operand 0 is the chain operand and operand 1 + // is the target address. The arguments start at operand 2. + // There is an optional glue operand at the end. + CALL, + + // Wraps a TargetGlobalAddress that should be loaded using PC-relative + // accesses (LARL). Operand 0 is the address. + PCREL_WRAPPER, + + // Signed integer and floating-point comparisons. The operands are the + // two values to compare. + CMP, + + // Likewise unsigned integer comparison. + UCMP, + + // Branches if a condition is true. Operand 0 is the chain operand; + // operand 1 is the 4-bit condition-code mask, with bit N in + // big-endian order meaning "branch if CC=N"; operand 2 is the + // target block and operand 3 is the flag operand. + BR_CCMASK, + + // Selects between operand 0 and operand 1. Operand 2 is the + // mask of condition-code values for which operand 0 should be + // chosen over operand 1; it has the same form as BR_CCMASK. + // Operand 3 is the flag operand. + SELECT_CCMASK, + + // Evaluates to the gap between the stack pointer and the + // base of the dynamically-allocatable area. + ADJDYNALLOC, + + // Extracts the value of a 32-bit access register. Operand 0 is + // the number of the register. + EXTRACT_ACCESS, + + // Wrappers around the ISD opcodes of the same name. The output and + // first input operands are GR128s. The trailing numbers are the + // widths of the second operand in bits. + UMUL_LOHI64, + SDIVREM64, + UDIVREM32, + UDIVREM64, + + // Wrappers around the inner loop of an 8- or 16-bit ATOMIC_SWAP or + // ATOMIC_LOAD_<op>. + // + // Operand 0: the address of the containing 32-bit-aligned field + // Operand 1: the second operand of <op>, in the high bits of an i32 + // for everything except ATOMIC_SWAPW + // Operand 2: how many bits to rotate the i32 left to bring the first + // operand into the high bits + // Operand 3: the negative of operand 2, for rotating the other way + // Operand 4: the width of the field in bits (8 or 16) + ATOMIC_SWAPW = ISD::FIRST_TARGET_MEMORY_OPCODE, + ATOMIC_LOADW_ADD, + ATOMIC_LOADW_SUB, + ATOMIC_LOADW_AND, + ATOMIC_LOADW_OR, + ATOMIC_LOADW_XOR, + ATOMIC_LOADW_NAND, + ATOMIC_LOADW_MIN, + ATOMIC_LOADW_MAX, + ATOMIC_LOADW_UMIN, + ATOMIC_LOADW_UMAX, + + // A wrapper around the inner loop of an ATOMIC_CMP_SWAP. + // + // Operand 0: the address of the containing 32-bit-aligned field + // Operand 1: the compare value, in the low bits of an i32 + // Operand 2: the swap value, in the low bits of an i32 + // Operand 3: how many bits to rotate the i32 left to bring the first + // operand into the high bits + // Operand 4: the negative of operand 2, for rotating the other way + // Operand 5: the width of the field in bits (8 or 16) + ATOMIC_CMP_SWAPW + }; +} + +class SystemZSubtarget; +class SystemZTargetMachine; + +class SystemZTargetLowering : public TargetLowering { +public: + explicit SystemZTargetLowering(SystemZTargetMachine &TM); + + // Override TargetLowering. + virtual MVT getScalarShiftAmountTy(EVT LHSTy) const LLVM_OVERRIDE { + return MVT::i32; + } + virtual EVT getSetCCResultType(EVT VT) const { + return MVT::i32; + } + virtual bool isFMAFasterThanMulAndAdd(EVT) const LLVM_OVERRIDE { + return true; + } + virtual bool isFPImmLegal(const APFloat &Imm, EVT VT) const; + virtual const char *getTargetNodeName(unsigned Opcode) const LLVM_OVERRIDE; + virtual std::pair<unsigned, const TargetRegisterClass *> + getRegForInlineAsmConstraint(const std::string &Constraint, + EVT VT) const LLVM_OVERRIDE; + virtual TargetLowering::ConstraintType + getConstraintType(const std::string &Constraint) const LLVM_OVERRIDE; + virtual TargetLowering::ConstraintWeight + getSingleConstraintMatchWeight(AsmOperandInfo &info, + const char *constraint) const LLVM_OVERRIDE; + virtual void + LowerAsmOperandForConstraint(SDValue Op, + std::string &Constraint, + std::vector<SDValue> &Ops, + SelectionDAG &DAG) const LLVM_OVERRIDE; + virtual MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const LLVM_OVERRIDE; + virtual SDValue LowerOperation(SDValue Op, + SelectionDAG &DAG) const LLVM_OVERRIDE; + virtual SDValue + LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc DL, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const LLVM_OVERRIDE; + virtual SDValue + LowerCall(CallLoweringInfo &CLI, + SmallVectorImpl<SDValue> &InVals) const LLVM_OVERRIDE; + + virtual SDValue + LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + DebugLoc DL, SelectionDAG &DAG) const LLVM_OVERRIDE; + +private: + const SystemZSubtarget &Subtarget; + const SystemZTargetMachine &TM; + + // Implement LowerOperation for individual opcodes. + SDValue lowerBR_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerGlobalAddress(GlobalAddressSDNode *Node, + SelectionDAG &DAG) const; + SDValue lowerGlobalTLSAddress(GlobalAddressSDNode *Node, + SelectionDAG &DAG) const; + SDValue lowerBlockAddress(BlockAddressSDNode *Node, + SelectionDAG &DAG) const; + SDValue lowerJumpTable(JumpTableSDNode *JT, SelectionDAG &DAG) const; + SDValue lowerConstantPool(ConstantPoolSDNode *CP, SelectionDAG &DAG) const; + SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerVACOPY(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerUMUL_LOHI(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSDIVREM(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerUDIVREM(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerBITCAST(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerOR(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerATOMIC_LOAD(SDValue Op, SelectionDAG &DAG, + unsigned Opcode) const; + SDValue lowerATOMIC_CMP_SWAP(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const; + + // Implement EmitInstrWithCustomInserter for individual operation types. + MachineBasicBlock *emitSelect(MachineInstr *MI, + MachineBasicBlock *BB) const; + MachineBasicBlock *emitExt128(MachineInstr *MI, + MachineBasicBlock *MBB, + bool ClearEven, unsigned SubReg) const; + MachineBasicBlock *emitAtomicLoadBinary(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned BinOpcode, unsigned BitSize, + bool Invert = false) const; + MachineBasicBlock *emitAtomicLoadMinMax(MachineInstr *MI, + MachineBasicBlock *MBB, + unsigned CompareOpcode, + unsigned KeepOldMask, + unsigned BitSize) const; + MachineBasicBlock *emitAtomicCmpSwapW(MachineInstr *MI, + MachineBasicBlock *BB) const; +}; +} // end namespace llvm + +#endif // LLVM_TARGET_SystemZ_ISELLOWERING_H diff --git a/lib/Target/SystemZ/SystemZInstrBuilder.h b/lib/Target/SystemZ/SystemZInstrBuilder.h new file mode 100644 index 0000000000..fb699b9ab8 --- /dev/null +++ b/lib/Target/SystemZ/SystemZInstrBuilder.h @@ -0,0 +1,48 @@ +//===-- 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. +// +//===----------------------------------------------------------------------===// + +#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 { + +/// Add a BDX memory reference for frame object FI to MIB. +static inline const MachineInstrBuilder & +addFrameReference(const MachineInstrBuilder &MIB, int FI) { + MachineInstr *MI = MIB; + MachineFunction &MF = *MI->getParent()->getParent(); + MachineFrameInfo *MFFrame = MF.getFrameInfo(); + const MCInstrDesc &MCID = MI->getDesc(); + unsigned Flags = 0; + if (MCID.mayLoad()) + Flags |= MachineMemOperand::MOLoad; + if (MCID.mayStore()) + Flags |= MachineMemOperand::MOStore; + int64_t Offset = 0; + MachineMemOperand *MMO = + MF.getMachineMemOperand(MachinePointerInfo( + PseudoSourceValue::getFixedStack(FI), Offset), + Flags, MFFrame->getObjectSize(FI), + MFFrame->getObjectAlignment(FI)); + return MIB.addFrameIndex(FI).addImm(Offset).addReg(0).addMemOperand(MMO); +} + +} // End llvm namespace + +#endif diff --git a/lib/Target/SystemZ/SystemZInstrFP.td b/lib/Target/SystemZ/SystemZInstrFP.td new file mode 100644 index 0000000000..7c9f0e668b --- /dev/null +++ b/lib/Target/SystemZ/SystemZInstrFP.td @@ -0,0 +1,318 @@ +//==- SystemZInstrFP.td - Floating-point SystemZ instructions --*- tblgen-*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Control-flow instructions +//===----------------------------------------------------------------------===// + +// C's ?: operator for floating-point operands. +def SelectF32 : SelectWrapper<FP32>; +def SelectF64 : SelectWrapper<FP64>; +def SelectF128 : SelectWrapper<FP128>; + +//===----------------------------------------------------------------------===// +// Move instructions +//===----------------------------------------------------------------------===// + +// Load zero. +let neverHasSideEffects = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in { + def LZER : InherentRRE<"lzer", 0xB374, FP32, (fpimm0)>; + def LZDR : InherentRRE<"lzdr", 0xB375, FP64, (fpimm0)>; + def LZXR : InherentRRE<"lzxr", 0xB376, FP128, (fpimm0)>; +} + +// Moves between two floating-point registers. +let neverHasSideEffects = 1 in { + def LER : UnaryRR <"ler", 0x38, null_frag, FP32, FP32>; + def LDR : UnaryRR <"ldr", 0x28, null_frag, FP64, FP64>; + def LXR : UnaryRRE<"lxr", 0xB365, null_frag, FP128, FP128>; +} + +// Moves between 64-bit integer and floating-point registers. +def LGDR : UnaryRRE<"lgdr", 0xB3CD, bitconvert, GR64, FP64>; +def LDGR : UnaryRRE<"ldgr", 0xB3C1, bitconvert, FP64, GR64>; + +// fcopysign with an FP32 result. +let isCodeGenOnly = 1 in { + def CPSDRss : BinaryRevRRF<"cpsdr", 0xB372, fcopysign, FP32, FP32>; + def CPSDRsd : BinaryRevRRF<"cpsdr", 0xB372, fcopysign, FP32, FP64>; +} + +// The sign of an FP128 is in the high register. Give the CPSDRsd +// operands in R1, R2, R3 order. +def : Pat<(fcopysign FP32:$src1, FP128:$src2), + (CPSDRsd (EXTRACT_SUBREG FP128:$src2, subreg_high), FP32:$src1)>; + +// fcopysign with an FP64 result. +let isCodeGenOnly = 1 in + def CPSDRds : BinaryRevRRF<"cpsdr", 0xB372, fcopysign, FP64, FP32>; +def CPSDRdd : BinaryRevRRF<"cpsdr", 0xB372, fcopysign, FP64, FP64>; + +// The sign of an FP128 is in the high register. Give the CPSDRdd +// operands in R1, R2, R3 order. +def : Pat<(fcopysign FP64:$src1, FP128:$src2), + (CPSDRdd (EXTRACT_SUBREG FP128:$src2, subreg_high), FP64:$src1)>; + +// fcopysign with an FP128 result. Use "upper" as the high half and leave +// the low half as-is. +class CopySign128<RegisterOperand cls, dag upper> + : Pat<(fcopysign FP128:$src1, cls:$src2), + (INSERT_SUBREG FP128:$src1, upper, subreg_high)>; + +// Give the CPSDR* operands in R1, R2, R3 order. +def : CopySign128<FP32, (CPSDRds FP32:$src2, + (EXTRACT_SUBREG FP128:$src1, subreg_high))>; +def : CopySign128<FP64, (CPSDRdd FP64:$src2, + (EXTRACT_SUBREG FP128:$src1, subreg_high))>; +def : CopySign128<FP128, (CPSDRdd (EXTRACT_SUBREG FP128:$src2, subreg_high), + (EXTRACT_SUBREG FP128:$src1, subreg_high))>; + +//===----------------------------------------------------------------------===// +// Load instructions +//===----------------------------------------------------------------------===// + +let canFoldAsLoad = 1, SimpleBDXLoad = 1 in { + defm LE : UnaryRXPair<"le", 0x78, 0xED64, load, FP32>; + defm LD : UnaryRXPair<"ld", 0x68, 0xED65, load, FP64>; + + // These instructions are split after register allocation, so we don't + // want a custom inserter. + let Has20BitOffset = 1, HasIndex = 1, Is128Bit = 1 in { + def LX : Pseudo<(outs FP128:$dst), (ins bdxaddr20only128:$src), + [(set FP128:$dst, (load bdxaddr20only128:$src))]>; + } +} + +//===----------------------------------------------------------------------===// +// Store instructions +//===----------------------------------------------------------------------===// + +let SimpleBDXStore = 1 in { + defm STE : StoreRXPair<"ste", 0x70, 0xED66, store, FP32>; + defm STD : StoreRXPair<"std", 0x60, 0xED67, store, FP64>; + + // These instructions are split after register allocation, so we don't + // want a custom inserter. + let Has20BitOffset = 1, HasIndex = 1, Is128Bit = 1 in { + def STX : Pseudo<(outs), (ins FP128:$src, bdxaddr20only128:$dst), + [(store FP128:$src, bdxaddr20only128:$dst)]>; + } +} + +//===----------------------------------------------------------------------===// +// Conversion instructions +//===----------------------------------------------------------------------===// + +// Convert floating-point values to narrower representations, rounding +// according to the current mode. The destination of LEXBR and LDXBR +// is a 128-bit value, but only the first register of the pair is used. +def LEDBR : UnaryRRE<"ledbr", 0xB344, fround, FP32, FP64>; +def LEXBR : UnaryRRE<"lexbr", 0xB346, null_frag, FP128, FP128>; +def LDXBR : UnaryRRE<"ldxbr", 0xB345, null_frag, FP128, FP128>; + +def : Pat<(f32 (fround FP128:$src)), + (EXTRACT_SUBREG (LEXBR FP128:$src), subreg_32bit)>; +def : Pat<(f64 (fround FP128:$src)), + (EXTRACT_SUBREG (LDXBR FP128:$src), subreg_high)>; + +// Extend register floating-point values to wider representations. +def LDEBR : UnaryRRE<"ldebr", 0xB304, fextend, FP64, FP32>; +def LXEBR : UnaryRRE<"lxebr", 0xB306, fextend, FP128, FP32>; +def LXDBR : UnaryRRE<"lxdbr", 0xB305, fextend, FP128, FP64>; + +// Extend memory floating-point values to wider representations. +def LDEB : UnaryRXE<"ldeb", 0xED04, extloadf32, FP64>; +def LXEB : UnaryRXE<"lxeb", 0xED06, extloadf32, FP128>; +def LXDB : UnaryRXE<"lxdb", 0xED05, extloadf64, FP128>; + +// Convert a signed integer register value to a floating-point one. +let Defs = [PSW] in { + def CEFBR : UnaryRRE<"cefbr", 0xB394, sint_to_fp, FP32, GR32>; + def CDFBR : UnaryRRE<"cdfbr", 0xB395, sint_to_fp, FP64, GR32>; + def CXFBR : UnaryRRE<"cxfbr", 0xB396, sint_to_fp, FP128, GR32>; + + def CEGBR : UnaryRRE<"cegbr", 0xB3A4, sint_to_fp, FP32, GR64>; + def CDGBR : UnaryRRE<"cdgbr", 0xB3A5, sint_to_fp, FP64, GR64>; + def CXGBR : UnaryRRE<"cxgbr", 0xB3A6, sint_to_fp, FP128, GR64>; +} + +// Convert a floating-point register value to a signed integer value, +// with the second operand (modifier M3) specifying the rounding mode. +let Defs = [PSW] in { + def CFEBR : UnaryRRF<"cfebr", 0xB398, GR32, FP32>; + def CFDBR : UnaryRRF<"cfdbr", 0xB399, GR32, FP64>; + def CFXBR : UnaryRRF<"cfxbr", 0xB39A, GR32, FP128>; + + def CGEBR : UnaryRRF<"cgebr", 0xB3A8, GR64, FP32>; + def CGDBR : UnaryRRF<"cgdbr", 0xB3A9, GR64, FP64>; + def CGXBR : UnaryRRF<"cgxbr", 0xB3AA, GR64, FP128>; +} + +// fp_to_sint always rounds towards zero, which is modifier value 5. +def : Pat<(i32 (fp_to_sint FP32:$src)), (CFEBR FP32:$src, 5)>; +def : Pat<(i32 (fp_to_sint FP64:$src)), (CFDBR FP64:$src, 5)>; +def : Pat<(i32 (fp_to_sint FP128:$src)), (CFXBR FP128:$src, 5)>; + +def : Pat<(i64 (fp_to_sint FP32:$src)), (CGEBR FP32:$src, 5)>; +def : Pat<(i64 (fp_to_sint FP64:$src)), (CGDBR FP64:$src, 5)>; +def : Pat<(i64 (fp_to_sint FP128:$src)), (CGXBR FP128:$src, 5)>; + +//===----------------------------------------------------------------------===// +// Unary arithmetic +//===----------------------------------------------------------------------===// + +// Negation (Load Complement). +let Defs = [PSW] in { + def LCEBR : UnaryRRE<"lcebr", 0xB303, fneg, FP32, FP32>; + def LCDBR : UnaryRRE<"lcdbr", 0xB313, fneg, FP64, FP64>; + def LCXBR : UnaryRRE<"lcxbr", 0xB343, fneg, FP128, FP128>; +} + +// Absolute value (Load Positive). +let Defs = [PSW] in { + def LPEBR : UnaryRRE<"lpebr", 0xB300, fabs, FP32, FP32>; + def LPDBR : UnaryRRE<"lpdbr", 0xB310, fabs, FP64, FP64>; + def LPXBR : UnaryRRE<"lpxbr", 0xB340, fabs, FP128, FP128>; +} + +// Negative absolute value (Load Negative). +let Defs = [PSW] in { + def LNEBR : UnaryRRE<"lnebr", 0xB301, fnabs, FP32, FP32>; + def LNDBR : UnaryRRE<"lndbr", 0xB311, fnabs, FP64, FP64>; + def LNXBR : UnaryRRE<"lnxbr", 0xB341, fnabs, FP128, FP128>; +} + +// Square root. +def SQEBR : UnaryRRE<"sqebr", 0xB314, fsqrt, FP32, FP32>; +def SQDBR : UnaryRRE<"sqdbr", 0xB315, fsqrt, FP64, FP64>; +def SQXBR : UnaryRRE<"sqxbr", 0xB316, fsqrt, FP128, FP128>; + +def SQEB : UnaryRXE<"sqeb", 0xED14, loadu<fsqrt>, FP32>; +def SQDB : UnaryRXE<"sqdb", 0xED15, loadu<fsqrt>, FP64>; + +// Round to an integer, with the second operand (modifier M3) specifying +// the rounding mode. +// +// These forms always check for inexact conditions. z196 added versions +// that allow this to suppressed (as for fnearbyint), but we don't yet +// support -march=z196. +let Defs = [PSW] in { + def FIEBR : UnaryRRF<"fiebr", 0xB357, FP32, FP32>; + def FIDBR : UnaryRRF<"fidbr", 0xB35F, FP64, FP64>; + def FIXBR : UnaryRRF<"fixbr", 0xB347, FP128, FP128>; +} + +// frint rounds according to the current mode (modifier 0) and detects +// inexact conditions. +def : Pat<(frint FP32:$src), (FIEBR FP32:$src, 0)>; +def : Pat<(frint FP64:$src), (FIDBR FP64:$src, 0)>; +def : Pat<(frint FP128:$src), (FIXBR FP128:$src, 0)>; + +//===----------------------------------------------------------------------===// +// Binary arithmetic +//===----------------------------------------------------------------------===// + +// Addition. +let Defs = [PSW] in { + let isCommutable = 1 in { + def AEBR : BinaryRRE<"aebr", 0xB30A, fadd, FP32, FP32>; + def ADBR : BinaryRRE<"adbr", 0xB31A, fadd, FP64, FP64>; + def AXBR : BinaryRRE<"axbr", 0xB34A, fadd, FP128, FP128>; + } + def AEB : BinaryRXE<"aeb", 0xED0A, fadd, FP32, load>; + def ADB : BinaryRXE<"adb", 0xED1A, fadd, FP64, load>; +} + +// Subtraction. +let Defs = [PSW] in { + def SEBR : BinaryRRE<"sebr", 0xB30B, fsub, FP32, FP32>; + def SDBR : BinaryRRE<"sdbr", 0xB31B, fsub, FP64, FP64>; + def SXBR : BinaryRRE<"sxbr", 0xB34B, fsub, FP128, FP128>; + + def SEB : BinaryRXE<"seb", 0xED0B, fsub, FP32, load>; + def SDB : BinaryRXE<"sdb", 0xED1B, fsub, FP64, load>; +} + +// Multiplication. +let isCommutable = 1 in { + def MEEBR : BinaryRRE<"meebr", 0xB317, fmul, FP32, FP32>; + def MDBR : BinaryRRE<"mdbr", 0xB31C, fmul, FP64, FP64>; + def MXBR : BinaryRRE<"mxbr", 0xB34C, fmul, FP128, FP128>; +} +def MEEB : BinaryRXE<"meeb", 0xED17, fmul, FP32, load>; +def MDB : BinaryRXE<"mdb", 0xED1C, fmul, FP64, load>; + +// f64 multiplication of two FP32 registers. +def MDEBR : BinaryRRE<"mdebr", 0xB30C, null_frag, FP64, FP32>; +def : Pat<(fmul (f64 (fextend FP32:$src1)), (f64 (fextend FP32:$src2))), + (MDEBR (INSERT_SUBREG (f64 (IMPLICIT_DEF)), + FP32:$src1, subreg_32bit), FP32:$src2)>; + +// f64 multiplication of an FP32 register and an f32 memory. +def MDEB : BinaryRXE<"mdeb", 0xED0C, null_frag, FP64, load>; +def : Pat<(fmul (f64 (fextend FP32:$src1)), + (f64 (extloadf32 bdxaddr12only:$addr))), + (MDEB (INSERT_SUBREG (f64 (IMPLICIT_DEF)), FP32:$src1, subreg_32bit), + bdxaddr12only:$addr)>; + +// f128 multiplication of two FP64 registers. +def MXDBR : BinaryRRE<"mxdbr", 0xB307, null_frag, FP128, FP64>; +def : Pat<(fmul (f128 (fextend FP64:$src1)), (f128 (fextend FP64:$src2))), + (MXDBR (INSERT_SUBREG (f128 (IMPLICIT_DEF)), + FP64:$src1, subreg_high), FP64:$src2)>; + +// f128 multiplication of an FP64 register and an f64 memory. +def MXDB : BinaryRXE<"mxdb", 0xED07, null_frag, FP128, load>; +def : Pat<(fmul (f128 (fextend FP64:$src1)), + (f128 (extloadf64 bdxaddr12only:$addr))), + (MXDB (INSERT_SUBREG (f128 (IMPLICIT_DEF)), FP64:$src1, subreg_high), + bdxaddr12only:$addr)>; + +// Fused multiply-add. +def MAEBR : TernaryRRD<"maebr", 0xB30E, z_fma, FP32>; +def MADBR : TernaryRRD<"madbr", 0xB31E, z_fma, FP64>; + +def MAEB : TernaryRXF<"maeb", 0xED0E, z_fma, FP32, load>; +def MADB : TernaryRXF<"madb", 0xED1E, z_fma, FP64, load>; + +// Fused multiply-subtract. +def MSEBR : TernaryRRD<"msebr", 0xB30F, z_fms, FP32>; +def MSDBR : TernaryRRD<"msdbr", 0xB31F, z_fms, FP64>; + +def MSEB : TernaryRXF<"mseb", 0xED0F, z_fms, FP32, load>; +def MSDB : TernaryRXF<"msdb", 0xED1F, z_fms, FP64, load>; + +// Division. +def DEBR : BinaryRRE<"debr", 0xB30D, fdiv, FP32, FP32>; +def DDBR : BinaryRRE<"ddbr", 0xB31D, fdiv, FP64, FP64>; +def DXBR : BinaryRRE<"dxbr", 0xB34D, fdiv, FP128, FP128>; + +def DEB : BinaryRXE<"deb", 0xED0D, fdiv, FP32, load>; +def DDB : BinaryRXE<"ddb", 0xED1D, fdiv, FP64, load>; + +//===----------------------------------------------------------------------===// +// Comparisons +//===----------------------------------------------------------------------===// + +let Defs = [PSW] in { + def CEBR : CompareRRE<"cebr", 0xB309, z_cmp, FP32, FP32>; + def CDBR : CompareRRE<"cdbr", 0xB319, z_cmp, FP64, FP64>; + def CXBR : CompareRRE<"cxbr", 0xB349, z_cmp, FP128, FP128>; + + def CEB : CompareRXE<"ceb", 0xED09, z_cmp, FP32, load>; + def CDB : CompareRXE<"cdb", 0xED19, z_cmp, FP64, load>; +} + +//===----------------------------------------------------------------------===// +// Peepholes +//===----------------------------------------------------------------------===// + +def : Pat<(f32 fpimmneg0), (LCEBR (LZER))>; +def : Pat<(f64 fpimmneg0), (LCDBR (LZDR))>; +def : Pat<(f128 fpimmneg0), (LCXBR (LZXR))>; diff --git a/lib/Target/SystemZ/SystemZInstrFormats.td b/lib/Target/SystemZ/SystemZInstrFormats.td new file mode 100644 index 0000000000..b32b7eb0fc --- /dev/null +++ b/lib/Target/SystemZ/SystemZInstrFormats.td @@ -0,0 +1,987 @@ +//==- 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. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Basic SystemZ instruction definition +//===----------------------------------------------------------------------===// + +class InstSystemZ<int size, dag outs, dag ins, string asmstr, + list<dag> pattern> : Instruction { + let Namespace = "SystemZ"; + + dag OutOperandList = outs; + dag InOperandList = ins; + let Size = size; + let Pattern = pattern; + let AsmString = asmstr; + + // Used to identify a group of related instructions, such as ST and STY. + string Function = ""; + + // "12" for an instruction that has a ...Y equivalent, "20" for that + // ...Y equivalent. + string PairType = "none"; + + // True if this instruction is a simple D(X,B) load of a register + // (with no sign or zero extension). + bit SimpleBDXLoad = 0; + + // True if this instruction is a simple D(X,B) store of a register + // (with no truncation). + bit SimpleBDXStore = 0; + + // True if this instruction has a 20-bit displacement field. + bit Has20BitOffset = 0; + + // True if addresses in this instruction have an index register. + bit HasIndex = 0; + + // True if this is a 128-bit pseudo instruction that combines two 64-bit + // operations. + bit Is128Bit = 0; + + let TSFlags{0} = SimpleBDXLoad; + let TSFlags{1} = SimpleBDXStore; + let TSFlags{2} = Has20BitOffset; + let TSFlags{3} = HasIndex; + let TSFlags{4} = Is128Bit; +} + +//===----------------------------------------------------------------------===// +// Mappings between instructions +//===----------------------------------------------------------------------===// + +// Return the version of an instruction that has an unsigned 12-bit +// displacement. +def getDisp12Opcode : InstrMapping { + let FilterClass = "InstSystemZ"; + let RowFields = ["Function"]; + let ColFields = ["PairType"]; + let KeyCol = ["20"]; + let ValueCols = [["12"]]; +} + +// Return the version of an instruction that has a signed 20-bit displacement. +def getDisp20Opcode : InstrMapping { + let FilterClass = "InstSystemZ"; + let RowFields = ["Function"]; + let ColFields = ["PairType"]; + let KeyCol = ["12"]; + let ValueCols = [["20"]]; +} + +//===----------------------------------------------------------------------===// +// Instruction formats +//===----------------------------------------------------------------------===// +// +// Formats are specified using operand field declarations of the form: +// +// bits<4> Rn : register input or output for operand n +// bits<m> In : immediate value of width m for operand n +// bits<4> Bn : base register for address operand n +// bits<m> Dn : displacement value of width m for address operand n +// bits<4> Xn : index register for address operand n +// bits<4> Mn : mode value for operand n +// +// The operand numbers ("n" in the list above) follow the architecture manual, +// but the fields are always declared in assembly order, so there are some +// cases where operand "2" comes after operand "3". For address operands, +// the base register field is declared first, followed by the displacement, +// followed by the index (if any). This matches the bdaddr* and bdxaddr* +// orders. +// +//===----------------------------------------------------------------------===// + +class InstRI<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<4, outs, ins, asmstr, pattern> { + field bits<32> Inst; + + bits<4> R1; + bits<16> I2; + + let Inst{31-24} = op{11-4}; + let Inst{23-20} = R1; + let Inst{19-16} = op{3-0}; + let Inst{15-0} = I2; +} + +class InstRIEf<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<6, outs, ins, asmstr, pattern> { + field bits<48> Inst; + + bits<4> R1; + bits<4> R2; + bits<8> I3; + bits<8> I4; + bits<8> I5; + + let Inst{47-40} = op{15-8}; + let Inst{39-36} = R1; + let Inst{35-32} = R2; + let Inst{31-24} = I3; + let Inst{23-16} = I4; + let Inst{15-8} = I5; + let Inst{7-0} = op{7-0}; +} + +class InstRIL<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<6, outs, ins, asmstr, pattern> { + field bits<48> Inst; + + bits<4> R1; + bits<32> I2; + + let Inst{47-40} = op{11-4}; + let Inst{39-36} = R1; + let Inst{35-32} = op{3-0}; + let Inst{31-0} = I2; +} + +class InstRR<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<2, outs, ins, asmstr, pattern> { + field bits<16> Inst; + + bits<4> R1; + bits<4> R2; + + let Inst{15-8} = op; + let Inst{7-4} = R1; + let Inst{3-0} = R2; +} + +class InstRRD<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<4, outs, ins, asmstr, pattern> { + field bits<32> Inst; + + bits<4> R1; + bits<4> R3; + bits<4> R2; + + let Inst{31-16} = op; + let Inst{15-12} = R1; + let Inst{11-8} = 0; + let Inst{7-4} = R3; + let Inst{3-0} = R2; +} + +class InstRRE<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<4, outs, ins, asmstr, pattern> { + field bits<32> Inst; + + bits<4> R1; + bits<4> R2; + + let Inst{31-16} = op; + let Inst{15-8} = 0; + let Inst{7-4} = R1; + let Inst{3-0} = R2; +} + +class InstRRF<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<4, outs, ins, asmstr, pattern> { + field bits<32> Inst; + + bits<4> R1; + bits<4> R2; + bits<4> R3; + + let Inst{31-16} = op; + let Inst{15-12} = R3; + let Inst{11-8} = 0; + let Inst{7-4} = R1; + let Inst{3-0} = R2; +} + +class InstRX<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<4, outs, ins, asmstr, pattern> { + field bits<32> Inst; + + bits<4> R1; + bits<4> B2; + bits<12> D2; + bits<4> X2; + + let Inst{31-24} = op; + let Inst{23-20} = R1; + let Inst{19-16} = X2; + let Inst{15-12} = B2; + let Inst{11-0} = D2; + + let HasIndex = 1; +} + +class InstRXE<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<6, outs, ins, asmstr, pattern> { + field bits<48> Inst; + + bits<4> R1; + bits<4> B2; + bits<12> D2; + bits<4> X2; + + let Inst{47-40} = op{15-8}; + let Inst{39-36} = R1; + let Inst{35-32} = X2; + let Inst{31-28} = B2; + let Inst{27-16} = D2; + let Inst{15-8} = 0; + let Inst{7-0} = op{7-0}; + + let HasIndex = 1; +} + +class InstRXF<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<6, outs, ins, asmstr, pattern> { + field bits<48> Inst; + + bits<4> R1; + bits<4> R3; + bits<4> B2; + bits<12> D2; + bits<4> X2; + + let Inst{47-40} = op{15-8}; + let Inst{39-36} = R3; + let Inst{35-32} = X2; + let Inst{31-28} = B2; + let Inst{27-16} = D2; + let Inst{15-12} = R1; + let Inst{11-8} = 0; + let Inst{7-0} = op{7-0}; + + let HasIndex = 1; +} + +class InstRXY<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<6, outs, ins, asmstr, pattern> { + field bits<48> Inst; + + bits<4> R1; + bits<4> B2; + bits<20> D2; + bits<4> X2; + + let Inst{47-40} = op{15-8}; + let Inst{39-36} = R1; + let Inst{35-32} = X2; + let Inst{31-28} = B2; + let Inst{27-16} = D2{11-0}; + let Inst{15-8} = D2{19-12}; + let Inst{7-0} = op{7-0}; + + let Has20BitOffset = 1; + let HasIndex = 1; +} + +class InstRS<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<4, outs, ins, asmstr, pattern> { + field bits<32> Inst; + + bits<4> R1; + bits<4> R3; + bits<4> B2; + bits<12> D2; + + let Inst{31-24} = op; + let Inst{23-20} = R1; + let Inst{19-16} = R3; + let Inst{15-12} = B2; + let Inst{11-0} = D2; +} + +class InstRSY<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<6, outs, ins, asmstr, pattern> { + field bits<48> Inst; + + bits<4> R1; + bits<4> R3; + bits<4> B2; + bits<20> D2; + + let Inst{47-40} = op{15-8}; + let Inst{39-36} = R1; + let Inst{35-32} = R3; + let Inst{31-28} = B2; + let Inst{27-16} = D2{11-0}; + let Inst{15-8} = D2{19-12}; + let Inst{7-0} = op{7-0}; + + let Has20BitOffset = 1; +} + +class InstSI<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<4, outs, ins, asmstr, pattern> { + field bits<32> Inst; + + bits<4> B1; + bits<12> D1; + bits<8> I2; + + let Inst{31-24} = op; + let Inst{23-16} = I2; + let Inst{15-12} = B1; + let Inst{11-0} = D1; +} + +class InstSIL<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<6, outs, ins, asmstr, pattern> { + field bits<48> Inst; + + bits<4> B1; + bits<12> D1; + bits<16> I2; + + let Inst{47-32} = op; + let Inst{31-28} = B1; + let Inst{27-16} = D1; + let Inst{15-0} = I2; +} + +class InstSIY<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSystemZ<6, outs, ins, asmstr, pattern> { + field bits<48> Inst; + + bits<4> B1; + bits<20> D1; + bits<8> I2; + + let Inst{47-40} = op{15-8}; + let Inst{39-32} = I2; + let Inst{31-28} = B1; + let Inst{27-16} = D1{11-0}; + let Inst{15-8} = D1{19-12}; + let Inst{7-0} = op{7-0}; + + let Has20BitOffset = 1; +} + +//===----------------------------------------------------------------------===// +// Instruction definitions with semantics +//===----------------------------------------------------------------------===// +// +// These classes have the form <Category><Format>, where <Format> is one +// of the formats defined above and where <Category> describes the inputs +// and outputs. <Category> can be one of: +// +// Inherent: +// One register output operand and no input operands. +// +// Store: +// One register or immediate input operand and one address input operand. +// The instruction stores the first operand to the address. +// +// This category is used for both pure and truncating stores. +// +// LoadMultiple: +// One address input operand and two explicit output operands. +// The instruction loads a range of registers from the address, +// with the explicit operands giving the first and last register +// to load. Other loaded registers are added as implicit definitions. +// +// StoreMultiple: +// Two explicit input register operands and an address operand. +// The instruction stores a range of registers to the address, +// with the explicit operands giving the first and last register +// to store. Other stored registers are added as implicit uses. +// +// Unary: +// One register output operand and one input operand. The input +// operand may be a register, immediate or memory. +// +// Binary: +// One register output operand and two input operands. The first +// input operand is always a register and he second may be a register, +// immediate or memory. +// +// Shift: +// One register output operand and two input operands. The first +// input operand is a register and the second has the same form as +// an address (although it isn't actually used to address memory). +// +// Compare: +// Two input operands. The first operand is always a register, +// the second may be a register, immediate or memory. +// +// Ternary: +// One register output operand and three register input operands. +// +// CmpSwap: +// One output operand and three input operands. The first two +// operands are registers and the third is an address. The instruction +// both reads from and writes to the address. +// +// RotateSelect: +// One output operand and five input operands. The first two operands +// are registers and the other three are immediates. +// +// The format determines which input operands are tied to output operands, +// and also determines the shape of any address operand. +// +// Multiclasses of the form <Category><Format>Pair define two instructions, +// one with <Category><Format> and one with <Category><Format>Y. The name +// of the first instruction has no suffix, the name of the second has +// an extra "y". +// +//===----------------------------------------------------------------------===// + +class InherentRRE<string mnemonic, bits<16> opcode, RegisterOperand cls, + dag src> + : InstRRE<opcode, (outs cls:$dst), (ins), + mnemonic#"\t$dst", + [(set cls:$dst, src)]> { + let R2 = 0; +} + +class LoadMultipleRSY<string mnemonic, bits<16> opcode, RegisterOperand cls> + : InstRSY<opcode, (outs cls:$dst1, cls:$dst2), (ins bdaddr20only:$addr), + mnemonic#"\t$dst1, $dst2, $addr", []> { + let mayLoad = 1; +} + +class StoreRILPC<string mnemonic, bits<12> opcode, SDPatternOperator operator, + RegisterOperand cls> + : InstRIL<opcode, (outs), (ins cls:$src, pcrel32:$addr), + mnemonic#"\t$src, $addr", + [(operator cls:$src, pcrel32:$addr)]> { + let mayStore = 1; + // We want PC-relative addresses to be tried ahead of BD and BDX addresses. + // However, BDXs have two extra operands and are therefore 6 units more + // complex. + let AddedComplexity = 7; +} + +class StoreRX<string mnemonic, bits<8> opcode, SDPatternOperator operator, + RegisterOperand cls, AddressingMode mode = bdxaddr12only> + : InstRX<opcode, (outs), (ins cls:$src, mode:$addr), + mnemonic#"\t$src, $addr", + [(operator cls:$src, mode:$addr)]> { + let mayStore = 1; +} + +class StoreRXY<string mnemonic, bits<16> opcode, SDPatternOperator operator, + RegisterOperand cls, AddressingMode mode = bdxaddr20only> + : InstRXY<opcode, (outs), (ins cls:$src, mode:$addr), + mnemonic#"\t$src, $addr", + [(operator cls:$src, mode:$addr)]> { + let mayStore = 1; +} + +multiclass StoreRXPair<string mnemonic, bits<8> rxOpcode, bits<16> rxyOpcode, + SDPatternOperator operator, RegisterOperand cls> { + let Function = mnemonic ## #cls in { + let PairType = "12" in + def "" : StoreRX<mnemonic, rxOpcode, operator, cls, bdxaddr12pair>; + let PairType = "20" in + def Y : StoreRXY<mnemonic#"y", rxyOpcode, operator, cls, bdxaddr20pair>; + } +} + +class StoreMultipleRSY<string mnemonic, bits<16> opcode, RegisterOperand cls> + : InstRSY<opcode, (outs), (ins cls:$from, cls:$to, bdaddr20only:$addr), + mnemonic#"\t$from, $to, $addr", []> { + let mayStore = 1; +} + +class StoreSI<string mnemonic, bits<8> opcode, SDPatternOperator operator, + Immediate imm, AddressingMode mode = bdaddr12only> + : InstSI<opcode, (outs), (ins mode:$addr, imm:$src), + mnemonic#"\t$addr, $src", + [(operator imm:$src, mode:$addr)]> { + let mayStore = 1; +} + +class StoreSIY<string mnemonic, bits<16> opcode, SDPatternOperator operator, + Immediate imm, AddressingMode mode = bdaddr20only> + : InstSIY<opcode, (outs), (ins mode:$addr, imm:$src), + mnemonic#"\t$addr, $src", + [(operator imm:$src, mode:$addr)]> { + let mayStore = 1; +} + +class StoreSIL<string mnemonic, bits<16> opcode, SDPatternOperator operator, + Immediate imm> + : InstSIL<opcode, (outs), (ins bdaddr12only:$addr, imm:$src), + mnemonic#"\t$addr, $src", + [(operator imm:$src, bdaddr12only:$addr)]> { + let mayStore = 1; +} + +multiclass StoreSIPair<string mnemonic, bits<8> siOpcode, bits<16> siyOpcode, + SDPatternOperator operator, Immediate imm> { + let Function = mnemonic in { + let PairType = "12" in + def "" : StoreSI<mnemonic, siOpcode, operator, imm, bdaddr12pair>; + let PairType = "20" in + def Y : StoreSIY<mnemonic#"y", siyOpcode, operator, imm, bdaddr20pair>; + } +} + +class UnaryRR<string mnemonic, bits<8> opcode, SDPatternOperator operator, + RegisterOperand cls1, RegisterOperand cls2> + : InstRR<opcode, (outs cls1:$dst), (ins cls2:$src), + mnemonic#"\t$dst, $src", + [(set cls1:$dst, (operator cls2:$src))]>; + +class UnaryRRE<string mnemonic, bits<16> opcode, SDPatternOperator operator, + RegisterOperand cls1, RegisterOperand cls2> + : InstRRE<opcode, (outs cls1:$dst), (ins cls2:$src), + mnemonic#"\t$dst, $src", + [(set cls1:$dst, (operator cls2:$src))]>; + +class UnaryRRF<string mnemonic, bits<16> opcode, RegisterOperand cls1, + RegisterOperand cls2> + : InstRRF<opcode, (outs cls1:$dst), (ins cls2:$src, uimm8zx4:$mode), + mnemonic#"\t$dst, $mode, $src", []>; + +class UnaryRI<string mnemonic, bits<12> opcode, SDPatternOperator operator, + RegisterOperand cls, Immediate imm> + : InstRI<opcode, (outs cls:$dst), (ins imm:$src), + mnemonic#"\t$dst, $src", + [(set cls:$dst, (operator imm:$src))]>; + +class UnaryRIL<string mnemonic, bits<12> opcode, SDPatternOperator operator, + RegisterOperand cls, Immediate imm> + : InstRIL<opcode, (outs cls:$dst), (ins imm:$src), + mnemonic#"\t$dst, $src", + [(set cls:$dst, (operator imm:$src))]>; + +class UnaryRILPC<string mnemonic, bits<12> opcode, SDPatternOperator operator, + RegisterOperand cls> + : InstRIL<opcode, (outs cls:$dst), (ins pcrel32:$addr), + mnemonic#"\t$dst, $addr", + [(set cls:$dst, (operator pcrel32:$addr))]> { + let mayLoad = 1; + // We want PC-relative addresses to be tried ahead of BD and BDX addresses. + // However, BDXs have two extra operands and are therefore 6 units more + // complex. + let AddedComplexity = 7; +} + +class UnaryRX<string mnemonic, bits<8> opcode, SDPatternOperator operator, + RegisterOperand cls, AddressingMode mode = bdxaddr12only> + : InstRX<opcode, (outs cls:$dst), (ins mode:$addr), + mnemonic#"\t$dst, $addr", + [(set cls:$dst, (operator mode:$addr))]> { + let mayLoad = 1; +} + +class UnaryRXE<string mnemonic, bits<16> opcode, SDPatternOperator operator, + RegisterOperand cls> + : InstRXE<opcode, (outs cls:$dst), (ins bdxaddr12only:$addr), + mnemonic#"\t$dst, $addr", + [(set cls:$dst, (operator bdxaddr12only:$addr))]> { + let mayLoad = 1; +} + +class UnaryRXY<string mnemonic, bits<16> opcode, SDPatternOperator operator, + RegisterOperand cls, AddressingMode mode = bdxaddr20only> + : InstRXY<opcode, (outs cls:$dst), (ins mode:$addr), + mnemonic#"\t$dst, $addr", + [(set cls:$dst, (operator mode:$addr))]> { + let mayLoad = 1; +} + +multiclass UnaryRXPair<string mnemonic, bits<8> rxOpcode, bits<16> rxyOpcode, + SDPatternOperator operator, RegisterOperand cls> { + let Function = mnemonic ## #cls in { + let PairType = "12" in + def "" : UnaryRX<mnemonic, rxOpcode, operator, cls, bdxaddr12pair>; + let PairType = "20" in + def Y : UnaryRXY<mnemonic#"y", rxyOpcode, operator, cls, bdxaddr20pair>; + } +} + +class BinaryRR<string mnemonic, bits<8> opcode, SDPatternOperator operator, + RegisterOperand cls1, RegisterOperand cls2> + : InstRR<opcode, (outs cls1:$dst), (ins cls1:$src1, cls2:$src2), + mnemonic#"\t$dst, $src2", + [(set cls1:$dst, (operator cls1:$src1, cls2:$src2))]> { + let Constraints = "$src1 = $dst"; + let DisableEncoding = "$src1"; +} + +class BinaryRRE<string mnemonic, bits<16> opcode, SDPatternOperator operator, + RegisterOperand cls1, RegisterOperand cls2> + : InstRRE<opcode, (outs cls1:$dst), (ins cls1:$src1, cls2:$src2), + mnemonic#"\t$dst, $src2", + [(set cls1:$dst, (operator cls1:$src1, cls2:$src2))]> { + let Constraints = "$src1 = $dst"; + let DisableEncoding = "$src1"; +} + +// Here the assembly and dag operands are in natural order, +// but the first input operand maps to R3 and the second to R2. +// This is used for "CPSDR R1, R3, R2", which is equivalent to +// R1 = copysign (R3, R2). +// +// Direct uses of the instruction must pass operands in encoding order -- +// R1, R2, R3 -- so they must pass the source operands in reverse order. +class BinaryRevRRF<string mnemonic, bits<16> opcode, SDPatternOperator operator, + RegisterOperand cls1, RegisterOperand cls2> + : InstRRF<opcode, (outs cls1:$dst), (ins cls2:$src2, cls1:$src1), + mnemonic#"\t$dst, $src1, $src2", + [(set cls1:$dst, (operator cls1:$src1, cls2:$src2))]>; + +class BinaryRI<string mnemonic, bits<12> opcode, SDPatternOperator operator, + RegisterOperand cls, Immediate imm> + : InstRI<opcode, (outs cls:$dst), (ins cls:$src1, imm:$src2), + mnemonic#"\t$dst, $src2", + [(set cls:$dst, (operator cls:$src1, imm:$src2))]> { + let Constraints = "$src1 = $dst"; + let DisableEncoding = "$src1"; +} + +class BinaryRIL<string mnemonic, bits<12> opcode, SDPatternOperator operator, + RegisterOperand cls, Immediate imm> + : InstRIL<opcode, (outs cls:$dst), (ins cls:$src1, imm:$src2), + mnemonic#"\t$dst, $src2", + [(set cls:$dst, (operator cls:$src1, imm:$src2))]> { + let Constraints = "$src1 = $dst"; + let DisableEncoding = "$src1"; +} + +class BinaryRX<string mnemonic, bits<8> opcode, SDPatternOperator operator, + RegisterOperand cls, SDPatternOperator load, + AddressingMode mode = bdxaddr12only> + : InstRX<opcode, (outs cls:$dst), (ins cls:$src1, mode:$src2), + mnemonic#"\t$dst, $src2", + [(set cls:$dst, (operator cls:$src1, (load mode:$src2)))]> { + let Constraints = "$src1 = $dst"; + let DisableEncoding = "$src1"; + let mayLoad = 1; +} + +class BinaryRXE<string mnemonic, bits<16> opcode, SDPatternOperator operator, + RegisterOperand cls, SDPatternOperator load> + : InstRXE<opcode, (outs cls:$dst), (ins cls:$src1, bdxaddr12only:$src2), + mnemonic#"\t$dst, $src2", + [(set cls:$dst, (operator cls:$src1, + (load bdxaddr12only:$src2)))]> { + let Constraints = "$src1 = $dst"; + let DisableEncoding = "$src1"; + let mayLoad = 1; +} + +class BinaryRXY<string mnemonic, bits<16> opcode, SDPatternOperator operator, + RegisterOperand cls, SDPatternOperator load, + AddressingMode mode = bdxaddr20only> + : InstRXY<opcode, (outs cls:$dst), (ins cls:$src1, mode:$src2), + mnemonic#"\t$dst, $src2", + [(set cls:$dst, (operator cls:$src1, (load mode:$src2)))]> { + let Constraints = "$src1 = $dst"; + let DisableEncoding = "$src1"; + let mayLoad = 1; +} + +multiclass BinaryRXPair<string mnemonic, bits<8> rxOpcode, bits<16> rxyOpcode, + SDPatternOperator operator, RegisterOperand cls, + SDPatternOperator load> { + let Function = mnemonic ## #cls in { + let PairType = "12" in + def "" : BinaryRX<mnemonic, rxOpcode, operator, cls, load, bdxaddr12pair>; + let PairType = "20" in + def Y : BinaryRXY<mnemonic#"y", rxyOpcode, operator, cls, load, + bdxaddr20pair>; + } +} + +class BinarySI<string mnemonic, bits<8> opcode, SDPatternOperator operator, + Operand imm, AddressingMode mode = bdaddr12only> + : InstSI<opcode, (outs), (ins mode:$addr, imm:$src), + mnemonic#"\t$addr, $src", + [(store (operator (load mode:$addr), imm:$src), mode:$addr)]> { + let mayLoad = 1; + let mayStore = 1; +} + +class BinarySIY<string mnemonic, bits<16> opcode, SDPatternOperator operator, + Operand imm, AddressingMode mode = bdaddr20only> + : InstSIY<opcode, (outs), (ins mode:$addr, imm:$src), + mnemonic#"\t$addr, $src", + [(store (operator (load mode:$addr), imm:$src), mode:$addr)]> { + let mayLoad = 1; + let mayStore = 1; +} + +multiclass BinarySIPair<string mnemonic, bits<8> siOpcode, + bits<16> siyOpcode, SDPatternOperator operator, + Operand imm> { + let Function = mnemonic ## #cls in { + let PairType = "12" in + def "" : BinarySI<mnemonic, siOpcode, operator, imm, bdaddr12pair>; + let PairType = "20" in + def Y : BinarySIY<mnemonic#"y", siyOpcode, operator, imm, bdaddr20pair>; + } +} + +class ShiftRS<string mnemonic, bits<8> opcode, SDPatternOperator operator, + RegisterOperand cls, AddressingMode mode> + : InstRS<opcode, (outs cls:$dst), (ins cls:$src1, mode:$src2), + mnemonic#"\t$dst, $src2", + [(set cls:$dst, (operator cls:$src1, mode:$src2))]> { + let R3 = 0; + let Constraints = "$src1 = $dst"; + let DisableEncoding = "$src1"; +} + +class ShiftRSY<string mnemonic, bits<16> opcode, SDPatternOperator operator, + RegisterOperand cls, AddressingMode mode> + : InstRSY<opcode, (outs cls:$dst), (ins cls:$src1, mode:$src2), + mnemonic#"\t$dst, $src1, $src2", + [(set cls:$dst, (operator cls:$src1, mode:$src2))]>; + +class CompareRR<string mnemonic, bits<8> opcode, SDPatternOperator operator, + RegisterOperand cls1, RegisterOperand cls2> + : InstRR<opcode, (outs), (ins cls1:$src1, cls2:$src2), + mnemonic#"\t$src1, $src2", + [(operator cls1:$src1, cls2:$src2)]>; + +class CompareRRE<string mnemonic, bits<16> opcode, SDPatternOperator operator, + RegisterOperand cls1, RegisterOperand cls2> + : InstRRE<opcode, (outs), (ins cls1:$src1, cls2:$src2), + mnemonic#"\t$src1, $src2", + [(operator cls1:$src1, cls2:$src2)]>; + +class CompareRI<string mnemonic, bits<12> opcode, SDPatternOperator operator, + RegisterOperand cls, Immediate imm> + : InstRI<opcode, (outs), (ins cls:$src1, imm:$src2), + mnemonic#"\t$src1, $src2", + [(operator cls:$src1, imm:$src2)]>; + +class CompareRIL<string mnemonic, bits<12> opcode, SDPatternOperator operator, + RegisterOperand cls, Immediate imm> + : InstRIL<opcode, (outs), (ins cls:$src1, imm:$src2), + mnemonic#"\t$src1, $src2", + [(operator cls:$src1, imm:$src2)]>; + +class CompareRILPC<string mnemonic, bits<12> opcode, SDPatternOperator operator, + RegisterOperand cls, SDPatternOperator load> + : InstRIL<opcode, (outs), (ins cls:$src1, pcrel32:$src2), + mnemonic#"\t$src1, $src2", + [(operator cls:$src1, (load pcrel32:$src2))]> { + let mayLoad = 1; + // We want PC-relative addresses to be tried ahead of BD and BDX addresses. + // However, BDXs have two extra operands and are therefore 6 units more + // complex. + let AddedComplexity = 7; +} + +class CompareRX<string mnemonic, bits<8> opcode, SDPatternOperator operator, + RegisterOperand cls, SDPatternOperator load, + AddressingMode mode = bdxaddr12only> + : InstRX<opcode, (outs), (ins cls:$src1, mode:$src2), + mnemonic#"\t$src1, $src2", + [(operator cls:$src1, (load mode:$src2))]> { + let mayLoad = 1; +} + +class CompareRXE<string mnemonic, bits<16> opcode, SDPatternOperator operator, + RegisterOperand cls, SDPatternOperator load> + : InstRXE<opcode, (outs), (ins cls:$src1, bdxaddr12only:$src2), + mnemonic#"\t$src1, $src2", + [(operator cls:$src1, (load bdxaddr12only:$src2))]> { + let mayLoad = 1; +} + +class CompareRXY<string mnemonic, bits<16> opcode, SDPatternOperator operator, + RegisterOperand cls, SDPatternOperator load, + AddressingMode mode = bdxaddr20only> + : InstRXY<opcode, (outs), (ins cls:$src1, mode:$src2), + mnemonic#"\t$src1, $src2", + [(operator cls:$src1, (load mode:$src2))]> { + let mayLoad = 1; +} + +multiclass CompareRXPair<string mnemonic, bits<8> rxOpcode, bits<16> rxyOpcode, + SDPatternOperator operator, RegisterOperand cls, + SDPatternOperator load> { + let Function = mnemonic ## #cls in { + let PairType = "12" in + def "" : CompareRX<mnemonic, rxOpcode, operator, cls, + load, bdxaddr12pair>; + let PairType = "20" in + def Y : CompareRXY<mnemonic#"y", rxyOpcode, operator, cls, + load, bdxaddr20pair>; + } +} + +class CompareSI<string mnemonic, bits<8> opcode, SDPatternOperator operator, + SDPatternOperator load, Immediate imm, + AddressingMode mode = bdaddr12only> + : InstSI<opcode, (outs), (ins mode:$addr, imm:$src), + mnemonic#"\t$addr, $src", + [(operator (load mode:$addr), imm:$src)]> { + let mayLoad = 1; +} + +class CompareSIL<string mnemonic, bits<16> opcode, SDPatternOperator operator, + SDPatternOperator load, Immediate imm> + : InstSIL<opcode, (outs), (ins bdaddr12only:$addr, imm:$src), + mnemonic#"\t$addr, $src", + [(operator (load bdaddr12only:$addr), imm:$src)]> { + let mayLoad = 1; +} + +class CompareSIY<string mnemonic, bits<16> opcode, SDPatternOperator operator, + SDPatternOperator load, Immediate imm, + AddressingMode mode = bdaddr20only> + : InstSIY<opcode, (outs), (ins mode:$addr, imm:$src), + mnemonic#"\t$addr, $src", + [(operator (load mode:$addr), imm:$src)]> { + let mayLoad = 1; +} + +multiclass CompareSIPair<string mnemonic, bits<8> siOpcode, bits<16> siyOpcode, + SDPatternOperator operator, SDPatternOperator load, + Immediate imm> { + let Function = mnemonic in { + let PairType = "12" in + def "" : CompareSI<mnemonic, siOpcode, operator, load, imm, bdaddr12pair>; + let PairType = "20" in + def Y : CompareSIY<mnemonic#"y", siyOpcode, operator, load, imm, + bdaddr20pair>; + } +} + +class TernaryRRD<string mnemonic, bits<16> opcode, + SDPatternOperator operator, RegisterOperand cls> + : InstRRD<opcode, (outs cls:$dst), (ins cls:$src1, cls:$src2, cls:$src3), + mnemonic#"\t$dst, $src2, $src3", + [(set cls:$dst, (operator cls:$src1, cls:$src2, cls:$src3))]> { + let Constraints = "$src1 = $dst"; + let DisableEncoding = "$src1"; +} + +class TernaryRXF<string mnemonic, bits<16> opcode, SDPatternOperator operator, + RegisterOperand cls, SDPatternOperator load> + : InstRXF<opcode, (outs cls:$dst), + (ins cls:$src1, cls:$src2, bdxaddr12only:$src3), + mnemonic#"\t$dst, $src2, $src3", + [(set cls:$dst, (operator cls:$src1, cls:$src2, + (load bdxaddr12only:$src3)))]> { + let Constraints = "$src1 = $dst"; + let DisableEncoding = "$src1"; + let mayLoad = 1; +} + +class CmpSwapRS<string mnemonic, bits<8> opcode, SDPatternOperator operator, + RegisterOperand cls, AddressingMode mode = bdaddr12only> + : InstRS<opcode, (outs cls:$dst), (ins cls:$old, cls:$new, mode:$ptr), + mnemonic#"\t$dst, $new, $ptr", + [(set cls:$dst, (operator mode:$ptr, cls:$old, cls:$new))]> { + let Constraints = "$old = $dst"; + let DisableEncoding = "$old"; + let mayLoad = 1; + let mayStore = 1; +} + +class CmpSwapRSY<string mnemonic, bits<16> opcode, SDPatternOperator operator, + RegisterOperand cls, AddressingMode mode = bdaddr20only> + : InstRSY<opcode, (outs cls:$dst), (ins cls:$old, cls:$new, mode:$ptr), + mnemonic#"\t$dst, $new, $ptr", + [(set cls:$dst, (operator mode:$ptr, cls:$old, cls:$new))]> { + let Constraints = "$old = $dst"; + let DisableEncoding = "$old"; + let mayLoad = 1; + let mayStore = 1; +} + +multiclass CmpSwapRSPair<string mnemonic, bits<8> rsOpcode, bits<16> rsyOpcode, + SDPatternOperator operator, RegisterOperand cls> { + let Function = mnemonic ## #cls in { + let PairType = "12" in + def "" : CmpSwapRS<mnemonic, rsOpcode, operator, cls, bdaddr12pair>; + let PairType = "20" in + def Y : CmpSwapRSY<mnemonic#"y", rsyOpcode, operator, cls, bdaddr20pair>; + } +} + +class RotateSelectRIEf<string mnemonic, bits<16> opcode, RegisterOperand cls1, + RegisterOperand cls2> + : InstRIEf<opcode, (outs cls1:$dst), + (ins cls1:$src1, cls2:$src2, + uimm8zx6:$imm1, uimm8zx6:$imm2, uimm8zx6:$imm3), + mnemonic#"\t$dst, $src2, $imm1, $imm2, $imm3", []> { + let Constraints = "$src1 = $dst"; + let DisableEncoding = "$src1"; +} + +//===----------------------------------------------------------------------===// +// Pseudo instructions +//===----------------------------------------------------------------------===// +// +// Convenience instructions that get lowered to real instructions +// by either SystemZTargetLowering::EmitInstrWithCustomInserter() +// or SystemZInstrInfo::expandPostRAPseudo(). +// +//===----------------------------------------------------------------------===// + +class Pseudo<dag outs, dag ins, list<dag> pattern> + : InstSystemZ<0, outs, ins, "", pattern> { + let isPseudo = 1; + let isCodeGenOnly = 1; +} + +// Implements "$dst = $cc & (8 >> CC) ? $src1 : $src2", where CC is +// the value of the PSW's 2-bit condition code field. +class SelectWrapper<RegisterOperand cls> + : Pseudo<(outs cls:$dst), (ins cls:$src1, cls:$src2, i8imm:$cc), + [(set cls:$dst, (z_select_ccmask cls:$src1, cls:$src2, imm:$cc))]> { + let usesCustomInserter = 1; + // Although the instructions used by these nodes do not in themselves + // change the PSW, the insertion requires new blocks, and the PSW cannot + // be live across them. + let Defs = [PSW]; + let Uses = [PSW]; +} + +// OPERATOR is ATOMIC_SWAP or an ATOMIC_LOAD_* operation. PAT and OPERAND +// describe the second (non-memory) operand. +class AtomicLoadBinary<SDPatternOperator operator, RegisterOperand cls, + dag pat, DAGOperand operand> + : Pseudo<(outs cls:$dst), (ins bdaddr20only:$ptr, operand:$src2), + [(set cls:$dst, (operator bdaddr20only:$ptr, pat))]> { + let Defs = [PSW]; + let Has20BitOffset = 1; + let mayLoad = 1; + let mayStore = 1; + let usesCustomInserter = 1; +} + +// Specializations of AtomicLoadWBinary. +class AtomicLoadBinaryReg32<SDPatternOperator operator> + : AtomicLoadBinary<operator, GR32, (i32 GR32:$src2), GR32>; +class AtomicLoadBinaryImm32<SDPatternOperator operator, Immediate imm> + : AtomicLoadBinary<operator, GR32, (i32 imm:$src2), imm>; +class AtomicLoadBinaryReg64<SDPatternOperator operator> + : AtomicLoadBinary<operator, GR64, (i64 GR64:$src2), GR64>; +class AtomicLoadBinaryImm64<SDPatternOperator operator, Immediate imm> + : AtomicLoadBinary<operator, GR64, (i64 imm:$src2), imm>; + +// OPERATOR is ATOMIC_SWAPW or an ATOMIC_LOADW_* operation. PAT and OPERAND +// describe the second (non-memory) operand. +class AtomicLoadWBinary<SDPatternOperator operator, dag pat, + DAGOperand operand> + : Pseudo<(outs GR32:$dst), + (ins bdaddr20only:$ptr, operand:$src2, ADDR32:$bitshift, + ADDR32:$negbitshift, uimm32:$bitsize), + [(set GR32:$dst, (operator bdaddr20only:$ptr, pat, ADDR32:$bitshift, + ADDR32:$negbitshift, uimm32:$bitsize))]> { + let Defs = [PSW]; + let Has20BitOffset = 1; + let mayLoad = 1; + let mayStore = 1; + let usesCustomInserter = 1; +} + +// Specializations of AtomicLoadWBinary. +class AtomicLoadWBinaryReg<SDPatternOperator operator> + : AtomicLoadWBinary<operator, (i32 GR32:$src2), GR32>; +class AtomicLoadWBinaryImm<SDPatternOperator operator, Immediate imm> + : AtomicLoadWBinary<operator, (i32 imm:$src2), imm>; diff --git a/lib/Target/SystemZ/SystemZInstrInfo.cpp b/lib/Target/SystemZ/SystemZInstrInfo.cpp new file mode 100644 index 0000000000..0718c83fc7 --- /dev/null +++ b/lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -0,0 +1,444 @@ +//===-- 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 "SystemZInstrInfo.h" +#include "SystemZInstrBuilder.h" + +#define GET_INSTRINFO_CTOR +#define GET_INSTRMAP_INFO +#include "SystemZGenInstrInfo.inc" + +using namespace llvm; + +SystemZInstrInfo::SystemZInstrInfo(SystemZTargetMachine &tm) + : SystemZGenInstrInfo(SystemZ::ADJCALLSTACKDOWN, SystemZ::ADJCALLSTACKUP), + RI(tm, *this) { +} + +// MI is a 128-bit load or store. Split it into two 64-bit loads or stores, +// each having the opcode given by NewOpcode. +void SystemZInstrInfo::splitMove(MachineBasicBlock::iterator MI, + unsigned NewOpcode) const { + MachineBasicBlock *MBB = MI->getParent(); + MachineFunction &MF = *MBB->getParent(); + + // Get two load or store instructions. Use the original instruction for one + // of them (arbitarily the second here) and create a clone for the other. + MachineInstr *EarlierMI = MF.CloneMachineInstr(MI); + MBB->insert(MI, EarlierMI); + + // Set up the two 64-bit registers. + MachineOperand &HighRegOp = EarlierMI->getOperand(0); + MachineOperand &LowRegOp = MI->getOperand(0); + HighRegOp.setReg(RI.getSubReg(HighRegOp.getReg(), SystemZ::subreg_high)); + LowRegOp.setReg(RI.getSubReg(LowRegOp.getReg(), SystemZ::subreg_low)); + + // The address in the first (high) instruction is already correct. + // Adjust the offset in the second (low) instruction. + MachineOperand &HighOffsetOp = EarlierMI->getOperand(2); + MachineOperand &LowOffsetOp = MI->getOperand(2); + LowOffsetOp.setImm(LowOffsetOp.getImm() + 8); + + // Set the opcodes. + unsigned HighOpcode = getOpcodeForOffset(NewOpcode, HighOffsetOp.getImm()); + unsigned LowOpcode = getOpcodeForOffset(NewOpcode, LowOffsetOp.getImm()); + assert(HighOpcode && LowOpcode && "Both offsets should be in range"); + + EarlierMI->setDesc(get(HighOpcode)); + MI->setDesc(get(LowOpcode)); +} + +// Split ADJDYNALLOC instruction MI. +void SystemZInstrInfo::splitAdjDynAlloc(MachineBasicBlock::iterator MI) const { + MachineBasicBlock *MBB = MI->getParent(); + MachineFunction &MF = *MBB->getParent(); + MachineFrameInfo *MFFrame = MF.getFrameInfo(); + MachineOperand &OffsetMO = MI->getOperand(2); + + uint64_t Offset = (MFFrame->getMaxCallFrameSize() + + SystemZMC::CallFrameSize + + OffsetMO.getImm()); + unsigned NewOpcode = getOpcodeForOffset(SystemZ::LA, Offset); + assert(NewOpcode && "No support for huge argument lists yet"); + MI->setDesc(get(NewOpcode)); + OffsetMO.setImm(Offset); +} + +// If MI is a simple load or store for a frame object, return the register +// it loads or stores and set FrameIndex to the index of the frame object. +// Return 0 otherwise. +// +// Flag is SimpleBDXLoad for loads and SimpleBDXStore for stores. +static int isSimpleMove(const MachineInstr *MI, int &FrameIndex, int Flag) { + const MCInstrDesc &MCID = MI->getDesc(); + if ((MCID.TSFlags & Flag) && + MI->getOperand(1).isFI() && + MI->getOperand(2).getImm() == 0 && + MI->getOperand(3).getReg() == 0) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + return 0; +} + +unsigned SystemZInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const { + return isSimpleMove(MI, FrameIndex, SystemZII::SimpleBDXLoad); +} + +unsigned SystemZInstrInfo::isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const { + return isSimpleMove(MI, FrameIndex, SystemZII::SimpleBDXStore); +} + +bool SystemZInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const { + // Most of the code and comments here are boilerplate. + + // 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. + unsigned ThisCond; + const MachineOperand *ThisTarget; + if (!isBranch(I, ThisCond, ThisTarget)) + return true; + + // Can't handle indirect branches. + if (!ThisTarget->isMBB()) + return true; + + if (ThisCond == SystemZ::CCMASK_ANY) { + // Handle unconditional branches. + if (!AllowModify) { + TBB = ThisTarget->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(ThisTarget->getMBB())) { + TBB = 0; + I->eraseFromParent(); + I = MBB.end(); + continue; + } + + // TBB is used to indicate the unconditinal destination. + TBB = ThisTarget->getMBB(); + continue; + } + + // Working from the bottom, handle the first conditional branch. + if (Cond.empty()) { + // FIXME: add X86-style branch swap + FBB = TBB; + TBB = ThisTarget->getMBB(); + Cond.push_back(MachineOperand::CreateImm(ThisCond)); + continue; + } + + // Handle subsequent conditional branches. + assert(Cond.size() == 1); + assert(TBB); + + // Only handle the case where all conditional branches branch to the same + // destination. + if (TBB != ThisTarget->getMBB()) + return true; + + // If the conditions are the same, we can leave them alone. + unsigned OldCond = Cond[0].getImm(); + if (OldCond == ThisCond) + continue; + + // FIXME: Try combining conditions like X86 does. Should be easy on Z! + } + + return false; +} + +unsigned SystemZInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const { + // Most of the code and comments here are boilerplate. + MachineBasicBlock::iterator I = MBB.end(); + unsigned Count = 0; + + while (I != MBB.begin()) { + --I; + if (I->isDebugValue()) + continue; + unsigned Cond; + const MachineOperand *Target; + if (!isBranch(I, Cond, Target)) + break; + if (!Target->isMBB()) + 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 { + // In this function we output 32-bit branches, which should always + // have enough range. They can be shortened and relaxed by later code + // in the pipeline, if desired. + + // 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::JG)).addMBB(TBB); + return 1; + } + + // Conditional branch. + unsigned Count = 0; + unsigned CC = Cond[0].getImm(); + BuildMI(&MBB, DL, get(SystemZ::BRCL)).addImm(CC).addMBB(TBB); + ++Count; + + if (FBB) { + // Two-way Conditional branch. Insert the second branch. + BuildMI(&MBB, DL, get(SystemZ::JG)).addMBB(FBB); + ++Count; + } + return Count; +} + +void +SystemZInstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const { + // Split 128-bit GPR moves into two 64-bit moves. This handles ADDR128 too. + if (SystemZ::GR128BitRegClass.contains(DestReg, SrcReg)) { + copyPhysReg(MBB, MBBI, DL, RI.getSubReg(DestReg, SystemZ::subreg_high), + RI.getSubReg(SrcReg, SystemZ::subreg_high), KillSrc); + copyPhysReg(MBB, MBBI, DL, RI.getSubReg(DestReg, SystemZ::subreg_low), + RI.getSubReg(SrcReg, SystemZ::subreg_low), KillSrc); + return; + } + + // Everything else needs only one instruction. + unsigned Opcode; + if (SystemZ::GR32BitRegClass.contains(DestReg, SrcReg)) + Opcode = SystemZ::LR; + else if (SystemZ::GR64BitRegClass.contains(DestReg, SrcReg)) + Opcode = SystemZ::LGR; + else if (SystemZ::FP32BitRegClass.contains(DestReg, SrcReg)) + Opcode = SystemZ::LER; + else if (SystemZ::FP64BitRegClass.contains(DestReg, SrcReg)) + Opcode = SystemZ::LDR; + else if (SystemZ::FP128BitRegClass.contains(DestReg, SrcReg)) + Opcode = SystemZ::LXR; + else + llvm_unreachable("Impossible reg-to-reg copy"); + + BuildMI(MBB, MBBI, DL, get(Opcode), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); +} + +void +SystemZInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, bool isKill, + int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + + // Callers may expect a single instruction, so keep 128-bit moves + // together for now and lower them after register allocation. + unsigned LoadOpcode, StoreOpcode; + getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode); + addFrameReference(BuildMI(MBB, MBBI, DL, get(StoreOpcode)) + .addReg(SrcReg, getKillRegState(isKill)), FrameIdx); +} + +void +SystemZInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + + // Callers may expect a single instruction, so keep 128-bit moves + // together for now and lower them after register allocation. + unsigned LoadOpcode, StoreOpcode; + getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode); + addFrameReference(BuildMI(MBB, MBBI, DL, get(LoadOpcode), DestReg), + FrameIdx); +} + +bool +SystemZInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { + switch (MI->getOpcode()) { + case SystemZ::L128: + splitMove(MI, SystemZ::LG); + return true; + + case SystemZ::ST128: + splitMove(MI, SystemZ::STG); + return true; + + case SystemZ::LX: + splitMove(MI, SystemZ::LD); + return true; + + case SystemZ::STX: + splitMove(MI, SystemZ::STD); + return true; + + case SystemZ::ADJDYNALLOC: + splitAdjDynAlloc(MI); + return true; + + default: + return false; + } +} + +bool SystemZInstrInfo:: +ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const { + assert(Cond.size() == 1 && "Invalid branch condition!"); + Cond[0].setImm(Cond[0].getImm() ^ SystemZ::CCMASK_ANY); + return false; +} + +bool SystemZInstrInfo::isBranch(const MachineInstr *MI, unsigned &Cond, + const MachineOperand *&Target) const { + switch (MI->getOpcode()) { + case SystemZ::BR: + case SystemZ::J: + case SystemZ::JG: + Cond = SystemZ::CCMASK_ANY; + Target = &MI->getOperand(0); + return true; + + case SystemZ::BRC: + case SystemZ::BRCL: + Cond = MI->getOperand(0).getImm(); + Target = &MI->getOperand(1); + return true; + + default: + assert(!MI->getDesc().isBranch() && "Unknown branch opcode"); + return false; + } +} + +void SystemZInstrInfo::getLoadStoreOpcodes(const TargetRegisterClass *RC, + unsigned &LoadOpcode, + unsigned &StoreOpcode) const { + if (RC == &SystemZ::GR32BitRegClass || RC == &SystemZ::ADDR32BitRegClass) { + LoadOpcode = SystemZ::L; + StoreOpcode = SystemZ::ST32; + } else if (RC == &SystemZ::GR64BitRegClass || + RC == &SystemZ::ADDR64BitRegClass) { + LoadOpcode = SystemZ::LG; + StoreOpcode = SystemZ::STG; + } else if (RC == &SystemZ::GR128BitRegClass || + RC == &SystemZ::ADDR128BitRegClass) { + LoadOpcode = SystemZ::L128; + StoreOpcode = SystemZ::ST128; + } else if (RC == &SystemZ::FP32BitRegClass) { + LoadOpcode = SystemZ::LE; + StoreOpcode = SystemZ::STE; + } else if (RC == &SystemZ::FP64BitRegClass) { + LoadOpcode = SystemZ::LD; + StoreOpcode = SystemZ::STD; + } else if (RC == &SystemZ::FP128BitRegClass) { + LoadOpcode = SystemZ::LX; + StoreOpcode = SystemZ::STX; + } else + llvm_unreachable("Unsupported regclass to load or store"); +} + +unsigned SystemZInstrInfo::getOpcodeForOffset(unsigned Opcode, + int64_t Offset) const { + const MCInstrDesc &MCID = get(Opcode); + int64_t Offset2 = (MCID.TSFlags & SystemZII::Is128Bit ? Offset + 8 : Offset); + if (isUInt<12>(Offset) && isUInt<12>(Offset2)) { + // Get the instruction to use for unsigned 12-bit displacements. + int Disp12Opcode = SystemZ::getDisp12Opcode(Opcode); + if (Disp12Opcode >= 0) + return Disp12Opcode; + + // All address-related instructions can use unsigned 12-bit + // displacements. + return Opcode; + } + if (isInt<20>(Offset) && isInt<20>(Offset2)) { + // Get the instruction to use for signed 20-bit displacements. + int Disp20Opcode = SystemZ::getDisp20Opcode(Opcode); + if (Disp20Opcode >= 0) + return Disp20Opcode; + + // Check whether Opcode allows signed 20-bit displacements. + if (MCID.TSFlags & SystemZII::Has20BitOffset) + return Opcode; + } + return 0; +} + +void SystemZInstrInfo::loadImmediate(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned Reg, uint64_t Value) const { + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + unsigned Opcode; + if (isInt<16>(Value)) + Opcode = SystemZ::LGHI; + else if (SystemZ::isImmLL(Value)) + Opcode = SystemZ::LLILL; + else if (SystemZ::isImmLH(Value)) { + Opcode = SystemZ::LLILH; + Value >>= 16; + } else { + assert(isInt<32>(Value) && "Huge values not handled yet"); + Opcode = SystemZ::LGFI; + } + BuildMI(MBB, MBBI, DL, get(Opcode), Reg).addImm(Value); +} diff --git a/lib/Target/SystemZ/SystemZInstrInfo.h b/lib/Target/SystemZ/SystemZInstrInfo.h new file mode 100644 index 0000000000..0fc47617f0 --- /dev/null +++ b/lib/Target/SystemZ/SystemZInstrInfo.h @@ -0,0 +1,123 @@ +//===-- 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/Target/TargetInstrInfo.h" + +#define GET_INSTRINFO_HEADER +#include "SystemZGenInstrInfo.inc" + +namespace llvm { + +class SystemZTargetMachine; + +namespace SystemZII { + enum { + // See comments in SystemZInstrFormats.td. + SimpleBDXLoad = (1 << 0), + SimpleBDXStore = (1 << 1), + Has20BitOffset = (1 << 2), + HasIndex = (1 << 3), + Is128Bit = (1 << 4) + }; + // SystemZ MachineOperand target flags. + enum { + // Masks out the bits for the access model. + MO_SYMBOL_MODIFIER = (1 << 0), + + // @GOT (aka @GOTENT) + MO_GOT = (1 << 0) + }; +} + +class SystemZInstrInfo : public SystemZGenInstrInfo { + const SystemZRegisterInfo RI; + + void splitMove(MachineBasicBlock::iterator MI, unsigned NewOpcode) const; + void splitAdjDynAlloc(MachineBasicBlock::iterator MI) const; + +public: + explicit SystemZInstrInfo(SystemZTargetMachine &TM); + + // Override TargetInstrInfo. + virtual unsigned isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const LLVM_OVERRIDE; + virtual unsigned isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const LLVM_OVERRIDE; + virtual bool AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const LLVM_OVERRIDE; + virtual unsigned RemoveBranch(MachineBasicBlock &MBB) const LLVM_OVERRIDE; + virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond, + DebugLoc DL) const LLVM_OVERRIDE; + virtual void copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const LLVM_OVERRIDE; + virtual void + storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const LLVM_OVERRIDE; + virtual void + loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const LLVM_OVERRIDE; + virtual bool + expandPostRAPseudo(MachineBasicBlock::iterator MBBI) const LLVM_OVERRIDE; + virtual bool + ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const + LLVM_OVERRIDE; + + // Return the SystemZRegisterInfo, which this class owns. + const SystemZRegisterInfo &getRegisterInfo() const { return RI; } + + // Return true if MI is a conditional or unconditional branch. + // When returning true, set Cond to the mask of condition-code + // values on which the instruction will branch, and set Target + // to the operand that contains the branch target. This target + // can be a register or a basic block. + bool isBranch(const MachineInstr *MI, unsigned &Cond, + const MachineOperand *&Target) const; + + // Get the load and store opcodes for a given register class. + void getLoadStoreOpcodes(const TargetRegisterClass *RC, + unsigned &LoadOpcode, unsigned &StoreOpcode) const; + + // Opcode is the opcode of an instruction that has an address operand, + // and the caller wants to perform that instruction's operation on an + // address that has displacement Offset. Return the opcode of a suitable + // instruction (which might be Opcode itself) or 0 if no such instruction + // exists. + unsigned getOpcodeForOffset(unsigned Opcode, int64_t Offset) const; + + // Emit code before MBBI in MI to move immediate value Value into + // physical register Reg. + void loadImmediate(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned Reg, uint64_t Value) const; +}; +} // end namespace llvm + +#endif diff --git a/lib/Target/SystemZ/SystemZInstrInfo.td b/lib/Target/SystemZ/SystemZInstrInfo.td new file mode 100644 index 0000000000..7ffa382d36 --- /dev/null +++ b/lib/Target/SystemZ/SystemZInstrInfo.td @@ -0,0 +1,955 @@ +//===-- SystemZInstrInfo.td - General SystemZ instructions ----*- tblgen-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Stack allocation +//===----------------------------------------------------------------------===// + +def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i64imm:$amt), + [(callseq_start timm:$amt)]>; +def ADJCALLSTACKUP : Pseudo<(outs), (ins i64imm:$amt1, i64imm:$amt2), + [(callseq_end timm:$amt1, timm:$amt2)]>; + +let neverHasSideEffects = 1 in { + // Takes as input the value of the stack pointer after a dynamic allocation + // has been made. Sets the output to the address of the dynamically- + // allocated area itself, skipping the outgoing arguments. + // + // This expands to an LA or LAY instruction. We restrict the offset + // to the range of LA and keep the LAY range in reserve for when + // the size of the outgoing arguments is added. + def ADJDYNALLOC : Pseudo<(outs GR64:$dst), (ins dynalloc12only:$src), + [(set GR64:$dst, dynalloc12only:$src)]>; +} + +//===----------------------------------------------------------------------===// +// Control flow instructions +//===----------------------------------------------------------------------===// + +// A return instruction. R1 is the condition-code mask (all 1s) +// and R2 is the target address, which is always stored in %r14. +let isReturn = 1, isTerminator = 1, isBarrier = 1, hasCtrlDep = 1, + R1 = 15, R2 = 14, isCodeGenOnly = 1 in { + def RET : InstRR<0x07, (outs), (ins), "br\t%r14", [(z_retflag)]>; +} + +// Unconditional branches. R1 is the condition-code mask (all 1s). +let isBranch = 1, isTerminator = 1, isBarrier = 1, R1 = 15 in { + let isIndirectBranch = 1 in + def BR : InstRR<0x07, (outs), (ins ADDR64:$dst), + "br\t$dst", [(brind ADDR64:$dst)]>; + + // An assembler extended mnemonic for BRC. Use a separate instruction for + // the asm parser, so that we don't relax Js to external symbols into JGs. + let isCodeGenOnly = 1 in + def J : InstRI<0xA74, (outs), (ins brtarget16:$dst), "j\t$dst", []>; + let isAsmParserOnly = 1 in + def AsmJ : InstRI<0xA74, (outs), (ins brtarget16:$dst), "j\t$dst", []>; + + // An assembler extended mnemonic for BRCL. (The extension is "G" + // rather than "L" because "JL" is "Jump if Less".) + def JG : InstRIL<0xC04, (outs), (ins brtarget32:$dst), + "jg\t$dst", [(br bb:$dst)]>; +} + +// Conditional branches. It's easier for LLVM to handle these branches +// in their raw BRC/BRCL form, with the 4-bit condition-code mask being +// the first operand. It seems friendlier to use mnemonic forms like +// JE and JLH when writing out the assembly though. +multiclass CondBranches<Operand imm, string short, string long> { + let isBranch = 1, isTerminator = 1, Uses = [PSW] in { + def "" : InstRI<0xA74, (outs), (ins imm:$cond, brtarget16:$dst), short, []>; + def L : InstRIL<0xC04, (outs), (ins imm:$cond, brtarget32:$dst), long, []>; + } +} +let isCodeGenOnly = 1 in + defm BRC : CondBranches<cond4, "j$cond\t$dst", "jg$cond\t$dst">; +let isAsmParserOnly = 1 in + defm AsmBRC : CondBranches<uimm8zx4, "brc\t$cond, $dst", "brcl\t$cond, $dst">; + +def : Pat<(z_br_ccmask cond4:$cond, bb:$dst), (BRCL cond4:$cond, bb:$dst)>; + +// Define AsmParser mnemonics for each condition code. +multiclass CondExtendedMnemonic<bits<4> Cond, string name> { + let R1 = Cond in { + def "" : InstRI<0xA74, (outs), (ins brtarget16:$dst), + "j"##name##"\t$dst", []>; + def L : InstRIL<0xC04, (outs), (ins brtarget32:$dst), + "jg"##name##"\t$dst", []>; + } +} +let isAsmParserOnly = 1 in { + defm AsmJO : CondExtendedMnemonic<1, "o">; + defm AsmJH : CondExtendedMnemonic<2, "h">; + defm AsmJNLE : CondExtendedMnemonic<3, "nle">; + defm AsmJL : CondExtendedMnemonic<4, "l">; + defm AsmJNHE : CondExtendedMnemonic<5, "nhe">; + defm AsmJLH : CondExtendedMnemonic<6, "lh">; + defm AsmJNE : CondExtendedMnemonic<7, "ne">; + defm AsmJE : CondExtendedMnemonic<8, "e">; + defm AsmJNLH : CondExtendedMnemonic<9, "nlh">; + defm AsmJHE : CondExtendedMnemonic<10, "he">; + defm AsmJNL : CondExtendedMnemonic<11, "nl">; + defm AsmJLE : CondExtendedMnemonic<12, "le">; + defm AsmJNH : CondExtendedMnemonic<13, "nh">; + defm AsmJNO : CondExtendedMnemonic<14, "no">; +} + +def Select32 : SelectWrapper<GR32>; +def Select64 : SelectWrapper<GR64>; + +//===----------------------------------------------------------------------===// +// Call instructions +//===----------------------------------------------------------------------===// + +// The definitions here are for the call-clobbered registers. +let isCall = 1, Defs = [R0D, R1D, R2D, R3D, R4D, R5D, R14D, + F0D, F1D, F2D, F3D, F4D, F5D, F6D, F7D], + R1 = 14, isCodeGenOnly = 1 in { + def BRAS : InstRI<0xA75, (outs), (ins pcrel16call:$dst, variable_ops), + "bras\t%r14, $dst", []>; + def BRASL : InstRIL<0xC05, (outs), (ins pcrel32call:$dst, variable_ops), + "brasl\t%r14, $dst", [(z_call pcrel32call:$dst)]>; + def BASR : InstRR<0x0D, (outs), (ins ADDR64:$dst, variable_ops), + "basr\t%r14, $dst", [(z_call ADDR64:$dst)]>; +} + +// Define the general form of the call instructions for the asm parser. +// These instructions don't hard-code %r14 as the return address register. +let isAsmParserOnly = 1 in { + def AsmBRAS : InstRI<0xA75, (outs), (ins GR64:$save, brtarget16:$dst), + "bras\t$save, $dst", []>; + def AsmBRASL : InstRIL<0xC05, (outs), (ins GR64:$save, brtarget32:$dst), + "brasl\t$save, $dst", []>; + def AsmBASR : InstRR<0x0D, (outs), (ins GR64:$save, ADDR64:$dst), + "basr\t$save, $dst", []>; +} + +//===----------------------------------------------------------------------===// +// Move instructions +//===----------------------------------------------------------------------===// + +// Register moves. +let neverHasSideEffects = 1 in { + def LR : UnaryRR <"lr", 0x18, null_frag, GR32, GR32>; + def LGR : UnaryRRE<"lgr", 0xB904, null_frag, GR64, GR64>; +} + +// Immediate moves. +let neverHasSideEffects = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in { + // 16-bit sign-extended immediates. + def LHI : UnaryRI<"lhi", 0xA78, bitconvert, GR32, imm32sx16>; + def LGHI : UnaryRI<"lghi", 0xA79, bitconvert, GR64, imm64sx16>; + + // Other 16-bit immediates. + def LLILL : UnaryRI<"llill", 0xA5F, bitconvert, GR64, imm64ll16>; + def LLILH : UnaryRI<"llilh", 0xA5E, bitconvert, GR64, imm64lh16>; + def LLIHL : UnaryRI<"llihl", 0xA5D, bitconvert, GR64, imm64hl16>; + def LLIHH : UnaryRI<"llihh", 0xA5C, bitconvert, GR64, imm64hh16>; + + // 32-bit immediates. + def LGFI : UnaryRIL<"lgfi", 0xC01, bitconvert, GR64, imm64sx32>; + def LLILF : UnaryRIL<"llilf", 0xC0F, bitconvert, GR64, imm64lf32>; + def LLIHF : UnaryRIL<"llihf", 0xC0E, bitconvert, GR64, imm64hf32>; +} + +// Register loads. +let canFoldAsLoad = 1, SimpleBDXLoad = 1 in { + defm L : UnaryRXPair<"l", 0x58, 0xE358, load, GR32>; + def LRL : UnaryRILPC<"lrl", 0xC4D, aligned_load, GR32>; + + def LG : UnaryRXY<"lg", 0xE304, load, GR64>; + def LGRL : UnaryRILPC<"lgrl", 0xC48, aligned_load, GR64>; + + // These instructions are split after register allocation, so we don't + // want a custom inserter. + let Has20BitOffset = 1, HasIndex = 1, Is128Bit = 1 in { + def L128 : Pseudo<(outs GR128:$dst), (ins bdxaddr20only128:$src), + [(set GR128:$dst, (load bdxaddr20only128:$src))]>; + } +} + +// Register stores. +let SimpleBDXStore = 1 in { + let isCodeGenOnly = 1 in { + defm ST32 : StoreRXPair<"st", 0x50, 0xE350, store, GR32>; + def STRL32 : StoreRILPC<"strl", 0xC4F, aligned_store, GR32>; + } + + def STG : StoreRXY<"stg", 0xE324, store, GR64>; + def STGRL : StoreRILPC<"stgrl", 0xC4B, aligned_store, GR64>; + + // These instructions are split after register allocation, so we don't + // want a custom inserter. + let Has20BitOffset = 1, HasIndex = 1, Is128Bit = 1 in { + def ST128 : Pseudo<(outs), (ins GR128:$src, bdxaddr20only128:$dst), + [(store GR128:$src, bdxaddr20only128:$dst)]>; + } +} + +// 8-bit immediate stores to 8-bit fields. +defm MVI : StoreSIPair<"mvi", 0x92, 0xEB52, truncstorei8, imm32zx8trunc>; + +// 16-bit immediate stores to 16-, 32- or 64-bit fields. +def MVHHI : StoreSIL<"mvhhi", 0xE544, truncstorei16, imm32sx16trunc>; +def MVHI : StoreSIL<"mvhi", 0xE54C, store, imm32sx16>; +def MVGHI : StoreSIL<"mvghi", 0xE548, store, imm64sx16>; + +//===----------------------------------------------------------------------===// +// Sign extensions +//===----------------------------------------------------------------------===// + +// 32-bit extensions from registers. +let neverHasSideEffects = 1 in { + def LBR : UnaryRRE<"lbr", 0xB926, sext8, GR32, GR32>; + def LHR : UnaryRRE<"lhr", 0xB927, sext16, GR32, GR32>; +} + +// 64-bit extensions from registers. +let neverHasSideEffects = 1 in { + def LGBR : UnaryRRE<"lgbr", 0xB906, sext8, GR64, GR64>; + def LGHR : UnaryRRE<"lghr", 0xB907, sext16, GR64, GR64>; + def LGFR : UnaryRRE<"lgfr", 0xB914, sext32, GR64, GR32>; +} + +// Match 32-to-64-bit sign extensions in which the source is already +// in a 64-bit register. +def : Pat<(sext_inreg GR64:$src, i32), + (LGFR (EXTRACT_SUBREG GR64:$src, subreg_32bit))>; + +// 32-bit extensions from memory. +def LB : UnaryRXY<"lb", 0xE376, sextloadi8, GR32>; +defm LH : UnaryRXPair<"lh", 0x48, 0xE378, sextloadi16, GR32>; +def LHRL : UnaryRILPC<"lhrl", 0xC45, aligned_sextloadi16, GR32>; + +// 64-bit extensions from memory. +def LGB : UnaryRXY<"lgb", 0xE377, sextloadi8, GR64>; +def LGH : UnaryRXY<"lgh", 0xE315, sextloadi16, GR64>; +def LGF : UnaryRXY<"lgf", 0xE314, sextloadi32, GR64>; +def LGHRL : UnaryRILPC<"lghrl", 0xC44, aligned_sextloadi16, GR64>; +def LGFRL : UnaryRILPC<"lgfrl", 0xC4C, aligned_sextloadi32, GR64>; + +// If the sign of a load-extend operation doesn't matter, use the signed ones. +// There's not really much to choose between the sign and zero extensions, +// but LH is more compact than LLH for small offsets. +def : Pat<(i32 (extloadi8 bdxaddr20only:$src)), (LB bdxaddr20only:$src)>; +def : Pat<(i32 (extloadi16 bdxaddr12pair:$src)), (LH bdxaddr12pair:$src)>; +def : Pat<(i32 (extloadi16 bdxaddr20pair:$src)), (LHY bdxaddr20pair:$src)>; + +def : Pat<(i64 (extloadi8 bdxaddr20only:$src)), (LGB bdxaddr20only:$src)>; +def : Pat<(i64 (extloadi16 bdxaddr20only:$src)), (LGH bdxaddr20only:$src)>; +def : Pat<(i64 (extloadi32 bdxaddr20only:$src)), (LGF bdxaddr20only:$src)>; + +//===----------------------------------------------------------------------===// +// Zero extensions +//===----------------------------------------------------------------------===// + +// 32-bit extensions from registers. +let neverHasSideEffects = 1 in { + def LLCR : UnaryRRE<"llcr", 0xB994, zext8, GR32, GR32>; + def LLHR : UnaryRRE<"llhr", 0xB995, zext16, GR32, GR32>; +} + +// 64-bit extensions from registers. +let neverHasSideEffects = 1 in { + def LLGCR : UnaryRRE<"llgcr", 0xB984, zext8, GR64, GR64>; + def LLGHR : UnaryRRE<"llghr", 0xB985, zext16, GR64, GR64>; + def LLGFR : UnaryRRE<"llgfr", 0xB916, zext32, GR64, GR32>; +} + +// Match 32-to-64-bit zero extensions in which the source is already +// in a 64-bit register. +def : Pat<(and GR64:$src, 0xffffffff), + (LLGFR (EXTRACT_SUBREG GR64:$src, subreg_32bit))>; + +// 32-bit extensions from memory. +def LLC : UnaryRXY<"llc", 0xE394, zextloadi8, GR32>; +def LLH : UnaryRXY<"llh", 0xE395, zextloadi16, GR32>; +def LLHRL : UnaryRILPC<"llhrl", 0xC42, aligned_zextloadi16, GR32>; + +// 64-bit extensions from memory. +def LLGC : UnaryRXY<"llgc", 0xE390, zextloadi8, GR64>; +def LLGH : UnaryRXY<"llgh", 0xE391, zextloadi16, GR64>; +def LLGF : UnaryRXY<"llgf", 0xE316, zextloadi32, GR64>; +def LLGHRL : UnaryRILPC<"llghrl", 0xC46, aligned_zextloadi16, GR64>; +def LLGFRL : UnaryRILPC<"llgfrl", 0xC4E, aligned_zextloadi32, GR64>; + +//===----------------------------------------------------------------------===// +// Truncations +//===----------------------------------------------------------------------===// + +// Truncations of 64-bit registers to 32-bit registers. +def : Pat<(i32 (trunc GR64:$src)), + (EXTRACT_SUBREG GR64:$src, subreg_32bit)>; + +// Truncations of 32-bit registers to memory. +let isCodeGenOnly = 1 in { + defm STC32 : StoreRXPair<"stc", 0x42, 0xE372, truncstorei8, GR32>; + defm STH32 : StoreRXPair<"sth", 0x40, 0xE370, truncstorei16, GR32>; + def STHRL32 : StoreRILPC<"sthrl", 0xC47, aligned_truncstorei16, GR32>; +} + +// Truncations of 64-bit registers to memory. +defm STC : StoreRXPair<"stc", 0x42, 0xE372, truncstorei8, GR64>; +defm STH : StoreRXPair<"sth", 0x40, 0xE370, truncstorei16, GR64>; +def STHRL : StoreRILPC<"sthrl", 0xC47, aligned_truncstorei16, GR64>; +defm ST : StoreRXPair<"st", 0x50, 0xE350, truncstorei32, GR64>; +def STRL : StoreRILPC<"strl", 0xC4F, aligned_truncstorei32, GR64>; + +//===----------------------------------------------------------------------===// +// Multi-register moves +//===----------------------------------------------------------------------===// + +// Multi-register loads. +def LMG : LoadMultipleRSY<"lmg", 0xEB04, GR64>; + +// Multi-register stores. +def STMG : StoreMultipleRSY<"stmg", 0xEB24, GR64>; + +//===----------------------------------------------------------------------===// +// Byte swaps +//===----------------------------------------------------------------------===// + +// Byte-swapping register moves. +let neverHasSideEffects = 1 in { + def LRVR : UnaryRRE<"lrvr", 0xB91F, bswap, GR32, GR32>; + def LRVGR : UnaryRRE<"lrvgr", 0xB90F, bswap, GR64, GR64>; +} + +// Byte-swapping loads. +def LRV : UnaryRXY<"lrv", 0xE31E, loadu<bswap>, GR32>; +def LRVG : UnaryRXY<"lrvg", 0xE30F, loadu<bswap>, GR64>; + +// Byte-swapping stores. +def STRV : StoreRXY<"strv", 0xE33E, storeu<bswap>, GR32>; +def STRVG : StoreRXY<"strvg", 0xE32F, storeu<bswap>, GR64>; + +//===----------------------------------------------------------------------===// +// Load address instructions +//===----------------------------------------------------------------------===// + +// Load BDX-style addresses. +let neverHasSideEffects = 1, Function = "la" in { + let PairType = "12" in + def LA : InstRX<0x41, (outs GR64:$dst), (ins laaddr12pair:$src), + "la\t$dst, $src", + [(set GR64:$dst, laaddr12pair:$src)]>; + let PairType = "20" in + def LAY : InstRXY<0xE371, (outs GR64:$dst), (ins laaddr20pair:$src), + "lay\t$dst, $src", + [(set GR64:$dst, laaddr20pair:$src)]>; +} + +// Load a PC-relative address. There's no version of this instruction +// with a 16-bit offset, so there's no relaxation. +let neverHasSideEffects = 1 in { + def LARL : InstRIL<0xC00, (outs GR64:$dst), (ins pcrel32:$src), + "larl\t$dst, $src", + [(set GR64:$dst, pcrel32:$src)]>; +} + +//===----------------------------------------------------------------------===// +// Negation +//===----------------------------------------------------------------------===// + +let Defs = [PSW] in { + def LCR : UnaryRR <"lcr", 0x13, ineg, GR32, GR32>; + def LCGR : UnaryRRE<"lcgr", 0xB903, ineg, GR64, GR64>; + def LCGFR : UnaryRRE<"lcgfr", 0xB913, null_frag, GR64, GR32>; +} +defm : SXU<ineg, LCGFR>; + +//===----------------------------------------------------------------------===// +// Insertion +//===----------------------------------------------------------------------===// + +let isCodeGenOnly = 1 in + defm IC32 : BinaryRXPair<"ic", 0x43, 0xE373, inserti8, GR32, zextloadi8>; +defm IC : BinaryRXPair<"ic", 0x43, 0xE373, inserti8, GR64, zextloadi8>; + +defm : InsertMem<"inserti8", IC32, GR32, zextloadi8, bdxaddr12pair>; +defm : InsertMem<"inserti8", IC32Y, GR32, zextloadi8, bdxaddr20pair>; + +defm : InsertMem<"inserti8", IC, GR64, zextloadi8, bdxaddr12pair>; +defm : InsertMem<"inserti8", ICY, GR64, zextloadi8, bdxaddr20pair>; + +// Insertions of a 16-bit immediate, leaving other bits unaffected. +// We don't have or_as_insert equivalents of these operations because +// OI is available instead. +let isCodeGenOnly = 1 in { + def IILL32 : BinaryRI<"iill", 0xA53, insertll, GR32, imm32ll16>; + def IILH32 : BinaryRI<"iilh", 0xA52, insertlh, GR32, imm32lh16>; +} +def IILL : BinaryRI<"iill", 0xA53, insertll, GR64, imm64ll16>; +def IILH : BinaryRI<"iilh", 0xA52, insertlh, GR64, imm64lh16>; +def IIHL : BinaryRI<"iihl", 0xA51, inserthl, GR64, imm64hl16>; +def IIHH : BinaryRI<"iihh", 0xA50, inserthh, GR64, imm64hh16>; + +// ...likewise for 32-bit immediates. For GR32s this is a general +// full-width move. (We use IILF rather than something like LLILF +// for 32-bit moves because IILF leaves the upper 32 bits of the +// GR64 unchanged.) +let isCodeGenOnly = 1 in { + def IILF32 : UnaryRIL<"iilf", 0xC09, bitconvert, GR32, uimm32>; +} +def IILF : BinaryRIL<"iilf", 0xC09, insertlf, GR64, imm64lf32>; +def IIHF : BinaryRIL<"iihf", 0xC08, inserthf, GR64, imm64hf32>; + +// An alternative model of inserthf, with the first operand being +// a zero-extended value. +def : Pat<(or (zext32 GR32:$src), imm64hf32:$imm), + (IIHF (INSERT_SUBREG (i64 (IMPLICIT_DEF)), GR32:$src, subreg_32bit), + imm64hf32:$imm)>; + +//===----------------------------------------------------------------------===// +// Addition +//===----------------------------------------------------------------------===// + +// Plain addition. +let Defs = [PSW] in { + // Addition of a register. + let isCommutable = 1 in { + def AR : BinaryRR <"ar", 0x1A, add, GR32, GR32>; + def AGR : BinaryRRE<"agr", 0xB908, add, GR64, GR64>; + } + def AGFR : BinaryRRE<"agfr", 0xB918, null_frag, GR64, GR32>; + + // Addition of signed 16-bit immediates. + def AHI : BinaryRI<"ahi", 0xA7A, add, GR32, imm32sx16>; + def AGHI : BinaryRI<"aghi", 0xA7B, add, GR64, imm64sx16>; + + // Addition of signed 32-bit immediates. + def AFI : BinaryRIL<"afi", 0xC29, add, GR32, simm32>; + def AGFI : BinaryRIL<"agfi", 0xC28, add, GR64, imm64sx32>; + + // Addition of memory. + defm AH : BinaryRXPair<"ah", 0x4A, 0xE37A, add, GR32, sextloadi16>; + defm A : BinaryRXPair<"a", 0x5A, 0xE35A, add, GR32, load>; + def AGF : BinaryRXY<"agf", 0xE318, add, GR64, sextloadi32>; + def AG : BinaryRXY<"ag", 0xE308, add, GR64, load>; + + // Addition to memory. + def ASI : BinarySIY<"asi", 0xEB6A, add, imm32sx8>; + def AGSI : BinarySIY<"agsi", 0xEB7A, add, imm64sx8>; +} +defm : SXB<add, GR64, AGFR>; + +// Addition producing a carry. +let Defs = [PSW] in { + // Addition of a register. + let isCommutable = 1 in { + def ALR : BinaryRR <"alr", 0x1E, addc, GR32, GR32>; + def ALGR : BinaryRRE<"algr", 0xB90A, addc, GR64, GR64>; + } + def ALGFR : BinaryRRE<"algfr", 0xB91A, null_frag, GR64, GR32>; + + // Addition of unsigned 32-bit immediates. + def ALFI : BinaryRIL<"alfi", 0xC2B, addc, GR32, uimm32>; + def ALGFI : BinaryRIL<"algfi", 0xC2A, addc, GR64, imm64zx32>; + + // Addition of memory. + defm AL : BinaryRXPair<"al", 0x5E, 0xE35E, addc, GR32, load>; + def ALGF : BinaryRXY<"algf", 0xE31A, addc, GR64, zextloadi32>; + def ALG : BinaryRXY<"alg", 0xE30A, addc, GR64, load>; +} +defm : ZXB<addc, GR64, ALGFR>; + +// Addition producing and using a carry. +let Defs = [PSW], Uses = [PSW] in { + // Addition of a register. + def ALCR : BinaryRRE<"alcr", 0xB998, adde, GR32, GR32>; + def ALCGR : BinaryRRE<"alcgr", 0xB988, adde, GR64, GR64>; + + // Addition of memory. + def ALC : BinaryRXY<"alc", 0xE398, adde, GR32, load>; + def ALCG : BinaryRXY<"alcg", 0xE388, adde, GR64, load>; +} + +//===----------------------------------------------------------------------===// +// Subtraction +//===----------------------------------------------------------------------===// + +// Plain substraction. Although immediate forms exist, we use the +// add-immediate instruction instead. +let Defs = [PSW] in { + // Subtraction of a register. + def SR : BinaryRR <"sr", 0x1B, sub, GR32, GR32>; + def SGFR : BinaryRRE<"sgfr", 0xB919, null_frag, GR64, GR32>; + def SGR : BinaryRRE<"sgr", 0xB909, sub, GR64, GR64>; + + // Subtraction of memory. + defm S : BinaryRXPair<"s", 0x5B, 0xE35B, sub, GR32, load>; + def SGF : BinaryRXY<"sgf", 0xE319, sub, GR64, sextloadi32>; + def SG : BinaryRXY<"sg", 0xE309, sub, GR64, load>; +} +defm : SXB<sub, GR64, SGFR>; + +// Subtraction producing a carry. +let Defs = [PSW] in { + // Subtraction of a register. + def SLR : BinaryRR <"slr", 0x1F, subc, GR32, GR32>; + def SLGFR : BinaryRRE<"slgfr", 0xB91B, null_frag, GR64, GR32>; + def SLGR : BinaryRRE<"slgr", 0xB90B, subc, GR64, GR64>; + + // Subtraction of unsigned 32-bit immediates. These don't match + // subc because we prefer addc for constants. + def SLFI : BinaryRIL<"slfi", 0xC25, null_frag, GR32, uimm32>; + def SLGFI : BinaryRIL<"slgfi", 0xC24, null_frag, GR64, imm64zx32>; + + // Subtraction of memory. + defm SL : BinaryRXPair<"sl", 0x5F, 0xE35F, subc, GR32, load>; + def SLGF : BinaryRXY<"slgf", 0xE31B, subc, GR64, zextloadi32>; + def SLG : BinaryRXY<"slg", 0xE30B, subc, GR64, load>; +} +defm : ZXB<subc, GR64, SLGFR>; + +// Subtraction producing and using a carry. +let Defs = [PSW], Uses = [PSW] in { + // Subtraction of a register. + def SLBR : BinaryRRE<"slbr", 0xB999, sube, GR32, GR32>; + def SLGBR : BinaryRRE<"slbgr", 0xB989, sube, GR64, GR64>; + + // Subtraction of memory. + def SLB : BinaryRXY<"slb", 0xE399, sube, GR32, load>; + def SLBG : BinaryRXY<"slbg", 0xE389, sube, GR64, load>; +} + +//===----------------------------------------------------------------------===// +// AND +//===----------------------------------------------------------------------===// + +let Defs = [PSW] in { + // ANDs of a register. + let isCommutable = 1 in { + def NR : BinaryRR <"nr", 0x14, and, GR32, GR32>; + def NGR : BinaryRRE<"ngr", 0xB980, and, GR64, GR64>; + } + + // ANDs of a 16-bit immediate, leaving other bits unaffected. + let isCodeGenOnly = 1 in { + def NILL32 : BinaryRI<"nill", 0xA57, and, GR32, imm32ll16c>; + def NILH32 : BinaryRI<"nilh", 0xA56, and, GR32, imm32lh16c>; + } + def NILL : BinaryRI<"nill", 0xA57, and, GR64, imm64ll16c>; + def NILH : BinaryRI<"nilh", 0xA56, and, GR64, imm64lh16c>; + def NIHL : BinaryRI<"nihl", 0xA55, and, GR64, imm64hl16c>; + def NIHH : BinaryRI<"nihh", 0xA54, and, GR64, imm64hh16c>; + + // ANDs of a 32-bit immediate, leaving other bits unaffected. + let isCodeGenOnly = 1 in + def NILF32 : BinaryRIL<"nilf", 0xC0B, and, GR32, uimm32>; + def NILF : BinaryRIL<"nilf", 0xC0B, and, GR64, imm64lf32c>; + def NIHF : BinaryRIL<"nihf", 0xC0A, and, GR64, imm64hf32c>; + + // ANDs of memory. + defm N : BinaryRXPair<"n", 0x54, 0xE354, and, GR32, load>; + def NG : BinaryRXY<"ng", 0xE380, and, GR64, load>; + + // AND to memory + defm NI : BinarySIPair<"ni", 0x94, 0xEB54, null_frag, uimm8>; +} +defm : RMWIByte<and, bdaddr12pair, NI>; +defm : RMWIByte<and, bdaddr20pair, NIY>; + +//===----------------------------------------------------------------------===// +// OR +//===----------------------------------------------------------------------===// + +let Defs = [PSW] in { + // ORs of a register. + let isCommutable = 1 in { + def OR : BinaryRR <"or", 0x16, or, GR32, GR32>; + def OGR : BinaryRRE<"ogr", 0xB981, or, GR64, GR64>; + } + + // ORs of a 16-bit immediate, leaving other bits unaffected. + let isCodeGenOnly = 1 in { + def OILL32 : BinaryRI<"oill", 0xA5B, or, GR32, imm32ll16>; + def OILH32 : BinaryRI<"oilh", 0xA5A, or, GR32, imm32lh16>; + } + def OILL : BinaryRI<"oill", 0xA5B, or, GR64, imm64ll16>; + def OILH : BinaryRI<"oilh", 0xA5A, or, GR64, imm64lh16>; + def OIHL : BinaryRI<"oihl", 0xA59, or, GR64, imm64hl16>; + def OIHH : BinaryRI<"oihh", 0xA58, or, GR64, imm64hh16>; + + // ORs of a 32-bit immediate, leaving other bits unaffected. + let isCodeGenOnly = 1 in + def OILF32 : BinaryRIL<"oilf", 0xC0D, or, GR32, uimm32>; + def OILF : BinaryRIL<"oilf", 0xC0D, or, GR64, imm64lf32>; + def OIHF : BinaryRIL<"oihf", 0xC0C, or, GR64, imm64hf32>; + + // ORs of memory. + defm O : BinaryRXPair<"o", 0x56, 0xE356, or, GR32, load>; + def OG : BinaryRXY<"og", 0xE381, or, GR64, load>; + + // OR to memory + defm OI : BinarySIPair<"oi", 0x96, 0xEB56, null_frag, uimm8>; +} +defm : RMWIByte<or, bdaddr12pair, OI>; +defm : RMWIByte<or, bdaddr20pair, OIY>; + +//===----------------------------------------------------------------------===// +// XOR +//===----------------------------------------------------------------------===// + +let Defs = [PSW] in { + // XORs of a register. + let isCommutable = 1 in { + def XR : BinaryRR <"xr", 0x17, xor, GR32, GR32>; + def XGR : BinaryRRE<"xgr", 0xB982, xor, GR64, GR64>; + } + + // XORs of a 32-bit immediate, leaving other bits unaffected. + let isCodeGenOnly = 1 in + def XILF32 : BinaryRIL<"xilf", 0xC07, xor, GR32, uimm32>; + def XILF : BinaryRIL<"xilf", 0xC07, xor, GR64, imm64lf32>; + def XIHF : BinaryRIL<"xihf", 0xC06, xor, GR64, imm64hf32>; + + // XORs of memory. + defm X : BinaryRXPair<"x",0x57, 0xE357, xor, GR32, load>; + def XG : BinaryRXY<"xg", 0xE382, xor, GR64, load>; + + // XOR to memory + defm XI : BinarySIPair<"xi", 0x97, 0xEB57, null_frag, uimm8>; +} +defm : RMWIByte<xor, bdaddr12pair, XI>; +defm : RMWIByte<xor, bdaddr20pair, XIY>; + +//===----------------------------------------------------------------------===// +// Multiplication +//===----------------------------------------------------------------------===// + +// Multiplication of a register. +let isCommutable = 1 in { + def MSR : BinaryRRE<"msr", 0xB252, mul, GR32, GR32>; + def MSGR : BinaryRRE<"msgr", 0xB90C, mul, GR64, GR64>; +} +def MSGFR : BinaryRRE<"msgfr", 0xB91C, null_frag, GR64, GR32>; +defm : SXB<mul, GR64, MSGFR>; + +// Multiplication of a signed 16-bit immediate. +def MHI : BinaryRI<"mhi", 0xA7C, mul, GR32, imm32sx16>; +def MGHI : BinaryRI<"mghi", 0xA7D, mul, GR64, imm64sx16>; + +// Multiplication of a signed 32-bit immediate. +def MSFI : BinaryRIL<"msfi", 0xC21, mul, GR32, simm32>; +def MSGFI : BinaryRIL<"msgfi", 0xC20, mul, GR64, imm64sx32>; + +// Multiplication of memory. +defm MH : BinaryRXPair<"mh", 0x4C, 0xE37C, mul, GR32, sextloadi16>; +defm MS : BinaryRXPair<"ms", 0x71, 0xE351, mul, GR32, load>; +def MSGF : BinaryRXY<"msgf", 0xE31C, mul, GR64, sextloadi32>; +def MSG : BinaryRXY<"msg", 0xE30C, mul, GR64, load>; + +// Multiplication of a register, producing two results. +def MLGR : BinaryRRE<"mlgr", 0xB986, z_umul_lohi64, GR128, GR64>; + +// Multiplication of memory, producing two results. +def MLG : BinaryRXY<"mlg", 0xE386, z_umul_lohi64, GR128, load>; + +//===----------------------------------------------------------------------===// +// Division and remainder +//===----------------------------------------------------------------------===// + +// Division and remainder, from registers. +def DSGFR : BinaryRRE<"dsgfr", 0xB91D, null_frag, GR128, GR32>; +def DSGR : BinaryRRE<"dsgr", 0xB90D, z_sdivrem64, GR128, GR64>; +def DLR : BinaryRRE<"dlr", 0xB997, z_udivrem32, GR128, GR32>; +def DLGR : BinaryRRE<"dlgr", 0xB987, z_udivrem64, GR128, GR64>; +defm : SXB<z_sdivrem64, GR128, DSGFR>; + +// Division and remainder, from memory. +def DSGF : BinaryRXY<"dsgf", 0xE31D, z_sdivrem64, GR128, sextloadi32>; +def DSG : BinaryRXY<"dsg", 0xE30D, z_sdivrem64, GR128, load>; +def DL : BinaryRXY<"dl", 0xE397, z_udivrem32, GR128, load>; +def DLG : BinaryRXY<"dlg", 0xE387, z_udivrem64, GR128, load>; + +//===----------------------------------------------------------------------===// +// Shifts +//===----------------------------------------------------------------------===// + +// Shift left. +let neverHasSideEffects = 1 in { + def SLL : ShiftRS <"sll", 0x89, shl, GR32, shift12only>; + def SLLG : ShiftRSY<"sllg", 0xEB0D, shl, GR64, shift20only>; +} + +// Logical shift right. +let neverHasSideEffects = 1 in { + def SRL : ShiftRS <"srl", 0x88, srl, GR32, shift12only>; + def SRLG : ShiftRSY<"srlg", 0xEB0C, srl, GR64, shift20only>; +} + +// Arithmetic shift right. +let Defs = [PSW] in { + def SRA : ShiftRS <"sra", 0x8A, sra, GR32, shift12only>; + def SRAG : ShiftRSY<"srag", 0xEB0A, sra, GR64, shift20only>; +} + +// Rotate left. +let neverHasSideEffects = 1 in { + def RLL : ShiftRSY<"rll", 0xEB1D, rotl, GR32, shift20only>; + def RLLG : ShiftRSY<"rllg", 0xEB1C, rotl, GR64, shift20only>; +} + +// Rotate second operand left and inserted selected bits into first operand. +// These can act like 32-bit operands provided that the constant start and +// end bits (operands 2 and 3) are in the range [32, 64) +let Defs = [PSW] in { + let isCodeGenOnly = 1 in + def RISBG32 : RotateSelectRIEf<"risbg", 0xEC55, GR32, GR32>; + def RISBG : RotateSelectRIEf<"risbg", 0xEC55, GR64, GR64>; +} + +//===----------------------------------------------------------------------===// +// Comparison +//===----------------------------------------------------------------------===// + +// Signed comparisons. +let Defs = [PSW] in { + // Comparison with a register. + def CR : CompareRR <"cr", 0x19, z_cmp, GR32, GR32>; + def CGFR : CompareRRE<"cgfr", 0xB930, null_frag, GR64, GR32>; + def CGR : CompareRRE<"cgr", 0xB920, z_cmp, GR64, GR64>; + + // Comparison with a signed 16-bit immediate. + def CHI : CompareRI<"chi", 0xA7E, z_cmp, GR32, imm32sx16>; + def CGHI : CompareRI<"cghi", 0xA7F, z_cmp, GR64, imm64sx16>; + + // Comparison with a signed 32-bit immediate. + def CFI : CompareRIL<"cfi", 0xC2D, z_cmp, GR32, simm32>; + def CGFI : CompareRIL<"cgfi", 0xC2C, z_cmp, GR64, imm64sx32>; + + // Comparison with memory. + defm CH : CompareRXPair<"ch", 0x49, 0xE379, z_cmp, GR32, sextloadi16>; + defm C : CompareRXPair<"c", 0x59, 0xE359, z_cmp, GR32, load>; + def CGH : CompareRXY<"cgh", 0xE334, z_cmp, GR64, sextloadi16>; + def CGF : CompareRXY<"cgf", 0xE330, z_cmp, GR64, sextloadi32>; + def CG : CompareRXY<"cg", 0xE320, z_cmp, GR64, load>; + def CHRL : CompareRILPC<"chrl", 0xC65, z_cmp, GR32, aligned_sextloadi16>; + def CRL : CompareRILPC<"crl", 0xC6D, z_cmp, GR32, aligned_load>; + def CGHRL : CompareRILPC<"cghrl", 0xC64, z_cmp, GR64, aligned_sextloadi16>; + def CGFRL : CompareRILPC<"cgfrl", 0xC6C, z_cmp, GR64, aligned_sextloadi32>; + def CGRL : CompareRILPC<"cgrl", 0xC68, z_cmp, GR64, aligned_load>; + + // Comparison between memory and a signed 16-bit immediate. + def CHHSI : CompareSIL<"chhsi", 0xE554, z_cmp, sextloadi16, imm32sx16>; + def CHSI : CompareSIL<"chsi", 0xE55C, z_cmp, load, imm32sx16>; + def CGHSI : CompareSIL<"cghsi", 0xE558, z_cmp, load, imm64sx16>; +} +defm : SXB<z_cmp, GR64, CGFR>; + +// Unsigned comparisons. +let Defs = [PSW] in { + // Comparison with a register. + def CLR : CompareRR <"clr", 0x15, z_ucmp, GR32, GR32>; + def CLGFR : CompareRRE<"clgfr", 0xB931, null_frag, GR64, GR32>; + def CLGR : CompareRRE<"clgr", 0xB921, z_ucmp, GR64, GR64>; + + // Comparison with a signed 32-bit immediate. + def CLFI : CompareRIL<"clfi", 0xC2F, z_ucmp, GR32, uimm32>; + def CLGFI : CompareRIL<"clgfi", 0xC2E, z_ucmp, GR64, imm64zx32>; + + // Comparison with memory. + defm CL : CompareRXPair<"cl", 0x55, 0xE355, z_ucmp, GR32, load>; + def CLGF : CompareRXY<"clgf", 0xE331, z_ucmp, GR64, zextloadi32>; + def CLG : CompareRXY<"clg", 0xE321, z_ucmp, GR64, load>; + def CLHRL : CompareRILPC<"clhrl", 0xC67, z_ucmp, GR32, + aligned_zextloadi16>; + def CLRL : CompareRILPC<"clrl", 0xC6F, z_ucmp, GR32, + aligned_load>; + def CLGHRL : CompareRILPC<"clghrl", 0xC66, z_ucmp, GR64, + aligned_zextloadi16>; + def CLGFRL : CompareRILPC<"clgfrl", 0xC6E, z_ucmp, GR64, + aligned_zextloadi32>; + def CLGRL : CompareRILPC<"clgrl", 0xC6A, z_ucmp, GR64, + aligned_load>; + + // Comparison between memory and an unsigned 8-bit immediate. + defm CLI : CompareSIPair<"cli", 0x95, 0xEB55, z_ucmp, zextloadi8, imm32zx8>; + + // Comparison between memory and an unsigned 16-bit immediate. + def CLHHSI : CompareSIL<"clhhsi", 0xE555, z_ucmp, zextloadi16, imm32zx16>; + def CLFHSI : CompareSIL<"clfhsi", 0xE55D, z_ucmp, load, imm32zx16>; + def CLGHSI : CompareSIL<"clghsi", 0xE559, z_ucmp, load, imm64zx16>; +} +defm : ZXB<z_ucmp, GR64, CLGFR>; + +//===----------------------------------------------------------------------===// +// Atomic operations +//===----------------------------------------------------------------------===// + +def ATOMIC_SWAPW : AtomicLoadWBinaryReg<z_atomic_swapw>; +def ATOMIC_SWAP_32 : AtomicLoadBinaryReg32<atomic_swap_32>; +def ATOMIC_SWAP_64 : AtomicLoadBinaryReg64<atomic_swap_64>; + +def ATOMIC_LOADW_AR : AtomicLoadWBinaryReg<z_atomic_loadw_add>; +def ATOMIC_LOADW_AFI : AtomicLoadWBinaryImm<z_atomic_loadw_add, simm32>; +def ATOMIC_LOAD_AR : AtomicLoadBinaryReg32<atomic_load_add_32>; +def ATOMIC_LOAD_AHI : AtomicLoadBinaryImm32<atomic_load_add_32, imm32sx16>; +def ATOMIC_LOAD_AFI : AtomicLoadBinaryImm32<atomic_load_add_32, simm32>; +def ATOMIC_LOAD_AGR : AtomicLoadBinaryReg64<atomic_load_add_64>; +def ATOMIC_LOAD_AGHI : AtomicLoadBinaryImm64<atomic_load_add_64, imm64sx16>; +def ATOMIC_LOAD_AGFI : AtomicLoadBinaryImm64<atomic_load_add_64, imm64sx32>; + +def ATOMIC_LOADW_SR : AtomicLoadWBinaryReg<z_atomic_loadw_sub>; +def ATOMIC_LOAD_SR : AtomicLoadBinaryReg32<atomic_load_sub_32>; +def ATOMIC_LOAD_SGR : AtomicLoadBinaryReg64<atomic_load_sub_64>; + +def ATOMIC_LOADW_NR : AtomicLoadWBinaryReg<z_atomic_loadw_and>; +def ATOMIC_LOADW_NILH : AtomicLoadWBinaryImm<z_atomic_loadw_and, imm32lh16c>; +def ATOMIC_LOAD_NR : AtomicLoadBinaryReg32<atomic_load_and_32>; +def ATOMIC_LOAD_NILL32 : AtomicLoadBinaryImm32<atomic_load_and_32, imm32ll16c>; +def ATOMIC_LOAD_NILH32 : AtomicLoadBinaryImm32<atomic_load_and_32, imm32lh16c>; +def ATOMIC_LOAD_NILF32 : AtomicLoadBinaryImm32<atomic_load_and_32, uimm32>; +def ATOMIC_LOAD_NGR : AtomicLoadBinaryReg64<atomic_load_and_64>; +def ATOMIC_LOAD_NILL : AtomicLoadBinaryImm64<atomic_load_and_64, imm64ll16c>; +def ATOMIC_LOAD_NILH : AtomicLoadBinaryImm64<atomic_load_and_64, imm64lh16c>; +def ATOMIC_LOAD_NIHL : AtomicLoadBinaryImm64<atomic_load_and_64, imm64hl16c>; +def ATOMIC_LOAD_NIHH : AtomicLoadBinaryImm64<atomic_load_and_64, imm64hh16c>; +def ATOMIC_LOAD_NILF : AtomicLoadBinaryImm64<atomic_load_and_64, imm64lf32c>; +def ATOMIC_LOAD_NIHF : AtomicLoadBinaryImm64<atomic_load_and_64, imm64hf32c>; + +def ATOMIC_LOADW_OR : AtomicLoadWBinaryReg<z_atomic_loadw_or>; +def ATOMIC_LOADW_OILH : AtomicLoadWBinaryImm<z_atomic_loadw_or, imm32lh16>; +def ATOMIC_LOAD_OR : AtomicLoadBinaryReg32<atomic_load_or_32>; +def ATOMIC_LOAD_OILL32 : AtomicLoadBinaryImm32<atomic_load_or_32, imm32ll16>; +def ATOMIC_LOAD_OILH32 : AtomicLoadBinaryImm32<atomic_load_or_32, imm32lh16>; +def ATOMIC_LOAD_OILF32 : AtomicLoadBinaryImm32<atomic_load_or_32, uimm32>; +def ATOMIC_LOAD_OGR : AtomicLoadBinaryReg64<atomic_load_or_64>; +def ATOMIC_LOAD_OILL : AtomicLoadBinaryImm64<atomic_load_or_64, imm64ll16>; +def ATOMIC_LOAD_OILH : AtomicLoadBinaryImm64<atomic_load_or_64, imm64lh16>; +def ATOMIC_LOAD_OIHL : AtomicLoadBinaryImm64<atomic_load_or_64, imm64hl16>; +def ATOMIC_LOAD_OIHH : AtomicLoadBinaryImm64<atomic_load_or_64, imm64hh16>; +def ATOMIC_LOAD_OILF : AtomicLoadBinaryImm64<atomic_load_or_64, imm64lf32>; +def ATOMIC_LOAD_OIHF : AtomicLoadBinaryImm64<atomic_load_or_64, imm64hf32>; + +def ATOMIC_LOADW_XR : AtomicLoadWBinaryReg<z_atomic_loadw_xor>; +def ATOMIC_LOADW_XILF : AtomicLoadWBinaryImm<z_atomic_loadw_xor, uimm32>; +def ATOMIC_LOAD_XR : AtomicLoadBinaryReg32<atomic_load_xor_32>; +def ATOMIC_LOAD_XILF32 : AtomicLoadBinaryImm32<atomic_load_xor_32, uimm32>; +def ATOMIC_LOAD_XGR : AtomicLoadBinaryReg64<atomic_load_xor_64>; +def ATOMIC_LOAD_XILF : AtomicLoadBinaryImm64<atomic_load_xor_64, imm64lf32>; +def ATOMIC_LOAD_XIHF : AtomicLoadBinaryImm64<atomic_load_xor_64, imm64hf32>; + +def ATOMIC_LOADW_NRi : AtomicLoadWBinaryReg<z_atomic_loadw_nand>; +def ATOMIC_LOADW_NILHi : AtomicLoadWBinaryImm<z_atomic_loadw_nand, + imm32lh16c>; +def ATOMIC_LOAD_NRi : AtomicLoadBinaryReg32<atomic_load_nand_32>; +def ATOMIC_LOAD_NILL32i : AtomicLoadBinaryImm32<atomic_load_nand_32, + imm32ll16c>; +def ATOMIC_LOAD_NILH32i : AtomicLoadBinaryImm32<atomic_load_nand_32, + imm32lh16c>; +def ATOMIC_LOAD_NILF32i : AtomicLoadBinaryImm32<atomic_load_nand_32, uimm32>; +def ATOMIC_LOAD_NGRi : AtomicLoadBinaryReg64<atomic_load_nand_64>; +def ATOMIC_LOAD_NILLi : AtomicLoadBinaryImm64<atomic_load_nand_64, + imm64ll16c>; +def ATOMIC_LOAD_NILHi : AtomicLoadBinaryImm64<atomic_load_nand_64, + imm64lh16c>; +def ATOMIC_LOAD_NIHLi : AtomicLoadBinaryImm64<atomic_load_nand_64, + imm64hl16c>; +def ATOMIC_LOAD_NIHHi : AtomicLoadBinaryImm64<atomic_load_nand_64, + imm64hh16c>; +def ATOMIC_LOAD_NILFi : AtomicLoadBinaryImm64<atomic_load_nand_64, + imm64lf32c>; +def ATOMIC_LOAD_NIHFi : AtomicLoadBinaryImm64<atomic_load_nand_64, + imm64hf32c>; + +def ATOMIC_LOADW_MIN : AtomicLoadWBinaryReg<z_atomic_loadw_min>; +def ATOMIC_LOAD_MIN_32 : AtomicLoadBinaryReg32<atomic_load_min_32>; +def ATOMIC_LOAD_MIN_64 : AtomicLoadBinaryReg64<atomic_load_min_64>; + +def ATOMIC_LOADW_MAX : AtomicLoadWBinaryReg<z_atomic_loadw_max>; +def ATOMIC_LOAD_MAX_32 : AtomicLoadBinaryReg32<atomic_load_max_32>; +def ATOMIC_LOAD_MAX_64 : AtomicLoadBinaryReg64<atomic_load_max_64>; + +def ATOMIC_LOADW_UMIN : AtomicLoadWBinaryReg<z_atomic_loadw_umin>; +def ATOMIC_LOAD_UMIN_32 : AtomicLoadBinaryReg32<atomic_load_umin_32>; +def ATOMIC_LOAD_UMIN_64 : AtomicLoadBinaryReg64<atomic_load_umin_64>; + +def ATOMIC_LOADW_UMAX : AtomicLoadWBinaryReg<z_atomic_loadw_umax>; +def ATOMIC_LOAD_UMAX_32 : AtomicLoadBinaryReg32<atomic_load_umax_32>; +def ATOMIC_LOAD_UMAX_64 : AtomicLoadBinaryReg64<atomic_load_umax_64>; + +def ATOMIC_CMP_SWAPW + : Pseudo<(outs GR32:$dst), (ins bdaddr20only:$addr, GR32:$cmp, GR32:$swap, + ADDR32:$bitshift, ADDR32:$negbitshift, + uimm32:$bitsize), + [(set GR32:$dst, + (z_atomic_cmp_swapw bdaddr20only:$addr, GR32:$cmp, GR32:$swap, + ADDR32:$bitshift, ADDR32:$negbitshift, + uimm32:$bitsize))]> { + let Defs = [PSW]; + let mayLoad = 1; + let mayStore = 1; + let usesCustomInserter = 1; +} + +let Defs = [PSW] in { + defm CS : CmpSwapRSPair<"cs", 0xBA, 0xEB14, atomic_cmp_swap_32, GR32>; + def CSG : CmpSwapRSY<"csg", 0xEB30, atomic_cmp_swap_64, GR64>; +} + +//===----------------------------------------------------------------------===// +// Miscellaneous Instructions. +//===----------------------------------------------------------------------===// + +// Read a 32-bit access register into a GR32. As with all GR32 operations, +// the upper 32 bits of the enclosing GR64 remain unchanged, which is useful +// when a 64-bit address is stored in a pair of access registers. +def EAR : InstRRE<0xB24F, (outs GR32:$dst), (ins access_reg:$src), + "ear\t$dst, $src", + [(set GR32:$dst, (z_extract_access access_reg:$src))]>; + +// Find leftmost one, AKA count leading zeros. The instruction actually +// returns a pair of GR64s, the first giving the number of leading zeros +// and the second giving a copy of the source with the leftmost one bit +// cleared. We only use the first result here. +let Defs = [PSW] in { + def FLOGR : UnaryRRE<"flogr", 0xB983, null_frag, GR128, GR64>; +} +def : Pat<(ctlz GR64:$src), + (EXTRACT_SUBREG (FLOGR GR64:$src), subreg_high)>; + +// Use subregs to populate the "don't care" bits in a 32-bit to 64-bit anyext. +def : Pat<(i64 (anyext GR32:$src)), + (INSERT_SUBREG (i64 (IMPLICIT_DEF)), GR32:$src, subreg_32bit)>; + +// There are no 32-bit equivalents of LLILL and LLILH, so use a full +// 64-bit move followed by a subreg. This preserves the invariant that +// all GR32 operations only modify the low 32 bits. +def : Pat<(i32 imm32ll16:$src), + (EXTRACT_SUBREG (LLILL (LL16 imm:$src)), subreg_32bit)>; +def : Pat<(i32 imm32lh16:$src), + (EXTRACT_SUBREG (LLILH (LH16 imm:$src)), subreg_32bit)>; + +// Extend GR32s and GR64s to GR128s. +let usesCustomInserter = 1 in { + def AEXT128_64 : Pseudo<(outs GR128:$dst), (ins GR64:$src), []>; + def ZEXT128_32 : Pseudo<(outs GR128:$dst), (ins GR32:$src), []>; + def ZEXT128_64 : Pseudo<(outs GR128:$dst), (ins GR64:$src), []>; +} + +//===----------------------------------------------------------------------===// +// Peepholes. +//===----------------------------------------------------------------------===// + +// Use AL* for GR64 additions of unsigned 32-bit values. +defm : ZXB<add, GR64, ALGFR>; +def : Pat<(add GR64:$src1, imm64zx32:$src2), + (ALGFI GR64:$src1, imm64zx32:$src2)>; +def : Pat<(add GR64:$src1, (zextloadi32 bdxaddr20only:$addr)), + (ALGF GR64:$src1, bdxaddr20only:$addr)>; + +// Use SL* for GR64 subtractions of unsigned 32-bit values. +defm : ZXB<sub, GR64, SLGFR>; +def : Pat<(add GR64:$src1, imm64zx32n:$src2), + (SLGFI GR64:$src1, imm64zx32n:$src2)>; +def : Pat<(sub GR64:$src1, (zextloadi32 bdxaddr20only:$addr)), + (SLGF GR64:$src1, bdxaddr20only:$addr)>; diff --git a/lib/Target/SystemZ/SystemZMCInstLower.cpp b/lib/Target/SystemZ/SystemZMCInstLower.cpp new file mode 100644 index 0000000000..5d833213e6 --- /dev/null +++ b/lib/Target/SystemZ/SystemZMCInstLower.cpp @@ -0,0 +1,116 @@ +//===-- SystemZMCInstLower.cpp - Lower MachineInstr to MCInst -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SystemZMCInstLower.h" +#include "SystemZAsmPrinter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Target/Mangler.h" + +using namespace llvm; + +// Where relaxable pairs of reloc-generating instructions exist, +// we tend to use the longest form by default, since that produces +// correct assembly in cases where no relaxation is performed. +// If Opcode is one such instruction, return the opcode for the +// shortest possible form instead, otherwise return Opcode itself. +static unsigned getShortenedInstr(unsigned Opcode) { + switch (Opcode) { + case SystemZ::BRCL: return SystemZ::BRC; + case SystemZ::JG: return SystemZ::J; + case SystemZ::BRASL: return SystemZ::BRAS; + } + return Opcode; +} + +// Return the VK_* enumeration for MachineOperand target flags Flags. +static MCSymbolRefExpr::VariantKind getVariantKind(unsigned Flags) { + switch (Flags & SystemZII::MO_SYMBOL_MODIFIER) { + case 0: + return MCSymbolRefExpr::VK_None; + case SystemZII::MO_GOT: + return MCSymbolRefExpr::VK_GOT; + } + llvm_unreachable("Unrecognised MO_ACCESS_MODEL"); +} + +SystemZMCInstLower::SystemZMCInstLower(Mangler *mang, MCContext &ctx, + SystemZAsmPrinter &asmprinter) + : Mang(mang), Ctx(ctx), AsmPrinter(asmprinter) {} + +MCOperand SystemZMCInstLower::lowerSymbolOperand(const MachineOperand &MO, + const MCSymbol *Symbol, + int64_t Offset) const { + MCSymbolRefExpr::VariantKind Kind = getVariantKind(MO.getTargetFlags()); + const MCExpr *Expr = MCSymbolRefExpr::Create(Symbol, Kind, Ctx); + if (Offset) { + const MCExpr *OffsetExpr = MCConstantExpr::Create(Offset, Ctx); + Expr = MCBinaryExpr::CreateAdd(Expr, OffsetExpr, Ctx); + } + return MCOperand::CreateExpr(Expr); +} + +MCOperand SystemZMCInstLower::lowerOperand(const MachineOperand &MO) const { + switch (MO.getType()) { + default: + llvm_unreachable("unknown operand type"); + + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) + return MCOperand(); + return MCOperand::CreateReg(MO.getReg()); + + case MachineOperand::MO_Immediate: + return MCOperand::CreateImm(MO.getImm()); + + case MachineOperand::MO_MachineBasicBlock: + return lowerSymbolOperand(MO, MO.getMBB()->getSymbol(), + /* MO has no offset field */0); + + case MachineOperand::MO_GlobalAddress: + return lowerSymbolOperand(MO, Mang->getSymbol(MO.getGlobal()), + MO.getOffset()); + + case MachineOperand::MO_ExternalSymbol: { + StringRef Name = MO.getSymbolName(); + return lowerSymbolOperand(MO, AsmPrinter.GetExternalSymbolSymbol(Name), + MO.getOffset()); + } + + case MachineOperand::MO_JumpTableIndex: + return lowerSymbolOperand(MO, AsmPrinter.GetJTISymbol(MO.getIndex()), + /* MO has no offset field */0); + + case MachineOperand::MO_ConstantPoolIndex: + return lowerSymbolOperand(MO, AsmPrinter.GetCPISymbol(MO.getIndex()), + MO.getOffset()); + + case MachineOperand::MO_BlockAddress: { + const BlockAddress *BA = MO.getBlockAddress(); + return lowerSymbolOperand(MO, AsmPrinter.GetBlockAddressSymbol(BA), + MO.getOffset()); + } + } +} + +void SystemZMCInstLower::lower(const MachineInstr *MI, MCInst &OutMI) const { + unsigned Opcode = MI->getOpcode(); + // When emitting binary code, start with the shortest form of an instruction + // and then relax it where necessary. + if (!AsmPrinter.OutStreamer.hasRawTextSupport()) + Opcode = getShortenedInstr(Opcode); + OutMI.setOpcode(Opcode); + for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) { + const MachineOperand &MO = MI->getOperand(I); + MCOperand MCOp = lowerOperand(MO); + if (MCOp.isValid()) + OutMI.addOperand(MCOp); + } +} diff --git a/lib/Target/SystemZ/SystemZMCInstLower.h b/lib/Target/SystemZ/SystemZMCInstLower.h new file mode 100644 index 0000000000..afa72f38ad --- /dev/null +++ b/lib/Target/SystemZ/SystemZMCInstLower.h @@ -0,0 +1,47 @@ +//===-- SystemZMCInstLower.h - Lower MachineInstr to MCInst ----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEMZMCINSTLOWER_H +#define LLVM_SYSTEMZMCINSTLOWER_H + +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { +class MCContext; +class MCInst; +class MCOperand; +class MCSymbol; +class MachineInstr; +class MachineOperand; +class Mangler; +class SystemZAsmPrinter; + +class LLVM_LIBRARY_VISIBILITY SystemZMCInstLower { + Mangler *Mang; + MCContext &Ctx; + SystemZAsmPrinter &AsmPrinter; + +public: + SystemZMCInstLower(Mangler *mang, MCContext &ctx, + SystemZAsmPrinter &asmPrinter); + + // Lower MachineInstr MI to MCInst OutMI. + void lower(const MachineInstr *MI, MCInst &OutMI) const; + + // Return an MCOperand for MO. Return an empty operand if MO is implicit. + MCOperand lowerOperand(const MachineOperand& MO) const; + + // Return an MCOperand for MO, given that it equals Symbol + Offset. + MCOperand lowerSymbolOperand(const MachineOperand &MO, + const MCSymbol *Symbol, int64_t Offset) const; +}; +} // end namespace llvm + +#endif diff --git a/lib/Target/SystemZ/SystemZMachineFunctionInfo.h b/lib/Target/SystemZ/SystemZMachineFunctionInfo.h new file mode 100644 index 0000000000..1dc05a7e12 --- /dev/null +++ b/lib/Target/SystemZ/SystemZMachineFunctionInfo.h @@ -0,0 +1,74 @@ +//==- 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. +// +//===----------------------------------------------------------------------===// + +#ifndef SYSTEMZMACHINEFUNCTIONINFO_H +#define SYSTEMZMACHINEFUNCTIONINFO_H + +#include "llvm/CodeGen/MachineFunction.h" + +namespace llvm { + +class SystemZMachineFunctionInfo : public MachineFunctionInfo { + unsigned SavedGPRFrameSize; + unsigned LowSavedGPR; + unsigned HighSavedGPR; + unsigned VarArgsFirstGPR; + unsigned VarArgsFirstFPR; + unsigned VarArgsFrameIndex; + unsigned RegSaveFrameIndex; + bool ManipulatesSP; + +public: + explicit SystemZMachineFunctionInfo(MachineFunction &MF) + : SavedGPRFrameSize(0), LowSavedGPR(0), HighSavedGPR(0), VarArgsFirstGPR(0), + VarArgsFirstFPR(0), VarArgsFrameIndex(0), RegSaveFrameIndex(0), + ManipulatesSP(false) {} + + // Get and set the number of bytes allocated by generic code to store + // call-saved GPRs. + unsigned getSavedGPRFrameSize() const { return SavedGPRFrameSize; } + void setSavedGPRFrameSize(unsigned bytes) { SavedGPRFrameSize = bytes; } + + // Get and set the first call-saved GPR that should be saved and restored + // by this function. This is 0 if no GPRs need to be saved or restored. + unsigned getLowSavedGPR() const { return LowSavedGPR; } + void setLowSavedGPR(unsigned Reg) { LowSavedGPR = Reg; } + + // Get and set the last call-saved GPR that should be saved and restored + // by this function. + unsigned getHighSavedGPR() const { return HighSavedGPR; } + void setHighSavedGPR(unsigned Reg) { HighSavedGPR = Reg; } + + // Get and set the number of fixed (as opposed to variable) arguments + // that are passed in GPRs to this function. + unsigned getVarArgsFirstGPR() const { return VarArgsFirstGPR; } + void setVarArgsFirstGPR(unsigned GPR) { VarArgsFirstGPR = GPR; } + + // Likewise FPRs. + unsigned getVarArgsFirstFPR() const { return VarArgsFirstFPR; } + void setVarArgsFirstFPR(unsigned FPR) { VarArgsFirstFPR = FPR; } + + // Get and set the frame index of the first stack vararg. + unsigned getVarArgsFrameIndex() const { return VarArgsFrameIndex; } + void setVarArgsFrameIndex(unsigned FI) { VarArgsFrameIndex = FI; } + + // Get and set the frame index of the register save area + // (i.e. the incoming stack pointer). + unsigned getRegSaveFrameIndex() const { return RegSaveFrameIndex; } + void setRegSaveFrameIndex(unsigned FI) { RegSaveFrameIndex = FI; } + + // Get and set whether the function directly manipulates the stack pointer, + // e.g. through STACKSAVE or STACKRESTORE. + bool getManipulatesSP() const { return ManipulatesSP; } + void setManipulatesSP(bool MSP) { ManipulatesSP = MSP; } +}; + +} // end llvm namespace + +#endif diff --git a/lib/Target/SystemZ/SystemZOperands.td b/lib/Target/SystemZ/SystemZOperands.td new file mode 100644 index 0000000000..0abc3f7517 --- /dev/null +++ b/lib/Target/SystemZ/SystemZOperands.td @@ -0,0 +1,435 @@ +//===-- SystemZOperands.td - SystemZ instruction operands ----*- tblgen-*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Class definitions +//===----------------------------------------------------------------------===// + +class ImmediateAsmOperand<string name> + : AsmOperandClass { + let Name = name; + let RenderMethod = "addImmOperands"; +} + +// Constructs both a DAG pattern and instruction operand for an immediate +// of type VT. PRED returns true if a node is acceptable and XFORM returns +// the operand value associated with the node. ASMOP is the name of the +// associated asm operand, and also forms the basis of the asm print method. +class Immediate<ValueType vt, code pred, SDNodeXForm xform, string asmop> + : PatLeaf<(vt imm), pred, xform>, Operand<vt> { + let PrintMethod = "print"##asmop##"Operand"; + let ParserMatchClass = !cast<AsmOperandClass>(asmop); +} + +// Constructs both a DAG pattern and instruction operand for a PC-relative +// address with address size VT. SELF is the name of the operand. +class PCRelAddress<ValueType vt, string self> + : ComplexPattern<vt, 1, "selectPCRelAddress", [z_pcrel_wrapper]>, + Operand<vt> { + let MIOperandInfo = (ops !cast<Operand>(self)); +} + +// Constructs an AsmOperandClass for addressing mode FORMAT, treating the +// registers as having BITSIZE bits and displacements as having DISPSIZE bits. +class AddressAsmOperand<string format, string bitsize, string dispsize> + : AsmOperandClass { + let Name = format##bitsize##"Disp"##dispsize; + let ParserMethod = "parse"##format##bitsize; + let RenderMethod = "add"##format##"Operands"; +} + +// Constructs both a DAG pattern and instruction operand for an addressing mode. +// The mode is selected by custom code in selectTYPE...SUFFIX(). The address +// registers have BITSIZE bits and displacements have DISPSIZE bits. NUMOPS is +// the number of operands that make up an address and OPERANDS lists the types +// of those operands using (ops ...). FORMAT is the type of addressing mode, +// which needs to match the names used in AddressAsmOperand. +class AddressingMode<string type, string bitsize, string dispsize, + string suffix, int numops, string format, dag operands> + : ComplexPattern<!cast<ValueType>("i"##bitsize), numops, + "select"##type##dispsize##suffix, + [add, sub, or, frameindex, z_adjdynalloc]>, + Operand<!cast<ValueType>("i"##bitsize)> { + let PrintMethod = "print"##format##"Operand"; + let MIOperandInfo = operands; + let ParserMatchClass = + !cast<AddressAsmOperand>(format##bitsize##"Disp"##dispsize); +} + +// An addressing mode with a base and displacement but no index. +class BDMode<string type, string bitsize, string dispsize, string suffix> + : AddressingMode<type, bitsize, dispsize, suffix, 2, "BDAddr", + (ops !cast<RegisterOperand>("ADDR"##bitsize), + !cast<Immediate>("disp"##dispsize##"imm"##bitsize))>; + +// An addressing mode with a base, displacement and index. +class BDXMode<string type, string bitsize, string dispsize, string suffix> + : AddressingMode<type, bitsize, dispsize, suffix, 3, "BDXAddr", + (ops !cast<RegisterOperand>("ADDR"##bitsize), + !cast<Immediate>("disp"##dispsize##"imm"##bitsize), + !cast<RegisterOperand>("ADDR"##bitsize))>; + +//===----------------------------------------------------------------------===// +// Extracting immediate operands from nodes +// These all create MVT::i64 nodes to ensure the value is not sign-extended +// when converted from an SDNode to a MachineOperand later on. +//===----------------------------------------------------------------------===// + +// Bits 0-15 (counting from the lsb). +def LL16 : SDNodeXForm<imm, [{ + uint64_t Value = N->getZExtValue() & 0x000000000000FFFFULL; + return CurDAG->getTargetConstant(Value, MVT::i64); +}]>; + +// Bits 16-31 (counting from the lsb). +def LH16 : SDNodeXForm<imm, [{ + uint64_t Value = (N->getZExtValue() & 0x00000000FFFF0000ULL) >> 16; + return CurDAG->getTargetConstant(Value, MVT::i64); +}]>; + +// Bits 32-47 (counting from the lsb). +def HL16 : SDNodeXForm<imm, [{ + uint64_t Value = (N->getZExtValue() & 0x0000FFFF00000000ULL) >> 32; + return CurDAG->getTargetConstant(Value, MVT::i64); +}]>; + +// Bits 48-63 (counting from the lsb). +def HH16 : SDNodeXForm<imm, [{ + uint64_t Value = (N->getZExtValue() & 0xFFFF000000000000ULL) >> 48; + return CurDAG->getTargetConstant(Value, MVT::i64); +}]>; + +// Low 32 bits. +def LF32 : SDNodeXForm<imm, [{ + uint64_t Value = N->getZExtValue() & 0x00000000FFFFFFFFULL; + return CurDAG->getTargetConstant(Value, MVT::i64); +}]>; + +// High 32 bits. +def HF32 : SDNodeXForm<imm, [{ + uint64_t Value = N->getZExtValue() >> 32; + return CurDAG->getTargetConstant(Value, MVT::i64); +}]>; + +// Truncate an immediate to a 8-bit signed quantity. +def SIMM8 : SDNodeXForm<imm, [{ + return CurDAG->getTargetConstant(int8_t(N->getZExtValue()), MVT::i64); +}]>; + +// Truncate an immediate to a 8-bit unsigned quantity. +def UIMM8 : SDNodeXForm<imm, [{ + return CurDAG->getTargetConstant(uint8_t(N->getZExtValue()), MVT::i64); +}]>; + +// Truncate an immediate to a 16-bit signed quantity. +def SIMM16 : SDNodeXForm<imm, [{ + return CurDAG->getTargetConstant(int16_t(N->getZExtValue()), MVT::i64); +}]>; + +// Truncate an immediate to a 16-bit unsigned quantity. +def UIMM16 : SDNodeXForm<imm, [{ + return CurDAG->getTargetConstant(uint16_t(N->getZExtValue()), MVT::i64); +}]>; + +// Truncate an immediate to a 32-bit signed quantity. +def SIMM32 : SDNodeXForm<imm, [{ + return CurDAG->getTargetConstant(int32_t(N->getZExtValue()), MVT::i64); +}]>; + +// Truncate an immediate to a 32-bit unsigned quantity. +def UIMM32 : SDNodeXForm<imm, [{ + return CurDAG->getTargetConstant(uint32_t(N->getZExtValue()), MVT::i64); +}]>; + +// Negate and then truncate an immediate to a 32-bit unsigned quantity. +def NEGIMM32 : SDNodeXForm<imm, [{ + return CurDAG->getTargetConstant(uint32_t(-N->getZExtValue()), MVT::i64); +}]>; + +//===----------------------------------------------------------------------===// +// Immediate asm operands. +//===----------------------------------------------------------------------===// + +def U4Imm : ImmediateAsmOperand<"U4Imm">; +def U6Imm : ImmediateAsmOperand<"U6Imm">; +def S8Imm : ImmediateAsmOperand<"S8Imm">; +def U8Imm : ImmediateAsmOperand<"U8Imm">; +def S16Imm : ImmediateAsmOperand<"S16Imm">; +def U16Imm : ImmediateAsmOperand<"U16Imm">; +def S32Imm : ImmediateAsmOperand<"S32Imm">; +def U32Imm : ImmediateAsmOperand<"U32Imm">; + +//===----------------------------------------------------------------------===// +// 8-bit immediates +//===----------------------------------------------------------------------===// + +def uimm8zx4 : Immediate<i8, [{ + return isUInt<4>(N->getZExtValue()); +}], NOOP_SDNodeXForm, "U4Imm">; + +def uimm8zx6 : Immediate<i8, [{ + return isUInt<6>(N->getZExtValue()); +}], NOOP_SDNodeXForm, "U6Imm">; + +def simm8 : Immediate<i8, [{}], SIMM8, "S8Imm">; +def uimm8 : Immediate<i8, [{}], UIMM8, "U8Imm">; + +//===----------------------------------------------------------------------===// +// i32 immediates +//===----------------------------------------------------------------------===// + +// Immediates for the lower and upper 16 bits of an i32, with the other +// bits of the i32 being zero. +def imm32ll16 : Immediate<i32, [{ + return SystemZ::isImmLL(N->getZExtValue()); +}], LL16, "U16Imm">; + +def imm32lh16 : Immediate<i32, [{ + return SystemZ::isImmLH(N->getZExtValue()); +}], LH16, "U16Imm">; + +// Immediates for the lower and upper 16 bits of an i32, with the other +// bits of the i32 being one. +def imm32ll16c : Immediate<i32, [{ + return SystemZ::isImmLL(uint32_t(~N->getZExtValue())); +}], LL16, "U16Imm">; + +def imm32lh16c : Immediate<i32, [{ + return SystemZ::isImmLH(uint32_t(~N->getZExtValue())); +}], LH16, "U16Imm">; + +// Short immediates +def imm32sx8 : Immediate<i32, [{ + return isInt<8>(N->getSExtValue()); +}], SIMM8, "S8Imm">; + +def imm32zx8 : Immediate<i32, [{ + return isUInt<8>(N->getZExtValue()); +}], UIMM8, "U8Imm">; + +def imm32zx8trunc : Immediate<i32, [{}], UIMM8, "U8Imm">; + +def imm32sx16 : Immediate<i32, [{ + return isInt<16>(N->getSExtValue()); +}], SIMM16, "S16Imm">; + +def imm32zx16 : Immediate<i32, [{ + return isUInt<16>(N->getZExtValue()); +}], UIMM16, "U16Imm">; + +def imm32sx16trunc : Immediate<i32, [{}], SIMM16, "S16Imm">; + +// Full 32-bit immediates. we need both signed and unsigned versions +// because the assembler is picky. E.g. AFI requires signed operands +// while NILF requires unsigned ones. +def simm32 : Immediate<i32, [{}], SIMM32, "S32Imm">; +def uimm32 : Immediate<i32, [{}], UIMM32, "U32Imm">; + +def imm32 : ImmLeaf<i32, [{}]>; + +//===----------------------------------------------------------------------===// +// 64-bit immediates +//===----------------------------------------------------------------------===// + +// Immediates for 16-bit chunks of an i64, with the other bits of the +// i32 being zero. +def imm64ll16 : Immediate<i64, [{ + return SystemZ::isImmLL(N->getZExtValue()); +}], LL16, "U16Imm">; + +def imm64lh16 : Immediate<i64, [{ + return SystemZ::isImmLH(N->getZExtValue()); +}], LH16, "U16Imm">; + +def imm64hl16 : Immediate<i64, [{ + return SystemZ::isImmHL(N->getZExtValue()); +}], HL16, "U16Imm">; + +def imm64hh16 : Immediate<i64, [{ + return SystemZ::isImmHH(N->getZExtValue()); +}], HH16, "U16Imm">; + +// Immediates for 16-bit chunks of an i64, with the other bits of the +// i32 being one. +def imm64ll16c : Immediate<i64, [{ + return SystemZ::isImmLL(uint64_t(~N->getZExtValue())); +}], LL16, "U16Imm">; + +def imm64lh16c : Immediate<i64, [{ + return SystemZ::isImmLH(uint64_t(~N->getZExtValue())); +}], LH16, "U16Imm">; + +def imm64hl16c : Immediate<i64, [{ + return SystemZ::isImmHL(uint64_t(~N->getZExtValue())); +}], HL16, "U16Imm">; + +def imm64hh16c : Immediate<i64, [{ + return SystemZ::isImmHH(uint64_t(~N->getZExtValue())); +}], HH16, "U16Imm">; + +// Immediates for the lower and upper 32 bits of an i64, with the other +// bits of the i32 being zero. +def imm64lf32 : Immediate<i64, [{ + return SystemZ::isImmLF(N->getZExtValue()); +}], LF32, "U32Imm">; + +def imm64hf32 : Immediate<i64, [{ + return SystemZ::isImmHF(N->getZExtValue()); +}], HF32, "U32Imm">; + +// Immediates for the lower and upper 32 bits of an i64, with the other +// bits of the i32 being one. +def imm64lf32c : Immediate<i64, [{ + return SystemZ::isImmLF(uint64_t(~N->getZExtValue())); +}], LF32, "U32Imm">; + +def imm64hf32c : Immediate<i64, [{ + return SystemZ::isImmHF(uint64_t(~N->getZExtValue())); +}], HF32, "U32Imm">; + +// Short immediates. +def imm64sx8 : Immediate<i64, [{ + return isInt<8>(N->getSExtValue()); +}], SIMM8, "S8Imm">; + +def imm64sx16 : Immediate<i64, [{ + return isInt<16>(N->getSExtValue()); +}], SIMM16, "S16Imm">; + +def imm64zx16 : Immediate<i64, [{ + return isUInt<16>(N->getZExtValue()); +}], UIMM16, "U16Imm">; + +def imm64sx32 : Immediate<i64, [{ + return isInt<32>(N->getSExtValue()); +}], SIMM32, "S32Imm">; + +def imm64zx32 : Immediate<i64, [{ + return isUInt<32>(N->getZExtValue()); +}], UIMM32, "U32Imm">; + +def imm64zx32n : Immediate<i64, [{ + return isUInt<32>(-N->getSExtValue()); +}], NEGIMM32, "U32Imm">; + +def imm64 : ImmLeaf<i64, [{}]>; + +//===----------------------------------------------------------------------===// +// Floating-point immediates +//===----------------------------------------------------------------------===// + +// Floating-point zero. +def fpimm0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(+0.0); }]>; + +// Floating point negative zero. +def fpimmneg0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(-0.0); }]>; + +//===----------------------------------------------------------------------===// +// Symbolic address operands +//===----------------------------------------------------------------------===// + +// PC-relative offsets of a basic block. The offset is sign-extended +// and multiplied by 2. +def brtarget16 : Operand<OtherVT> { + let EncoderMethod = "getPC16DBLEncoding"; +} +def brtarget32 : Operand<OtherVT> { + let EncoderMethod = "getPC32DBLEncoding"; +} + +// A PC-relative offset of a global value. The offset is sign-extended +// and multiplied by 2. +def pcrel32 : PCRelAddress<i64, "pcrel32"> { + let EncoderMethod = "getPC32DBLEncoding"; +} + +// A PC-relative offset of a global value when the value is used as a +// call target. The offset is sign-extended and multiplied by 2. +def pcrel16call : PCRelAddress<i64, "pcrel16call"> { + let PrintMethod = "printCallOperand"; + let EncoderMethod = "getPLT16DBLEncoding"; +} +def pcrel32call : PCRelAddress<i64, "pcrel32call"> { + let PrintMethod = "printCallOperand"; + let EncoderMethod = "getPLT32DBLEncoding"; +} + +//===----------------------------------------------------------------------===// +// Addressing modes +//===----------------------------------------------------------------------===// + +// 12-bit displacement operands. +def disp12imm32 : Operand<i32>; +def disp12imm64 : Operand<i64>; + +// 20-bit displacement operands. +def disp20imm32 : Operand<i32>; +def disp20imm64 : Operand<i64>; + +def BDAddr32Disp12 : AddressAsmOperand<"BDAddr", "32", "12">; +def BDAddr32Disp20 : AddressAsmOperand<"BDAddr", "32", "20">; +def BDAddr64Disp12 : AddressAsmOperand<"BDAddr", "64", "12">; +def BDAddr64Disp20 : AddressAsmOperand<"BDAddr", "64", "20">; +def BDXAddr64Disp12 : AddressAsmOperand<"BDXAddr", "64", "12">; +def BDXAddr64Disp20 : AddressAsmOperand<"BDXAddr", "64", "20">; + +// DAG patterns and operands for addressing modes. Each mode has +// the form <type><range><group> where: +// +// <type> is one of: +// shift : base + displacement (32-bit) +// bdaddr : base + displacement +// bdxaddr : base + displacement + index +// laaddr : like bdxaddr, but used for Load Address operations +// dynalloc : base + displacement + index + ADJDYNALLOC +// +// <range> is one of: +// 12 : the displacement is an unsigned 12-bit value +// 20 : the displacement is a signed 20-bit value +// +// <group> is one of: +// pair : used when there is an equivalent instruction with the opposite +// range value (12 or 20) +// only : used when there is no equivalent instruction with the opposite +// range value +def shift12only : BDMode <"BDAddr", "32", "12", "Only">; +def shift20only : BDMode <"BDAddr", "32", "20", "Only">; +def bdaddr12only : BDMode <"BDAddr", "64", "12", "Only">; +def bdaddr12pair : BDMode <"BDAddr", "64", "12", "Pair">; +def bdaddr20only : BDMode <"BDAddr", "64", "20", "Only">; +def bdaddr20pair : BDMode <"BDAddr", "64", "20", "Pair">; +def bdxaddr12only : BDXMode<"BDXAddr", "64", "12", "Only">; +def bdxaddr12pair : BDXMode<"BDXAddr", "64", "12", "Pair">; +def bdxaddr20only : BDXMode<"BDXAddr", "64", "20", "Only">; +def bdxaddr20only128 : BDXMode<"BDXAddr", "64", "20", "Only128">; +def bdxaddr20pair : BDXMode<"BDXAddr", "64", "20", "Pair">; +def dynalloc12only : BDXMode<"DynAlloc", "64", "12", "Only">; +def laaddr12pair : BDXMode<"LAAddr", "64", "12", "Pair">; +def laaddr20pair : BDXMode<"LAAddr", "64", "20", "Pair">; + +//===----------------------------------------------------------------------===// +// Miscellaneous +//===----------------------------------------------------------------------===// + +// Access registers. At present we just use them for accessing the thread +// pointer, so we don't expose them as register to LLVM. +def AccessReg : AsmOperandClass { + let Name = "AccessReg"; + let ParserMethod = "parseAccessReg"; +} +def access_reg : Immediate<i8, [{ return N->getZExtValue() < 16; }], + NOOP_SDNodeXForm, "AccessReg"> { + let ParserMatchClass = AccessReg; +} + +// A 4-bit condition-code mask. +def cond4 : PatLeaf<(i8 imm), [{ return (N->getZExtValue() < 16); }]>, + Operand<i8> { + let PrintMethod = "printCond4Operand"; +} diff --git a/lib/Target/SystemZ/SystemZOperators.td b/lib/Target/SystemZ/SystemZOperators.td new file mode 100644 index 0000000000..8c4df56b46 --- /dev/null +++ b/lib/Target/SystemZ/SystemZOperators.td @@ -0,0 +1,196 @@ +//===-- SystemZOperators.td - SystemZ-specific operators ------*- tblgen-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Type profiles +//===----------------------------------------------------------------------===// +def SDT_CallSeqStart : SDCallSeqStart<[SDTCisVT<0, i64>]>; +def SDT_CallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i64>, + SDTCisVT<1, i64>]>; +def SDT_ZCall : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>; +def SDT_ZCmp : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>; +def SDT_ZBRCCMask : SDTypeProfile<0, 2, + [SDTCisVT<0, i8>, + SDTCisVT<1, OtherVT>]>; +def SDT_ZSelectCCMask : SDTypeProfile<1, 3, + [SDTCisSameAs<0, 1>, + SDTCisSameAs<1, 2>, + SDTCisVT<3, i8>]>; +def SDT_ZWrapPtr : SDTypeProfile<1, 1, + [SDTCisSameAs<0, 1>, + SDTCisPtrTy<0>]>; +def SDT_ZAdjDynAlloc : SDTypeProfile<1, 0, [SDTCisVT<0, i64>]>; +def SDT_ZExtractAccess : SDTypeProfile<1, 1, + [SDTCisVT<0, i32>, + SDTCisVT<1, i8>]>; +def SDT_ZGR128Binary32 : SDTypeProfile<1, 2, + [SDTCisVT<0, untyped>, + SDTCisVT<1, untyped>, + SDTCisVT<2, i32>]>; +def SDT_ZGR128Binary64 : SDTypeProfile<1, 2, + [SDTCisVT<0, untyped>, + SDTCisVT<1, untyped>, + SDTCisVT<2, i64>]>; +def SDT_ZAtomicLoadBinaryW : SDTypeProfile<1, 5, + [SDTCisVT<0, i32>, + SDTCisPtrTy<1>, + SDTCisVT<2, i32>, + SDTCisVT<3, i32>, + SDTCisVT<4, i32>, + SDTCisVT<5, i32>]>; +def SDT_ZAtomicCmpSwapW : SDTypeProfile<1, 6, + [SDTCisVT<0, i32>, + SDTCisPtrTy<1>, + SDTCisVT<2, i32>, + SDTCisVT<3, i32>, + SDTCisVT<4, i32>, + SDTCisVT<5, i32>, + SDTCisVT<6, i32>]>; + +//===----------------------------------------------------------------------===// +// Node definitions +//===----------------------------------------------------------------------===// + +// These are target-independent nodes, but have target-specific formats. +def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_CallSeqStart, + [SDNPHasChain, SDNPSideEffect, SDNPOutGlue]>; +def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_CallSeqEnd, + [SDNPHasChain, SDNPSideEffect, SDNPOptInGlue, + SDNPOutGlue]>; + +// Nodes for SystemZISD::*. See SystemZISelLowering.h for more details. +def z_retflag : SDNode<"SystemZISD::RET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; +def z_call : SDNode<"SystemZISD::CALL", SDT_ZCall, + [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, + SDNPVariadic]>; +def z_pcrel_wrapper : SDNode<"SystemZISD::PCREL_WRAPPER", SDT_ZWrapPtr, []>; +def z_cmp : SDNode<"SystemZISD::CMP", SDT_ZCmp, [SDNPOutGlue]>; +def z_ucmp : SDNode<"SystemZISD::UCMP", SDT_ZCmp, [SDNPOutGlue]>; +def z_br_ccmask : SDNode<"SystemZISD::BR_CCMASK", SDT_ZBRCCMask, + [SDNPHasChain, SDNPInGlue]>; +def z_select_ccmask : SDNode<"SystemZISD::SELECT_CCMASK", SDT_ZSelectCCMask, + [SDNPInGlue]>; +def z_adjdynalloc : SDNode<"SystemZISD::ADJDYNALLOC", SDT_ZAdjDynAlloc>; +def z_extract_access : SDNode<"SystemZISD::EXTRACT_ACCESS", + SDT_ZExtractAccess>; +def z_umul_lohi64 : SDNode<"SystemZISD::UMUL_LOHI64", SDT_ZGR128Binary64>; +def z_sdivrem64 : SDNode<"SystemZISD::SDIVREM64", SDT_ZGR128Binary64>; +def z_udivrem32 : SDNode<"SystemZISD::UDIVREM32", SDT_ZGR128Binary32>; +def z_udivrem64 : SDNode<"SystemZISD::UDIVREM64", SDT_ZGR128Binary64>; + +class AtomicWOp<string name, SDTypeProfile profile = SDT_ZAtomicLoadBinaryW> + : SDNode<"SystemZISD::"##name, profile, + [SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>; + +def z_atomic_swapw : AtomicWOp<"ATOMIC_SWAPW">; +def z_atomic_loadw_add : AtomicWOp<"ATOMIC_LOADW_ADD">; +def z_atomic_loadw_sub : AtomicWOp<"ATOMIC_LOADW_SUB">; +def z_atomic_loadw_and : AtomicWOp<"ATOMIC_LOADW_AND">; +def z_atomic_loadw_or : AtomicWOp<"ATOMIC_LOADW_OR">; +def z_atomic_loadw_xor : AtomicWOp<"ATOMIC_LOADW_XOR">; +def z_atomic_loadw_nand : AtomicWOp<"ATOMIC_LOADW_NAND">; +def z_atomic_loadw_min : AtomicWOp<"ATOMIC_LOADW_MIN">; +def z_atomic_loadw_max : AtomicWOp<"ATOMIC_LOADW_MAX">; +def z_atomic_loadw_umin : AtomicWOp<"ATOMIC_LOADW_UMIN">; +def z_atomic_loadw_umax : AtomicWOp<"ATOMIC_LOADW_UMAX">; +def z_atomic_cmp_swapw : AtomicWOp<"ATOMIC_CMP_SWAPW", SDT_ZAtomicCmpSwapW>; + +//===----------------------------------------------------------------------===// +// Pattern fragments +//===----------------------------------------------------------------------===// + +// Register sign-extend operations. Sub-32-bit values are represented as i32s. +def sext8 : PatFrag<(ops node:$src), (sext_inreg node:$src, i8)>; +def sext16 : PatFrag<(ops node:$src), (sext_inreg node:$src, i16)>; +def sext32 : PatFrag<(ops node:$src), (sext (i32 node:$src))>; + +// Register zero-extend operations. Sub-32-bit values are represented as i32s. +def zext8 : PatFrag<(ops node:$src), (and node:$src, 0xff)>; +def zext16 : PatFrag<(ops node:$src), (and node:$src, 0xffff)>; +def zext32 : PatFrag<(ops node:$src), (zext (i32 node:$src))>; + +// Typed floating-point loads. +def loadf32 : PatFrag<(ops node:$src), (f32 (load node:$src))>; +def loadf64 : PatFrag<(ops node:$src), (f64 (load node:$src))>; + +// Aligned loads. +class AlignedLoad<SDPatternOperator load> + : PatFrag<(ops node:$addr), (load node:$addr), [{ + LoadSDNode *Load = cast<LoadSDNode>(N); + return Load->getAlignment() >= Load->getMemoryVT().getStoreSize(); +}]>; +def aligned_load : AlignedLoad<load>; +def aligned_sextloadi16 : AlignedLoad<sextloadi16>; +def aligned_sextloadi32 : AlignedLoad<sextloadi32>; +def aligned_zextloadi16 : AlignedLoad<zextloadi16>; +def aligned_zextloadi32 : AlignedLoad<zextloadi32>; + +// Aligned stores. +class AlignedStore<SDPatternOperator store> + : PatFrag<(ops node:$src, node:$addr), (store node:$src, node:$addr), [{ + StoreSDNode *Store = cast<StoreSDNode>(N); + return Store->getAlignment() >= Store->getMemoryVT().getStoreSize(); +}]>; +def aligned_store : AlignedStore<store>; +def aligned_truncstorei16 : AlignedStore<truncstorei16>; +def aligned_truncstorei32 : AlignedStore<truncstorei32>; + +// Insertions. +def inserti8 : PatFrag<(ops node:$src1, node:$src2), + (or (and node:$src1, -256), node:$src2)>; +def insertll : PatFrag<(ops node:$src1, node:$src2), + (or (and node:$src1, 0xffffffffffff0000), node:$src2)>; +def insertlh : PatFrag<(ops node:$src1, node:$src2), + (or (and node:$src1, 0xffffffff0000ffff), node:$src2)>; +def inserthl : PatFrag<(ops node:$src1, node:$src2), + (or (and node:$src1, 0xffff0000ffffffff), node:$src2)>; +def inserthh : PatFrag<(ops node:$src1, node:$src2), + (or (and node:$src1, 0x0000ffffffffffff), node:$src2)>; +def insertlf : PatFrag<(ops node:$src1, node:$src2), + (or (and node:$src1, 0xffffffff00000000), node:$src2)>; +def inserthf : PatFrag<(ops node:$src1, node:$src2), + (or (and node:$src1, 0x00000000ffffffff), node:$src2)>; + +// ORs that can be treated as insertions. +def or_as_inserti8 : PatFrag<(ops node:$src1, node:$src2), + (or node:$src1, node:$src2), [{ + unsigned BitWidth = N->getValueType(0).getScalarType().getSizeInBits(); + return CurDAG->MaskedValueIsZero(N->getOperand(0), + APInt::getLowBitsSet(BitWidth, 8)); +}]>; + +// ORs that can be treated as reversed insertions. +def or_as_revinserti8 : PatFrag<(ops node:$src1, node:$src2), + (or node:$src1, node:$src2), [{ + unsigned BitWidth = N->getValueType(0).getScalarType().getSizeInBits(); + return CurDAG->MaskedValueIsZero(N->getOperand(1), + APInt::getLowBitsSet(BitWidth, 8)); +}]>; + +// Fused multiply-add and multiply-subtract, but with the order of the +// operands matching SystemZ's MA and MS instructions. +def z_fma : PatFrag<(ops node:$src1, node:$src2, node:$src3), + (fma node:$src2, node:$src3, node:$src1)>; +def z_fms : PatFrag<(ops node:$src1, node:$src2, node:$src3), + (fma node:$src2, node:$src3, (fneg node:$src1))>; + +// Floating-point negative absolute. +def fnabs : PatFrag<(ops node:$ptr), (fneg (fabs node:$ptr))>; + +// Create a unary operator that loads from memory and then performs +// the given operation on it. +class loadu<SDPatternOperator operator> + : PatFrag<(ops node:$addr), (operator (load node:$addr))>; + +// Create a store operator that performs the given unary operation +// on the value before storing it. +class storeu<SDPatternOperator operator> + : PatFrag<(ops node:$value, node:$addr), + (store (operator node:$value), node:$addr)>; diff --git a/lib/Target/SystemZ/SystemZPatterns.td b/lib/Target/SystemZ/SystemZPatterns.td new file mode 100644 index 0000000000..3689f74bfd --- /dev/null +++ b/lib/Target/SystemZ/SystemZPatterns.td @@ -0,0 +1,71 @@ +//===-- SystemZPatterns.td - SystemZ-specific pattern rules ---*- tblgen-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Record that INSN performs a 64-bit version of unary operator OPERATOR +// in which the operand is sign-extended from 32 to 64 bits. +multiclass SXU<SDPatternOperator operator, Instruction insn> { + def : Pat<(operator (sext (i32 GR32:$src))), + (insn GR32:$src)>; + def : Pat<(operator (sext_inreg GR64:$src, i32)), + (insn (EXTRACT_SUBREG GR64:$src, subreg_32bit))>; +} + +// Record that INSN performs a 64-bit version of binary operator OPERATOR +// in which the first operand has class CLS and which the second operand +// is sign-extended from a 32-bit register. +multiclass SXB<SDPatternOperator operator, RegisterOperand cls, + Instruction insn> { + def : Pat<(operator cls:$src1, (sext GR32:$src2)), + (insn cls:$src1, GR32:$src2)>; + def : Pat<(operator cls:$src1, (sext_inreg GR64:$src2, i32)), + (insn cls:$src1, (EXTRACT_SUBREG GR64:$src2, subreg_32bit))>; +} + +// Like SXB, but for zero extension. +multiclass ZXB<SDPatternOperator operator, RegisterOperand cls, + Instruction insn> { + def : Pat<(operator cls:$src1, (zext GR32:$src2)), + (insn cls:$src1, GR32:$src2)>; + def : Pat<(operator cls:$src1, (and GR64:$src2, 0xffffffff)), + (insn cls:$src1, (EXTRACT_SUBREG GR64:$src2, subreg_32bit))>; +} + +// Record that INSN performs a binary read-modify-write operation, +// with LOAD, OPERATOR and STORE being the read, modify and write +// respectively. MODE is the addressing mode and IMM is the type +// of the second operand. +class RMWI<SDPatternOperator load, SDPatternOperator operator, + SDPatternOperator store, AddressingMode mode, + PatFrag imm, Instruction insn> + : Pat<(store (operator (load mode:$addr), imm:$src), mode:$addr), + (insn mode:$addr, (UIMM8 imm:$src))>; + +// Record that INSN performs binary operation OPERATION on a byte +// memory location. IMM is the type of the second operand. +multiclass RMWIByte<SDPatternOperator operator, AddressingMode mode, + Instruction insn> { + def : RMWI<zextloadi8, operator, truncstorei8, mode, imm32, insn>; + def : RMWI<zextloadi8, operator, truncstorei8, mode, imm64, insn>; + def : RMWI<sextloadi8, operator, truncstorei8, mode, imm32, insn>; + def : RMWI<sextloadi8, operator, truncstorei8, mode, imm64, insn>; + def : RMWI<extloadi8, operator, truncstorei8, mode, imm32, insn>; + def : RMWI<extloadi8, operator, truncstorei8, mode, imm64, insn>; +} + +// Record that INSN performs insertion TYPE into a register of class CLS. +// The inserted operand is loaded using LOAD from an address of mode MODE. +multiclass InsertMem<string type, Instruction insn, RegisterOperand cls, + SDPatternOperator load, AddressingMode mode> { + def : Pat<(!cast<SDPatternOperator>("or_as_"##type) + cls:$src1, (load mode:$src2)), + (insn cls:$src1, mode:$src2)>; + def : Pat<(!cast<SDPatternOperator>("or_as_rev"##type) + (load mode:$src2), cls:$src1), + (insn cls:$src1, mode:$src2)>; +} diff --git a/lib/Target/SystemZ/SystemZRegisterInfo.cpp b/lib/Target/SystemZ/SystemZRegisterInfo.cpp new file mode 100644 index 0000000000..a0ae7ed000 --- /dev/null +++ b/lib/Target/SystemZ/SystemZRegisterInfo.cpp @@ -0,0 +1,162 @@ +//===-- SystemZRegisterInfo.cpp - SystemZ register information ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SystemZRegisterInfo.h" +#include "SystemZTargetMachine.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" + +#define GET_REGINFO_TARGET_DESC +#include "SystemZGenRegisterInfo.inc" + +using namespace llvm; + +SystemZRegisterInfo::SystemZRegisterInfo(SystemZTargetMachine &tm, + const SystemZInstrInfo &tii) + : SystemZGenRegisterInfo(SystemZ::R14D), TM(tm), TII(tii) {} + +const uint16_t* +SystemZRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + static const uint16_t CalleeSavedRegs[] = { + SystemZ::R6D, SystemZ::R7D, SystemZ::R8D, SystemZ::R9D, + SystemZ::R10D, SystemZ::R11D, SystemZ::R12D, SystemZ::R13D, + SystemZ::R14D, SystemZ::R15D, + SystemZ::F8D, SystemZ::F9D, SystemZ::F10D, SystemZ::F11D, + SystemZ::F12D, SystemZ::F13D, SystemZ::F14D, SystemZ::F15D, + 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::R10Q); + } + + // R15D is the stack pointer. Reserve all aliases. + Reserved.set(SystemZ::R15D); + Reserved.set(SystemZ::R15W); + Reserved.set(SystemZ::R14Q); + return Reserved; +} + +bool +SystemZRegisterInfo::saveScavengerRegister(MachineBasicBlock &MBB, + MachineBasicBlock::iterator SaveMBBI, + MachineBasicBlock::iterator &UseMBBI, + const TargetRegisterClass *RC, + unsigned Reg) const { + MachineFunction &MF = *MBB.getParent(); + const SystemZFrameLowering *TFI = + static_cast<const SystemZFrameLowering *>(TM.getFrameLowering()); + unsigned Base = getFrameRegister(MF); + uint64_t Offset = TFI->getEmergencySpillSlotOffset(MF); + DebugLoc DL; + + unsigned LoadOpcode, StoreOpcode; + TII.getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode); + + // The offset must always be in range of a 12-bit unsigned displacement. + BuildMI(MBB, SaveMBBI, DL, TII.get(StoreOpcode)) + .addReg(Reg, RegState::Kill).addReg(Base).addImm(Offset).addReg(0); + BuildMI(MBB, UseMBBI, DL, TII.get(LoadOpcode), Reg) + .addReg(Base).addImm(Offset).addReg(0); + return true; +} + +void +SystemZRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI, + int SPAdj, unsigned FIOperandNum, + RegScavenger *RS) const { + assert(SPAdj == 0 && "Outgoing arguments should be part of the frame"); + + MachineBasicBlock &MBB = *MI->getParent(); + MachineFunction &MF = *MBB.getParent(); + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + DebugLoc DL = MI->getDebugLoc(); + + // Decompose the frame index into a base and offset. + int FrameIndex = MI->getOperand(FIOperandNum).getIndex(); + unsigned BasePtr = getFrameRegister(MF); + int64_t Offset = (TFI->getFrameIndexOffset(MF, FrameIndex) + + MI->getOperand(FIOperandNum + 1).getImm()); + + // Special handling of dbg_value instructions. + if (MI->isDebugValue()) { + MI->getOperand(FIOperandNum).ChangeToRegister(BasePtr, /*isDef*/ false); + MI->getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); + return; + } + + // See if the offset is in range, or if an equivalent instruction that + // accepts the offset exists. + unsigned Opcode = MI->getOpcode(); + unsigned OpcodeForOffset = TII.getOpcodeForOffset(Opcode, Offset); + if (OpcodeForOffset) + MI->getOperand(FIOperandNum).ChangeToRegister(BasePtr, false); + else { + // Create an anchor point that is in range. Start at 0xffff so that + // can use LLILH to load the immediate. + int64_t OldOffset = Offset; + int64_t Mask = 0xffff; + do { + Offset = OldOffset & Mask; + OpcodeForOffset = TII.getOpcodeForOffset(Opcode, Offset); + Mask >>= 1; + assert(Mask && "One offset must be OK"); + } while (!OpcodeForOffset); + + unsigned ScratchReg = + MF.getRegInfo().createVirtualRegister(&SystemZ::ADDR64BitRegClass); + int64_t HighOffset = OldOffset - Offset; + + if (MI->getDesc().TSFlags & SystemZII::HasIndex + && MI->getOperand(FIOperandNum + 2).getReg() == 0) { + // Load the offset into the scratch register and use it as an index. + // The scratch register then dies here. + TII.loadImmediate(MBB, MI, ScratchReg, HighOffset); + MI->getOperand(FIOperandNum).ChangeToRegister(BasePtr, false); + MI->getOperand(FIOperandNum + 2).ChangeToRegister(ScratchReg, + false, false, true); + } else { + // Load the anchor address into a scratch register. + unsigned LAOpcode = TII.getOpcodeForOffset(SystemZ::LA, HighOffset); + if (LAOpcode) + BuildMI(MBB, MI, DL, TII.get(LAOpcode),ScratchReg) + .addReg(BasePtr).addImm(HighOffset).addReg(0); + else { + // Load the high offset into the scratch register and use it as + // an index. + TII.loadImmediate(MBB, MI, ScratchReg, HighOffset); + BuildMI(MBB, MI, DL, TII.get(SystemZ::AGR),ScratchReg) + .addReg(ScratchReg, RegState::Kill).addReg(BasePtr); + } + + // Use the scratch register as the base. It then dies here. + MI->getOperand(FIOperandNum).ChangeToRegister(ScratchReg, + false, false, true); + } + } + MI->setDesc(TII.get(OpcodeForOffset)); + MI->getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); +} + +unsigned +SystemZRegisterInfo::getFrameRegister(const MachineFunction &MF) const { + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + return TFI->hasFP(MF) ? SystemZ::R11D : SystemZ::R15D; +} diff --git a/lib/Target/SystemZ/SystemZRegisterInfo.h b/lib/Target/SystemZ/SystemZRegisterInfo.h new file mode 100644 index 0000000000..91a70dea29 --- /dev/null +++ b/lib/Target/SystemZ/SystemZRegisterInfo.h @@ -0,0 +1,70 @@ +//===-- 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. +// +//===----------------------------------------------------------------------===// + +#ifndef SystemZREGISTERINFO_H +#define SystemZREGISTERINFO_H + +#include "SystemZ.h" +#include "llvm/Target/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "SystemZGenRegisterInfo.inc" + +namespace llvm { + +namespace SystemZ { + // Return the subreg to use for referring to the even and odd registers + // in a GR128 pair. Is32Bit says whether we want a GR32 or GR64. + inline unsigned even128(bool Is32bit) { + return Is32bit ? subreg_32bit : subreg_high; + } + inline unsigned odd128(bool Is32bit) { + return Is32bit ? subreg_low32 : subreg_low; + } +} + +class SystemZSubtarget; +class SystemZInstrInfo; + +struct SystemZRegisterInfo : public SystemZGenRegisterInfo { +private: + SystemZTargetMachine &TM; + const SystemZInstrInfo &TII; + +public: + SystemZRegisterInfo(SystemZTargetMachine &tm, const SystemZInstrInfo &tii); + + // Override TargetRegisterInfo.h. + virtual bool requiresRegisterScavenging(const MachineFunction &MF) const + LLVM_OVERRIDE { + return true; + } + virtual bool requiresFrameIndexScavenging(const MachineFunction &MF) const + LLVM_OVERRIDE { + return true; + } + virtual const uint16_t *getCalleeSavedRegs(const MachineFunction *MF = 0) + const LLVM_OVERRIDE; + virtual BitVector getReservedRegs(const MachineFunction &MF) + const LLVM_OVERRIDE; + virtual bool saveScavengerRegister(MachineBasicBlock &MBB, + MachineBasicBlock::iterator SaveMBBI, + MachineBasicBlock::iterator &UseMBBI, + const TargetRegisterClass *RC, + unsigned Reg) const LLVM_OVERRIDE; + virtual void eliminateFrameIndex(MachineBasicBlock::iterator MI, + int SPAdj, unsigned FIOperandNum, + RegScavenger *RS) const LLVM_OVERRIDE; + virtual unsigned getFrameRegister(const MachineFunction &MF) const + LLVM_OVERRIDE; +}; + +} // end namespace llvm + +#endif diff --git a/lib/Target/SystemZ/SystemZRegisterInfo.td b/lib/Target/SystemZ/SystemZRegisterInfo.td new file mode 100644 index 0000000000..bd1b563b9a --- /dev/null +++ b/lib/Target/SystemZ/SystemZRegisterInfo.td @@ -0,0 +1,150 @@ +//==- SystemZRegisterInfo.td - SystemZ register definitions -*- tablegen -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Class definitions. +//===----------------------------------------------------------------------===// + +class SystemZReg<string n> : Register<n> { + let Namespace = "SystemZ"; +} + +class SystemZRegWithSubregs<string n, list<Register> subregs> + : RegisterWithSubRegs<n, subregs> { + let Namespace = "SystemZ"; +} + +let Namespace = "SystemZ" in { +def subreg_32bit : SubRegIndex; // could also be known as "subreg_high32" +def subreg_high : SubRegIndex; +def subreg_low : SubRegIndex; +def subreg_low32 : SubRegIndex<[subreg_low, subreg_32bit]>; +} + +// Define a register class that contains values of type TYPE and an +// associated operand called NAME. SIZE is the size and alignment +// of the registers and REGLIST is the list of individual registers. +multiclass SystemZRegClass<string name, ValueType type, int size, dag regList> { + def AsmOperand : AsmOperandClass { + let Name = name; + let ParserMethod = "parse"##name; + let RenderMethod = "addRegOperands"; + } + def Bit : RegisterClass<"SystemZ", [type], size, regList> { + let Size = size; + } + def "" : RegisterOperand<!cast<RegisterClass>(name##"Bit")> { + let ParserMatchClass = !cast<AsmOperandClass>(name##"AsmOperand"); + } +} + +//===----------------------------------------------------------------------===// +// General-purpose registers +//===----------------------------------------------------------------------===// + +// Lower 32 bits of one of the 16 64-bit general-purpose registers +class GPR32<bits<16> num, string n> : SystemZReg<n> { + let HWEncoding = num; +} + +// One of the 16 64-bit general-purpose registers. +class GPR64<bits<16> num, string n, GPR32 low> + : SystemZRegWithSubregs<n, [low]> { + let HWEncoding = num; + let SubRegIndices = [subreg_32bit]; +} + +// 8 even-odd pairs of GPR64s. +class GPR128<bits<16> num, string n, GPR64 high, GPR64 low> + : SystemZRegWithSubregs<n, [high, low]> { + let HWEncoding = num; + let SubRegIndices = [subreg_high, subreg_low]; +} + +// General-purpose registers +foreach I = 0-15 in { + def R#I#W : GPR32<I, "r"#I>; + def R#I#D : GPR64<I, "r"#I, !cast<GPR32>("R"#I#"W")>, DwarfRegNum<[I]>; +} + +foreach I = [0, 2, 4, 6, 8, 10, 12, 14] in { + def R#I#Q : GPR128<I, "r"#I, !cast<GPR64>("R"#I#"D"), + !cast<GPR64>("R"#!add(I, 1)#"D")>; +} + +/// Allocate the callee-saved R6-R13 backwards. That way they can be saved +/// together with R14 and R15 in one prolog instruction. +defm GR32 : SystemZRegClass<"GR32", i32, 32, (add (sequence "R%uW", 0, 5), + (sequence "R%uW", 15, 6))>; +defm GR64 : SystemZRegClass<"GR64", i64, 64, (add (sequence "R%uD", 0, 5), + (sequence "R%uD", 15, 6))>; + +// The architecture doesn't really have any i128 support, so model the +// register pairs as untyped instead. +defm GR128 : SystemZRegClass<"GR128", untyped, 128, (add R0Q, R2Q, R4Q, + R12Q, R10Q, R8Q, R6Q, + R14Q)>; + +// Base and index registers. Everything except R0, which in an address +// context evaluates as 0. +defm ADDR32 : SystemZRegClass<"ADDR32", i32, 32, (sub GR32Bit, R0W)>; +defm ADDR64 : SystemZRegClass<"ADDR64", i64, 64, (sub GR64Bit, R0D)>; + +// Not used directly, but needs to exist for ADDR32 and ADDR64 subregs +// of a GR128. +defm ADDR128 : SystemZRegClass<"ADDR128", untyped, 128, (sub GR128Bit, R0Q)>; + +//===----------------------------------------------------------------------===// +// Floating-point registers +//===----------------------------------------------------------------------===// + +// Lower 32 bits of one of the 16 64-bit floating-point registers +class FPR32<bits<16> num, string n> : SystemZReg<n> { + let HWEncoding = num; +} + +// One of the 16 64-bit floating-point registers +class FPR64<bits<16> num, string n, FPR32 low> + : SystemZRegWithSubregs<n, [low]> { + let HWEncoding = num; + let SubRegIndices = [subreg_32bit]; +} + +// 8 pairs of FPR64s, with a one-register gap inbetween. +class FPR128<bits<16> num, string n, FPR64 high, FPR64 low> + : SystemZRegWithSubregs<n, [high, low]> { + let HWEncoding = num; + let SubRegIndices = [subreg_high, subreg_low]; +} + +// Floating-point registers +foreach I = 0-15 in { + def F#I#S : FPR32<I, "f"#I>; + def F#I#D : FPR64<I, "f"#I, !cast<FPR32>("F"#I#"S")>, + DwarfRegNum<[!add(I, 16)]>; +} + +foreach I = [0, 1, 4, 5, 8, 9, 12, 13] in { + def F#I#Q : FPR128<I, "f"#I, !cast<FPR64>("F"#I#"D"), + !cast<FPR64>("F"#!add(I, 2)#"D")>; +} + +// There's no store-multiple instruction for FPRs, so we're not fussy +// about the order in which call-saved registers are allocated. +defm FP32 : SystemZRegClass<"FP32", f32, 32, (sequence "F%uS", 0, 15)>; +defm FP64 : SystemZRegClass<"FP64", f64, 64, (sequence "F%uD", 0, 15)>; +defm FP128 : SystemZRegClass<"FP128", f128, 128, (add F0Q, F1Q, F4Q, F5Q, + F8Q, F9Q, F12Q, F13Q)>; + +//===----------------------------------------------------------------------===// +// Other registers +//===----------------------------------------------------------------------===// + +// Status register +def PSW : SystemZReg<"psw">; diff --git a/lib/Target/SystemZ/SystemZSubtarget.cpp b/lib/Target/SystemZ/SystemZSubtarget.cpp new file mode 100644 index 0000000000..cfd3324aad --- /dev/null +++ b/lib/Target/SystemZ/SystemZSubtarget.cpp @@ -0,0 +1,56 @@ +//===-- SystemZSubtarget.cpp - SystemZ subtarget information --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SystemZSubtarget.h" +#include "llvm/IR/GlobalValue.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), TargetTriple(TT) { + std::string CPUName = CPU; + if (CPUName.empty()) + CPUName = "z10"; + + // Parse features string. + ParseSubtargetFeatures(CPUName, FS); +} + +// Return true if GV binds locally under reloc model RM. +static bool bindsLocally(const GlobalValue *GV, Reloc::Model RM) { + // For non-PIC, all symbols bind locally. + if (RM == Reloc::Static) + return true; + + return GV->hasLocalLinkage() || !GV->hasDefaultVisibility(); +} + +bool SystemZSubtarget::isPC32DBLSymbol(const GlobalValue *GV, + Reloc::Model RM, + CodeModel::Model CM) const { + // PC32DBL accesses require the low bit to be clear. Note that a zero + // value selects the default alignment and is therefore OK. + if (GV->getAlignment() == 1) + return false; + + // For the small model, all locally-binding symbols are in range. + if (CM == CodeModel::Small) + return bindsLocally(GV, RM); + + // For Medium and above, assume that the symbol is not within the 4GB range. + // Taking the address of locally-defined text would be OK, but that + // case isn't easy to detect. + return false; +} diff --git a/lib/Target/SystemZ/SystemZSubtarget.h b/lib/Target/SystemZ/SystemZSubtarget.h new file mode 100644 index 0000000000..8d4d450844 --- /dev/null +++ b/lib/Target/SystemZ/SystemZSubtarget.h @@ -0,0 +1,48 @@ +//===-- SystemZSubtarget.h - 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 declares the SystemZ specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef SYSTEMZSUBTARGET_H +#define SYSTEMZSUBTARGET_H + +#include "llvm/ADT/Triple.h" +#include "llvm/Target/TargetSubtargetInfo.h" +#include <string> + +#define GET_SUBTARGETINFO_HEADER +#include "SystemZGenSubtargetInfo.inc" + +namespace llvm { +class GlobalValue; +class StringRef; + +class SystemZSubtarget : public SystemZGenSubtargetInfo { +private: + Triple TargetTriple; + +public: + SystemZSubtarget(const std::string &TT, const std::string &CPU, + const std::string &FS); + + // Automatically generated by tblgen. + void ParseSubtargetFeatures(StringRef CPU, StringRef FS); + + // Return true if GV can be accessed using LARL for reloc model RM + // and code model CM. + bool isPC32DBLSymbol(const GlobalValue *GV, Reloc::Model RM, + CodeModel::Model CM) const; + + bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); } +}; +} // end namespace llvm + +#endif diff --git a/lib/Target/SystemZ/SystemZTargetMachine.cpp b/lib/Target/SystemZ/SystemZTargetMachine.cpp new file mode 100644 index 0000000000..8c4c456ef5 --- /dev/null +++ b/lib/Target/SystemZ/SystemZTargetMachine.cpp @@ -0,0 +1,60 @@ +//===-- 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 "llvm/CodeGen/Passes.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +extern "C" void LLVMInitializeSystemZTarget() { + // Register the target. + RegisterTargetMachine<SystemZTargetMachine> X(TheSystemZTarget); +} + +SystemZTargetMachine::SystemZTargetMachine(const Target &T, StringRef TT, + StringRef CPU, StringRef FS, + const TargetOptions &Options, + Reloc::Model RM, + CodeModel::Model CM, + CodeGenOpt::Level OL) + : LLVMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL), + Subtarget(TT, CPU, FS), + // Make sure that global data has at least 16 bits of alignment by default, + // so that we can refer to it using LARL. We don't have any special + // requirements for stack variables though. + DL("E-p:64:64:64-i1:8:16-i8:8:16-i16:16-i32:32-i64:64" + "-f32:32-f64:64-f128:64-a0:8:16-n32:64"), + InstrInfo(*this), TLInfo(*this), TSInfo(*this), + FrameLowering(*this, Subtarget) { +} + +namespace { +/// SystemZ Code Generator Pass Configuration Options. +class SystemZPassConfig : public TargetPassConfig { +public: + SystemZPassConfig(SystemZTargetMachine *TM, PassManagerBase &PM) + : TargetPassConfig(TM, PM) {} + + SystemZTargetMachine &getSystemZTargetMachine() const { + return getTM<SystemZTargetMachine>(); + } + + virtual bool addInstSelector(); +}; +} // end anonymous namespace + +bool SystemZPassConfig::addInstSelector() { + addPass(createSystemZISelDag(getSystemZTargetMachine(), getOptLevel())); + return false; +} + +TargetPassConfig *SystemZTargetMachine::createPassConfig(PassManagerBase &PM) { + return new SystemZPassConfig(this, PM); +} diff --git a/lib/Target/SystemZ/SystemZTargetMachine.h b/lib/Target/SystemZ/SystemZTargetMachine.h new file mode 100644 index 0000000000..98614e7b7e --- /dev/null +++ b/lib/Target/SystemZ/SystemZTargetMachine.h @@ -0,0 +1,74 @@ +//==- 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 SYSTEMZTARGETMACHINE_H +#define SYSTEMZTARGETMACHINE_H + +#include "SystemZFrameLowering.h" +#include "SystemZISelLowering.h" +#include "SystemZInstrInfo.h" +#include "SystemZRegisterInfo.h" +#include "SystemZSubtarget.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetSelectionDAGInfo.h" + +namespace llvm { + +class SystemZTargetMachine : public LLVMTargetMachine { + SystemZSubtarget Subtarget; + const DataLayout DL; + SystemZInstrInfo InstrInfo; + SystemZTargetLowering TLInfo; + TargetSelectionDAGInfo TSInfo; + SystemZFrameLowering FrameLowering; + +public: + SystemZTargetMachine(const Target &T, StringRef TT, StringRef CPU, + StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL); + + // Override TargetMachine. + virtual const TargetFrameLowering *getFrameLowering() const LLVM_OVERRIDE { + return &FrameLowering; + } + virtual const SystemZInstrInfo *getInstrInfo() const LLVM_OVERRIDE { + return &InstrInfo; + } + virtual const SystemZSubtarget *getSubtargetImpl() const LLVM_OVERRIDE { + return &Subtarget; + } + virtual const DataLayout *getDataLayout() const LLVM_OVERRIDE { + return &DL; + } + virtual const SystemZRegisterInfo *getRegisterInfo() const LLVM_OVERRIDE { + return &InstrInfo.getRegisterInfo(); + } + virtual const SystemZTargetLowering *getTargetLowering() const LLVM_OVERRIDE { + return &TLInfo; + } + virtual const TargetSelectionDAGInfo *getSelectionDAGInfo() const + LLVM_OVERRIDE { + return &TSInfo; + } + + // Override LLVMTargetMachine + virtual TargetPassConfig *createPassConfig(PassManagerBase &PM) LLVM_OVERRIDE; +}; + +} // end namespace llvm + +#endif diff --git a/lib/Target/SystemZ/TargetInfo/CMakeLists.txt b/lib/Target/SystemZ/TargetInfo/CMakeLists.txt new file mode 100644 index 0000000000..b6051d3bf6 --- /dev/null +++ b/lib/Target/SystemZ/TargetInfo/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMSystemZInfo + SystemZTargetInfo.cpp + ) + +add_dependencies(LLVMSystemZInfo SystemZCommonTableGen) diff --git a/lib/Target/SystemZ/TargetInfo/LLVMBuild.txt b/lib/Target/SystemZ/TargetInfo/LLVMBuild.txt new file mode 100644 index 0000000000..ea43736a68 --- /dev/null +++ b/lib/Target/SystemZ/TargetInfo/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/SystemZ/TargetInfo/LLVMBuild.txt ------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = SystemZInfo +parent = SystemZ +required_libraries = MC Support Target +add_to_library_groups = SystemZ diff --git a/lib/Target/SystemZ/TargetInfo/Makefile b/lib/Target/SystemZ/TargetInfo/Makefile new file mode 100644 index 0000000000..0be80eb4e6 --- /dev/null +++ b/lib/Target/SystemZ/TargetInfo/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/SystemZ/TargetInfo/Makefile --------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../../.. +LIBRARYNAME = LLVMSystemZInfo + +# Hack: we need to include 'main' target directory to grab private headers +CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/lib/Target/SystemZ/TargetInfo/SystemZTargetInfo.cpp b/lib/Target/SystemZ/TargetInfo/SystemZTargetInfo.cpp new file mode 100644 index 0000000000..8f9aa2811d --- /dev/null +++ b/lib/Target/SystemZ/TargetInfo/SystemZTargetInfo.cpp @@ -0,0 +1,20 @@ +//===-- 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/Support/TargetRegistry.h" + +using namespace llvm; + +Target llvm::TheSystemZTarget; + +extern "C" void LLVMInitializeSystemZTargetInfo() { + RegisterTarget<Triple::systemz, /*HasJIT=*/true> + X(TheSystemZTarget, "systemz", "SystemZ"); +} |