mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 04:30:23 +00:00
[SystemZ] Add back end
This adds the actual lib/Target/SystemZ target files necessary to implement the SystemZ target. Note that at this point, the target cannot yet be built since the configure bits are missing. Those will be provided shortly by a follow-on patch. This version of the patch incorporates feedback from reviews by Chris Lattner and Anton Korobeynikov. Thanks to all reviewers! Patch by Richard Sandiford. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@181203 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e96e43f9a4
commit
1d09d56fe1
@ -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
|
||||
|
7
lib/Target/SystemZ/AsmParser/CMakeLists.txt
Normal file
7
lib/Target/SystemZ/AsmParser/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. )
|
||||
|
||||
add_llvm_library(LLVMSystemZAsmParser
|
||||
SystemZAsmParser.cpp
|
||||
)
|
||||
|
||||
add_dependencies(LLVMSystemZAsmParser SystemZCommonTableGen)
|
23
lib/Target/SystemZ/AsmParser/LLVMBuild.txt
Normal file
23
lib/Target/SystemZ/AsmParser/LLVMBuild.txt
Normal file
@ -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
|
16
lib/Target/SystemZ/AsmParser/Makefile
Normal file
16
lib/Target/SystemZ/AsmParser/Makefile
Normal file
@ -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
|
689
lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
Normal file
689
lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
Normal file
@ -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);
|
||||
}
|
32
lib/Target/SystemZ/CMakeLists.txt
Normal file
32
lib/Target/SystemZ/CMakeLists.txt
Normal file
@ -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)
|
7
lib/Target/SystemZ/InstPrinter/CMakeLists.txt
Normal file
7
lib/Target/SystemZ/InstPrinter/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. )
|
||||
|
||||
add_llvm_library(LLVMSystemZAsmPrinter
|
||||
SystemZInstPrinter.cpp
|
||||
)
|
||||
|
||||
add_dependencies(LLVMSystemZAsmPrinter SystemZCommonTableGen)
|
23
lib/Target/SystemZ/InstPrinter/LLVMBuild.txt
Normal file
23
lib/Target/SystemZ/InstPrinter/LLVMBuild.txt
Normal file
@ -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
|
16
lib/Target/SystemZ/InstPrinter/Makefile
Normal file
16
lib/Target/SystemZ/InstPrinter/Makefile
Normal file
@ -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
|
150
lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp
Normal file
150
lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp
Normal file
@ -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];
|
||||
}
|
68
lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h
Normal file
68
lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h
Normal file
@ -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
|
34
lib/Target/SystemZ/LLVMBuild.txt
Normal file
34
lib/Target/SystemZ/LLVMBuild.txt
Normal file
@ -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
|
9
lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt
Normal file
9
lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
add_llvm_library(LLVMSystemZDesc
|
||||
SystemZMCAsmBackend.cpp
|
||||
SystemZMCAsmInfo.cpp
|
||||
SystemZMCCodeEmitter.cpp
|
||||
SystemZMCObjectWriter.cpp
|
||||
SystemZMCTargetDesc.cpp
|
||||
)
|
||||
|
||||
add_dependencies(LLVMSystemZDesc SystemZCommonTableGen)
|
23
lib/Target/SystemZ/MCTargetDesc/LLVMBuild.txt
Normal file
23
lib/Target/SystemZ/MCTargetDesc/LLVMBuild.txt
Normal file
@ -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
|
16
lib/Target/SystemZ/MCTargetDesc/Makefile
Normal file
16
lib/Target/SystemZ/MCTargetDesc/Makefile
Normal file
@ -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
|
151
lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
Normal file
151
lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
Normal file
@ -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);
|
||||
}
|
38
lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp
Normal file
38
lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp
Normal file
@ -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());
|
||||
}
|
31
lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h
Normal file
31
lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h
Normal file
@ -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
|
131
lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp
Normal file
131
lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp
Normal file
@ -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"
|
31
lib/Target/SystemZ/MCTargetDesc/SystemZMCFixups.h
Normal file
31
lib/Target/SystemZ/MCTargetDesc/SystemZMCFixups.h
Normal file
@ -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
|
140
lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp
Normal file
140
lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp
Normal file
@ -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);
|
||||
}
|
160
lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp
Normal file
160
lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp
Normal file
@ -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);
|
||||
}
|
62
lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h
Normal file
62
lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h
Normal file
@ -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
|
28
lib/Target/SystemZ/Makefile
Normal file
28
lib/Target/SystemZ/Makefile
Normal file
@ -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
|
||||
|
146
lib/Target/SystemZ/README.txt
Normal file
146
lib/Target/SystemZ/README.txt
Normal file
@ -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.
|
77
lib/Target/SystemZ/SystemZ.h
Normal file
77
lib/Target/SystemZ/SystemZ.h
Normal file
@ -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
|
75
lib/Target/SystemZ/SystemZ.td
Normal file
75
lib/Target/SystemZ/SystemZ.td
Normal file
@ -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];
|
||||
}
|
113
lib/Target/SystemZ/SystemZAsmPrinter.cpp
Normal file
113
lib/Target/SystemZ/SystemZAsmPrinter.cpp
Normal file
@ -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);
|
||||
}
|
52
lib/Target/SystemZ/SystemZAsmPrinter.h
Normal file
52
lib/Target/SystemZ/SystemZAsmPrinter.h
Normal file
@ -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
|
21
lib/Target/SystemZ/SystemZCallingConv.cpp
Normal file
21
lib/Target/SystemZ/SystemZCallingConv.cpp
Normal file
@ -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
|
||||
};
|
23
lib/Target/SystemZ/SystemZCallingConv.h
Normal file
23
lib/Target/SystemZ/SystemZCallingConv.h
Normal file
@ -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
|
65
lib/Target/SystemZ/SystemZCallingConv.td
Normal file
65
lib/Target/SystemZ/SystemZCallingConv.td
Normal file
@ -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>>
|
||||
]>;
|
62
lib/Target/SystemZ/SystemZConstantPoolValue.cpp
Normal file
62
lib/Target/SystemZ/SystemZConstantPoolValue.cpp
Normal file
@ -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);
|
||||
}
|
55
lib/Target/SystemZ/SystemZConstantPoolValue.h
Normal file
55
lib/Target/SystemZ/SystemZConstantPoolValue.h
Normal file
@ -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
|
535
lib/Target/SystemZ/SystemZFrameLowering.cpp
Normal file
535
lib/Target/SystemZ/SystemZFrameLowering.cpp
Normal file
@ -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");
|
||||
}
|
||||
}
|
93
lib/Target/SystemZ/SystemZFrameLowering.h
Normal file
93
lib/Target/SystemZ/SystemZFrameLowering.h
Normal file
@ -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
|
616
lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
Normal file
616
lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
Normal file
@ -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;
|
||||
}
|
2233
lib/Target/SystemZ/SystemZISelLowering.cpp
Normal file
2233
lib/Target/SystemZ/SystemZISelLowering.cpp
Normal file
File diff suppressed because it is too large
Load Diff
212
lib/Target/SystemZ/SystemZISelLowering.h
Normal file
212
lib/Target/SystemZ/SystemZISelLowering.h
Normal file
@ -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
|
48
lib/Target/SystemZ/SystemZInstrBuilder.h
Normal file
48
lib/Target/SystemZ/SystemZInstrBuilder.h
Normal file
@ -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
|
318
lib/Target/SystemZ/SystemZInstrFP.td
Normal file
318
lib/Target/SystemZ/SystemZInstrFP.td
Normal file
@ -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))>;
|
987
lib/Target/SystemZ/SystemZInstrFormats.td
Normal file
987
lib/Target/SystemZ/SystemZInstrFormats.td
Normal file
@ -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>;
|
444
lib/Target/SystemZ/SystemZInstrInfo.cpp
Normal file
444
lib/Target/SystemZ/SystemZInstrInfo.cpp
Normal file
@ -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);
|
||||
}
|
123
lib/Target/SystemZ/SystemZInstrInfo.h
Normal file
123
lib/Target/SystemZ/SystemZInstrInfo.h
Normal file
@ -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
|
955
lib/Target/SystemZ/SystemZInstrInfo.td
Normal file
955
lib/Target/SystemZ/SystemZInstrInfo.td
Normal file
@ -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)>;
|
116
lib/Target/SystemZ/SystemZMCInstLower.cpp
Normal file
116
lib/Target/SystemZ/SystemZMCInstLower.cpp
Normal file
@ -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);
|
||||
}
|
||||
}
|
47
lib/Target/SystemZ/SystemZMCInstLower.h
Normal file
47
lib/Target/SystemZ/SystemZMCInstLower.h
Normal file
@ -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
|
74
lib/Target/SystemZ/SystemZMachineFunctionInfo.h
Normal file
74
lib/Target/SystemZ/SystemZMachineFunctionInfo.h
Normal file
@ -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
|
435
lib/Target/SystemZ/SystemZOperands.td
Normal file
435
lib/Target/SystemZ/SystemZOperands.td
Normal file
@ -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";
|
||||
}
|
196
lib/Target/SystemZ/SystemZOperators.td
Normal file
196
lib/Target/SystemZ/SystemZOperators.td
Normal file
@ -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)>;
|
71
lib/Target/SystemZ/SystemZPatterns.td
Normal file
71
lib/Target/SystemZ/SystemZPatterns.td
Normal file
@ -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)>;
|
||||
}
|
162
lib/Target/SystemZ/SystemZRegisterInfo.cpp
Normal file
162
lib/Target/SystemZ/SystemZRegisterInfo.cpp
Normal file
@ -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;
|
||||
}
|
70
lib/Target/SystemZ/SystemZRegisterInfo.h
Normal file
70
lib/Target/SystemZ/SystemZRegisterInfo.h
Normal file
@ -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
|
150
lib/Target/SystemZ/SystemZRegisterInfo.td
Normal file
150
lib/Target/SystemZ/SystemZRegisterInfo.td
Normal file
@ -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">;
|
56
lib/Target/SystemZ/SystemZSubtarget.cpp
Normal file
56
lib/Target/SystemZ/SystemZSubtarget.cpp
Normal file
@ -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;
|
||||
}
|
48
lib/Target/SystemZ/SystemZSubtarget.h
Normal file
48
lib/Target/SystemZ/SystemZSubtarget.h
Normal file
@ -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
|
60
lib/Target/SystemZ/SystemZTargetMachine.cpp
Normal file
60
lib/Target/SystemZ/SystemZTargetMachine.cpp
Normal file
@ -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);
|
||||
}
|
74
lib/Target/SystemZ/SystemZTargetMachine.h
Normal file
74
lib/Target/SystemZ/SystemZTargetMachine.h
Normal file
@ -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
|
7
lib/Target/SystemZ/TargetInfo/CMakeLists.txt
Normal file
7
lib/Target/SystemZ/TargetInfo/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. )
|
||||
|
||||
add_llvm_library(LLVMSystemZInfo
|
||||
SystemZTargetInfo.cpp
|
||||
)
|
||||
|
||||
add_dependencies(LLVMSystemZInfo SystemZCommonTableGen)
|
23
lib/Target/SystemZ/TargetInfo/LLVMBuild.txt
Normal file
23
lib/Target/SystemZ/TargetInfo/LLVMBuild.txt
Normal file
@ -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
|
15
lib/Target/SystemZ/TargetInfo/Makefile
Normal file
15
lib/Target/SystemZ/TargetInfo/Makefile
Normal file
@ -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
|
20
lib/Target/SystemZ/TargetInfo/SystemZTargetInfo.cpp
Normal file
20
lib/Target/SystemZ/TargetInfo/SystemZTargetInfo.cpp
Normal file
@ -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");
|
||||
}
|
Loading…
Reference in New Issue
Block a user