forked from OSchip/llvm-project
[CSKY] Lower leaf DAG node such as global symbol, frame address and jumptable, etc.
Lower global symbols such as call/external symbol. Lower other leaf DAG node such as frame address/block address/jumptable/vastart. Normally some leaf symbols need reside in constant pool as ABI prefers, and are addressed by lrw or jsri instructions. Every symbol in constant pool is lowered with one entry in target constant pool. The entry has different type corresponding to different leaf node such as blockaddress, jumptable, or global value.
This commit is contained in:
parent
cd4deef28e
commit
8ddc816929
|
@ -17,6 +17,7 @@ add_public_tablegen_target(CSKYCommonTableGen)
|
|||
|
||||
add_llvm_target(CSKYCodeGen
|
||||
CSKYAsmPrinter.cpp
|
||||
CSKYConstantPoolValue.cpp
|
||||
CSKYFrameLowering.cpp
|
||||
CSKYInstrInfo.cpp
|
||||
CSKYISelDAGToDAG.cpp
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
#include "CSKYAsmPrinter.h"
|
||||
#include "CSKY.h"
|
||||
#include "CSKYConstantPoolValue.h"
|
||||
#include "CSKYTargetMachine.h"
|
||||
#include "MCTargetDesc/CSKYInstPrinter.h"
|
||||
#include "MCTargetDesc/CSKYMCExpr.h"
|
||||
|
@ -66,6 +67,84 @@ void CSKYAsmPrinter::emitInstruction(const MachineInstr *MI) {
|
|||
EmitToStreamer(*OutStreamer, TmpInst);
|
||||
}
|
||||
|
||||
// Convert a CSKY-specific constant pool modifier into the associated
|
||||
// MCSymbolRefExpr variant kind.
|
||||
static CSKYMCExpr::VariantKind
|
||||
getModifierVariantKind(CSKYCP::CSKYCPModifier Modifier) {
|
||||
switch (Modifier) {
|
||||
case CSKYCP::NO_MOD:
|
||||
return CSKYMCExpr::VK_CSKY_None;
|
||||
case CSKYCP::ADDR:
|
||||
return CSKYMCExpr::VK_CSKY_ADDR;
|
||||
case CSKYCP::GOT:
|
||||
return CSKYMCExpr::VK_CSKY_GOT;
|
||||
case CSKYCP::GOTOFF:
|
||||
return CSKYMCExpr::VK_CSKY_GOTOFF;
|
||||
case CSKYCP::PLT:
|
||||
return CSKYMCExpr::VK_CSKY_PLT;
|
||||
case CSKYCP::TLSGD:
|
||||
return CSKYMCExpr::VK_CSKY_TLSGD;
|
||||
case CSKYCP::TLSLE:
|
||||
return CSKYMCExpr::VK_CSKY_TLSLE;
|
||||
case CSKYCP::TLSIE:
|
||||
return CSKYMCExpr::VK_CSKY_TLSIE;
|
||||
}
|
||||
llvm_unreachable("Invalid CSKYCPModifier!");
|
||||
}
|
||||
|
||||
void CSKYAsmPrinter::emitMachineConstantPoolValue(
|
||||
MachineConstantPoolValue *MCPV) {
|
||||
int Size = getDataLayout().getTypeAllocSize(MCPV->getType());
|
||||
CSKYConstantPoolValue *CCPV = static_cast<CSKYConstantPoolValue *>(MCPV);
|
||||
MCSymbol *MCSym;
|
||||
|
||||
if (CCPV->isBlockAddress()) {
|
||||
const BlockAddress *BA =
|
||||
cast<CSKYConstantPoolConstant>(CCPV)->getBlockAddress();
|
||||
MCSym = GetBlockAddressSymbol(BA);
|
||||
} else if (CCPV->isGlobalValue()) {
|
||||
const GlobalValue *GV = cast<CSKYConstantPoolConstant>(CCPV)->getGV();
|
||||
MCSym = getSymbol(GV);
|
||||
} else if (CCPV->isMachineBasicBlock()) {
|
||||
const MachineBasicBlock *MBB = cast<CSKYConstantPoolMBB>(CCPV)->getMBB();
|
||||
MCSym = MBB->getSymbol();
|
||||
} else if (CCPV->isJT()) {
|
||||
signed JTI = cast<CSKYConstantPoolJT>(CCPV)->getJTI();
|
||||
MCSym = GetJTISymbol(JTI);
|
||||
} else {
|
||||
assert(CCPV->isExtSymbol() && "unrecognized constant pool value");
|
||||
StringRef Sym = cast<CSKYConstantPoolSymbol>(CCPV)->getSymbol();
|
||||
MCSym = GetExternalSymbolSymbol(Sym);
|
||||
}
|
||||
// Create an MCSymbol for the reference.
|
||||
const MCExpr *Expr =
|
||||
MCSymbolRefExpr::create(MCSym, MCSymbolRefExpr::VK_None, OutContext);
|
||||
|
||||
if (CCPV->getPCAdjustment()) {
|
||||
|
||||
MCSymbol *PCLabel = OutContext.getOrCreateSymbol(
|
||||
Twine(MAI->getPrivateGlobalPrefix()) + "PC" +
|
||||
Twine(getFunctionNumber()) + "_" + Twine(CCPV->getLabelID()));
|
||||
|
||||
const MCExpr *PCRelExpr = MCSymbolRefExpr::create(PCLabel, OutContext);
|
||||
if (CCPV->mustAddCurrentAddress()) {
|
||||
// We want "(<expr> - .)", but MC doesn't have a concept of the '.'
|
||||
// label, so just emit a local label end reference that instead.
|
||||
MCSymbol *DotSym = OutContext.createTempSymbol();
|
||||
OutStreamer->emitLabel(DotSym);
|
||||
const MCExpr *DotExpr = MCSymbolRefExpr::create(DotSym, OutContext);
|
||||
PCRelExpr = MCBinaryExpr::createSub(PCRelExpr, DotExpr, OutContext);
|
||||
}
|
||||
Expr = MCBinaryExpr::createSub(Expr, PCRelExpr, OutContext);
|
||||
}
|
||||
|
||||
// Create an MCSymbol for the reference.
|
||||
Expr = CSKYMCExpr::create(Expr, getModifierVariantKind(CCPV->getModifier()),
|
||||
OutContext);
|
||||
|
||||
OutStreamer->emitValue(Expr, Size);
|
||||
}
|
||||
|
||||
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmPrinter() {
|
||||
RegisterAsmPrinter<CSKYAsmPrinter> X(getTheCSKYTarget());
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ public:
|
|||
bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
|
||||
const MachineInstr *MI);
|
||||
|
||||
void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override;
|
||||
|
||||
void emitInstruction(const MachineInstr *MI) override;
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
|
|
|
@ -0,0 +1,216 @@
|
|||
//===-- CSKYConstantPoolValue.cpp - CSKY constantpool value ---------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the CSKY specific constantpool value class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CSKYConstantPoolValue.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/IR/Constant.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/GlobalValue.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CSKYConstantPoolValue
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CSKYConstantPoolValue::CSKYConstantPoolValue(Type *Ty, CSKYCP::CSKYCPKind Kind,
|
||||
unsigned PCAdjust,
|
||||
CSKYCP::CSKYCPModifier Modifier,
|
||||
bool AddCurrentAddress,
|
||||
unsigned ID)
|
||||
: MachineConstantPoolValue(Ty), Kind(Kind), PCAdjust(PCAdjust),
|
||||
Modifier(Modifier), AddCurrentAddress(AddCurrentAddress), LabelId(ID) {}
|
||||
|
||||
const char *CSKYConstantPoolValue::getModifierText() const {
|
||||
switch (Modifier) {
|
||||
case CSKYCP::ADDR:
|
||||
return "ADDR";
|
||||
case CSKYCP::GOT:
|
||||
return "GOT";
|
||||
case CSKYCP::GOTOFF:
|
||||
return "GOTOFF";
|
||||
case CSKYCP::PLT:
|
||||
return "PLT";
|
||||
case CSKYCP::TLSIE:
|
||||
return "TLSIE";
|
||||
case CSKYCP::TLSLE:
|
||||
return "TLSLE";
|
||||
case CSKYCP::TLSGD:
|
||||
return "TLSGD";
|
||||
case CSKYCP::NO_MOD:
|
||||
return "";
|
||||
}
|
||||
llvm_unreachable("Unknown modifier!");
|
||||
}
|
||||
|
||||
int CSKYConstantPoolValue::getExistingMachineCPValue(MachineConstantPool *CP,
|
||||
Align Alignment) {
|
||||
llvm_unreachable("Shouldn't be calling this directly!");
|
||||
}
|
||||
|
||||
void CSKYConstantPoolValue::addSelectionDAGCSEId(FoldingSetNodeID &ID) {
|
||||
ID.AddInteger(LabelId);
|
||||
ID.AddInteger(PCAdjust);
|
||||
ID.AddInteger(Modifier);
|
||||
}
|
||||
|
||||
void CSKYConstantPoolValue::print(raw_ostream &O) const {
|
||||
if (Modifier)
|
||||
O << "(" << getModifierText() << ")";
|
||||
if (PCAdjust)
|
||||
O << " + " << PCAdjust;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CSKYConstantPoolConstant
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CSKYConstantPoolConstant::CSKYConstantPoolConstant(
|
||||
const Constant *C, CSKYCP::CSKYCPKind Kind, unsigned PCAdjust,
|
||||
CSKYCP::CSKYCPModifier Modifier, bool AddCurrentAddress, unsigned ID)
|
||||
: CSKYConstantPoolValue(C->getType(), Kind, PCAdjust, Modifier,
|
||||
AddCurrentAddress, ID),
|
||||
CVal(C) {}
|
||||
|
||||
CSKYConstantPoolConstant *CSKYConstantPoolConstant::Create(
|
||||
const Constant *C, CSKYCP::CSKYCPKind Kind, unsigned PCAdjust,
|
||||
CSKYCP::CSKYCPModifier Modifier, bool AddCurrentAddress, unsigned ID) {
|
||||
return new CSKYConstantPoolConstant(C, Kind, PCAdjust, Modifier,
|
||||
AddCurrentAddress, ID);
|
||||
}
|
||||
|
||||
const GlobalValue *CSKYConstantPoolConstant::getGV() const {
|
||||
assert(isa<GlobalValue>(CVal) && "CVal should be GlobalValue");
|
||||
return cast<GlobalValue>(CVal);
|
||||
}
|
||||
|
||||
const BlockAddress *CSKYConstantPoolConstant::getBlockAddress() const {
|
||||
assert(isa<BlockAddress>(CVal) && "CVal should be BlockAddress");
|
||||
return cast<BlockAddress>(CVal);
|
||||
}
|
||||
|
||||
int CSKYConstantPoolConstant::getExistingMachineCPValue(MachineConstantPool *CP,
|
||||
Align Alignment) {
|
||||
return getExistingMachineCPValueImpl<CSKYConstantPoolConstant>(CP, Alignment);
|
||||
}
|
||||
|
||||
void CSKYConstantPoolConstant::addSelectionDAGCSEId(FoldingSetNodeID &ID) {
|
||||
ID.AddPointer(CVal);
|
||||
|
||||
CSKYConstantPoolValue::addSelectionDAGCSEId(ID);
|
||||
}
|
||||
|
||||
void CSKYConstantPoolConstant::print(raw_ostream &O) const {
|
||||
O << CVal->getName();
|
||||
CSKYConstantPoolValue::print(O);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CSKYConstantPoolSymbol
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CSKYConstantPoolSymbol::CSKYConstantPoolSymbol(Type *Ty, const char *S,
|
||||
unsigned PCAdjust,
|
||||
CSKYCP::CSKYCPModifier Modifier,
|
||||
bool AddCurrentAddress)
|
||||
: CSKYConstantPoolValue(Ty, CSKYCP::CPExtSymbol, PCAdjust, Modifier,
|
||||
AddCurrentAddress),
|
||||
S(strdup(S)) {}
|
||||
|
||||
CSKYConstantPoolSymbol *
|
||||
CSKYConstantPoolSymbol::Create(Type *Ty, const char *S, unsigned PCAdjust,
|
||||
CSKYCP::CSKYCPModifier Modifier) {
|
||||
return new CSKYConstantPoolSymbol(Ty, S, PCAdjust, Modifier, false);
|
||||
}
|
||||
|
||||
int CSKYConstantPoolSymbol::getExistingMachineCPValue(MachineConstantPool *CP,
|
||||
Align Alignment) {
|
||||
|
||||
return getExistingMachineCPValueImpl<CSKYConstantPoolSymbol>(CP, Alignment);
|
||||
}
|
||||
|
||||
void CSKYConstantPoolSymbol::addSelectionDAGCSEId(FoldingSetNodeID &ID) {
|
||||
ID.AddString(S);
|
||||
CSKYConstantPoolValue::addSelectionDAGCSEId(ID);
|
||||
}
|
||||
|
||||
void CSKYConstantPoolSymbol::print(raw_ostream &O) const {
|
||||
O << S;
|
||||
CSKYConstantPoolValue::print(O);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CSKYConstantPoolMBB
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CSKYConstantPoolMBB::CSKYConstantPoolMBB(Type *Ty, const MachineBasicBlock *Mbb,
|
||||
unsigned PCAdjust,
|
||||
CSKYCP::CSKYCPModifier Modifier,
|
||||
bool AddCurrentAddress)
|
||||
: CSKYConstantPoolValue(Ty, CSKYCP::CPMachineBasicBlock, PCAdjust, Modifier,
|
||||
AddCurrentAddress),
|
||||
MBB(Mbb) {}
|
||||
|
||||
CSKYConstantPoolMBB *CSKYConstantPoolMBB::Create(Type *Ty,
|
||||
const MachineBasicBlock *Mbb,
|
||||
unsigned PCAdjust) {
|
||||
return new CSKYConstantPoolMBB(Ty, Mbb, PCAdjust, CSKYCP::ADDR, false);
|
||||
}
|
||||
|
||||
int CSKYConstantPoolMBB::getExistingMachineCPValue(MachineConstantPool *CP,
|
||||
Align Alignment) {
|
||||
return getExistingMachineCPValueImpl<CSKYConstantPoolMBB>(CP, Alignment);
|
||||
}
|
||||
|
||||
void CSKYConstantPoolMBB::addSelectionDAGCSEId(FoldingSetNodeID &ID) {
|
||||
ID.AddPointer(MBB);
|
||||
CSKYConstantPoolValue::addSelectionDAGCSEId(ID);
|
||||
}
|
||||
|
||||
void CSKYConstantPoolMBB::print(raw_ostream &O) const {
|
||||
O << "BB#" << MBB->getNumber();
|
||||
CSKYConstantPoolValue::print(O);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CSKYConstantPoolJT
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CSKYConstantPoolJT::CSKYConstantPoolJT(Type *Ty, int JTIndex, unsigned PCAdj,
|
||||
CSKYCP::CSKYCPModifier Modifier,
|
||||
bool AddCurrentAddress)
|
||||
: CSKYConstantPoolValue(Ty, CSKYCP::CPJT, PCAdj, Modifier,
|
||||
AddCurrentAddress),
|
||||
JTI(JTIndex) {}
|
||||
|
||||
CSKYConstantPoolJT *
|
||||
CSKYConstantPoolJT::Create(Type *Ty, int JTI, unsigned PCAdj,
|
||||
CSKYCP::CSKYCPModifier Modifier) {
|
||||
return new CSKYConstantPoolJT(Ty, JTI, PCAdj, Modifier, false);
|
||||
}
|
||||
|
||||
int CSKYConstantPoolJT::getExistingMachineCPValue(MachineConstantPool *CP,
|
||||
Align Alignment) {
|
||||
return getExistingMachineCPValueImpl<CSKYConstantPoolJT>(CP, Alignment);
|
||||
}
|
||||
|
||||
void CSKYConstantPoolJT::addSelectionDAGCSEId(FoldingSetNodeID &ID) {
|
||||
ID.AddInteger(JTI);
|
||||
CSKYConstantPoolValue::addSelectionDAGCSEId(ID);
|
||||
}
|
||||
|
||||
void CSKYConstantPoolJT::print(raw_ostream &O) const {
|
||||
O << "JTI#" << JTI;
|
||||
CSKYConstantPoolValue::print(O);
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
//===-- CSKYConstantPoolValue.h - CSKY constantpool value -----*- C++ -*---===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the CSKY specific constantpool value class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TARGET_CSKY_CONSTANTPOOLVALUE_H
|
||||
#define LLVM_TARGET_CSKY_CONSTANTPOOLVALUE_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <cstddef>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BlockAddress;
|
||||
class Constant;
|
||||
class GlobalValue;
|
||||
class LLVMContext;
|
||||
class MachineBasicBlock;
|
||||
|
||||
namespace CSKYCP {
|
||||
enum CSKYCPKind {
|
||||
CPValue,
|
||||
CPExtSymbol,
|
||||
CPBlockAddress,
|
||||
CPMachineBasicBlock,
|
||||
CPJT
|
||||
};
|
||||
|
||||
enum CSKYCPModifier { NO_MOD, ADDR, GOT, GOTOFF, PLT, TLSLE, TLSIE, TLSGD };
|
||||
} // namespace CSKYCP
|
||||
|
||||
/// CSKYConstantPoolValue - CSKY specific constantpool value. This is used to
|
||||
/// represent PC-relative displacement between the address of the load
|
||||
/// instruction and the constant being loaded, i.e. (&GV-(LPIC+8)).
|
||||
class CSKYConstantPoolValue : public MachineConstantPoolValue {
|
||||
protected:
|
||||
CSKYCP::CSKYCPKind Kind; // Kind of constant.
|
||||
unsigned PCAdjust; // Extra adjustment if constantpool is pc-relative.
|
||||
CSKYCP::CSKYCPModifier Modifier; // GV modifier
|
||||
bool AddCurrentAddress;
|
||||
|
||||
unsigned LabelId = 0;
|
||||
|
||||
CSKYConstantPoolValue(Type *Ty, CSKYCP::CSKYCPKind Kind, unsigned PCAdjust,
|
||||
CSKYCP::CSKYCPModifier Modifier, bool AddCurrentAddress,
|
||||
unsigned ID = 0);
|
||||
|
||||
public:
|
||||
const char *getModifierText() const;
|
||||
unsigned getPCAdjustment() const { return PCAdjust; }
|
||||
bool mustAddCurrentAddress() const { return AddCurrentAddress; }
|
||||
CSKYCP::CSKYCPModifier getModifier() const { return Modifier; }
|
||||
unsigned getLabelID() const { return LabelId; }
|
||||
|
||||
bool isGlobalValue() const { return Kind == CSKYCP::CPValue; }
|
||||
bool isExtSymbol() const { return Kind == CSKYCP::CPExtSymbol; }
|
||||
bool isBlockAddress() const { return Kind == CSKYCP::CPBlockAddress; }
|
||||
bool isMachineBasicBlock() const {
|
||||
return Kind == CSKYCP::CPMachineBasicBlock;
|
||||
}
|
||||
bool isJT() const { return Kind == CSKYCP::CPJT; }
|
||||
|
||||
int getExistingMachineCPValue(MachineConstantPool *CP,
|
||||
Align Alignment) override;
|
||||
|
||||
void addSelectionDAGCSEId(FoldingSetNodeID &ID) override;
|
||||
|
||||
void print(raw_ostream &O) const override;
|
||||
|
||||
bool equals(const CSKYConstantPoolValue *A) const {
|
||||
return this->LabelId == A->LabelId && this->PCAdjust == A->PCAdjust &&
|
||||
this->Modifier == A->Modifier;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
int getExistingMachineCPValueImpl(MachineConstantPool *CP, Align Alignment) {
|
||||
const std::vector<MachineConstantPoolEntry> &Constants = CP->getConstants();
|
||||
for (unsigned i = 0, e = Constants.size(); i != e; ++i) {
|
||||
if (Constants[i].isMachineConstantPoolEntry() &&
|
||||
Constants[i].getAlign() >= Alignment) {
|
||||
auto *CPV =
|
||||
static_cast<CSKYConstantPoolValue *>(Constants[i].Val.MachineCPVal);
|
||||
if (Derived *APC = dyn_cast<Derived>(CPV))
|
||||
if (cast<Derived>(this)->equals(APC))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
/// CSKY-specific constant pool values for Constants,
|
||||
/// Functions, and BlockAddresses.
|
||||
class CSKYConstantPoolConstant : public CSKYConstantPoolValue {
|
||||
const Constant *CVal; // Constant being loaded.
|
||||
|
||||
CSKYConstantPoolConstant(const Constant *C, CSKYCP::CSKYCPKind Kind,
|
||||
unsigned PCAdjust, CSKYCP::CSKYCPModifier Modifier,
|
||||
bool AddCurrentAddress, unsigned ID);
|
||||
|
||||
public:
|
||||
static CSKYConstantPoolConstant *
|
||||
Create(const Constant *C, CSKYCP::CSKYCPKind Kind, unsigned PCAdjust,
|
||||
CSKYCP::CSKYCPModifier Modifier, bool AddCurrentAddress,
|
||||
unsigned ID = 0);
|
||||
const GlobalValue *getGV() const;
|
||||
const BlockAddress *getBlockAddress() const;
|
||||
|
||||
int getExistingMachineCPValue(MachineConstantPool *CP,
|
||||
Align Alignment) override;
|
||||
void addSelectionDAGCSEId(FoldingSetNodeID &ID) override;
|
||||
void print(raw_ostream &O) const override;
|
||||
|
||||
bool equals(const CSKYConstantPoolConstant *A) const {
|
||||
return CVal == A->CVal && CSKYConstantPoolValue::equals(A);
|
||||
}
|
||||
|
||||
static bool classof(const CSKYConstantPoolValue *APV) {
|
||||
return APV->isGlobalValue() || APV->isBlockAddress();
|
||||
}
|
||||
};
|
||||
|
||||
/// CSKYConstantPoolSymbol - CSKY-specific constantpool values for external
|
||||
/// symbols.
|
||||
class CSKYConstantPoolSymbol : public CSKYConstantPoolValue {
|
||||
const std::string S; // ExtSymbol being loaded.
|
||||
|
||||
CSKYConstantPoolSymbol(Type *Ty, const char *S, unsigned PCAdjust,
|
||||
CSKYCP::CSKYCPModifier Modifier,
|
||||
bool AddCurrentAddress);
|
||||
|
||||
public:
|
||||
static CSKYConstantPoolSymbol *Create(Type *Ty, const char *S,
|
||||
unsigned PCAdjust,
|
||||
CSKYCP::CSKYCPModifier Modifier);
|
||||
|
||||
StringRef getSymbol() const { return S; }
|
||||
|
||||
int getExistingMachineCPValue(MachineConstantPool *CP,
|
||||
Align Alignment) override;
|
||||
void addSelectionDAGCSEId(FoldingSetNodeID &ID) override;
|
||||
void print(raw_ostream &O) const override;
|
||||
|
||||
bool equals(const CSKYConstantPoolSymbol *A) const {
|
||||
return S == A->S && CSKYConstantPoolValue::equals(A);
|
||||
}
|
||||
|
||||
static bool classof(const CSKYConstantPoolValue *ACPV) {
|
||||
return ACPV->isExtSymbol();
|
||||
}
|
||||
};
|
||||
|
||||
/// CSKYConstantPoolMBB - CSKY-specific constantpool value of a machine basic
|
||||
/// block.
|
||||
class CSKYConstantPoolMBB : public CSKYConstantPoolValue {
|
||||
const MachineBasicBlock *MBB; // Machine basic block.
|
||||
|
||||
CSKYConstantPoolMBB(Type *Ty, const MachineBasicBlock *Mbb, unsigned PCAdjust,
|
||||
CSKYCP::CSKYCPModifier Modifier, bool AddCurrentAddress);
|
||||
|
||||
public:
|
||||
static CSKYConstantPoolMBB *Create(Type *Ty, const MachineBasicBlock *Mbb,
|
||||
unsigned PCAdjust);
|
||||
|
||||
const MachineBasicBlock *getMBB() const { return MBB; }
|
||||
|
||||
int getExistingMachineCPValue(MachineConstantPool *CP,
|
||||
Align Alignment) override;
|
||||
void addSelectionDAGCSEId(FoldingSetNodeID &ID) override;
|
||||
void print(raw_ostream &O) const override;
|
||||
|
||||
bool equals(const CSKYConstantPoolMBB *A) const {
|
||||
return MBB == A->MBB && CSKYConstantPoolValue::equals(A);
|
||||
}
|
||||
|
||||
static bool classof(const CSKYConstantPoolValue *ACPV) {
|
||||
return ACPV->isMachineBasicBlock();
|
||||
}
|
||||
};
|
||||
|
||||
/// CSKY-specific constantpool value of a jump table.
|
||||
class CSKYConstantPoolJT : public CSKYConstantPoolValue {
|
||||
signed JTI; // Machine basic block.
|
||||
|
||||
CSKYConstantPoolJT(Type *Ty, int JTIndex, unsigned PCAdj,
|
||||
CSKYCP::CSKYCPModifier Modifier, bool AddCurrentAddress);
|
||||
|
||||
public:
|
||||
static CSKYConstantPoolJT *Create(Type *Ty, int JTI, unsigned PCAdj,
|
||||
CSKYCP::CSKYCPModifier Modifier);
|
||||
|
||||
signed getJTI() { return JTI; }
|
||||
|
||||
int getExistingMachineCPValue(MachineConstantPool *CP,
|
||||
Align Alignment) override;
|
||||
void addSelectionDAGCSEId(FoldingSetNodeID &ID) override;
|
||||
void print(raw_ostream &O) const override;
|
||||
|
||||
bool equals(const CSKYConstantPoolJT *A) const {
|
||||
return JTI == A->JTI && CSKYConstantPoolValue::equals(A);
|
||||
}
|
||||
|
||||
static bool classof(const CSKYConstantPoolValue *ACPV) {
|
||||
return ACPV->isJT();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
|
@ -68,6 +68,13 @@ void CSKYDAGToDAGISel::Select(SDNode *N) {
|
|||
case ISD::SUBCARRY:
|
||||
IsSelected = selectSubCarry(N);
|
||||
break;
|
||||
case ISD::GLOBAL_OFFSET_TABLE: {
|
||||
Register GP = Subtarget->getInstrInfo()->getGlobalBaseReg(*MF);
|
||||
ReplaceNode(N, CurDAG->getRegister(GP, N->getValueType(0)).getNode());
|
||||
|
||||
IsSelected = true;
|
||||
break;
|
||||
}
|
||||
case ISD::FrameIndex: {
|
||||
SDValue Imm = CurDAG->getTargetConstant(0, Dl, MVT::i32);
|
||||
int FI = cast<FrameIndexSDNode>(N)->getIndex();
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "CSKYISelLowering.h"
|
||||
#include "CSKYCallingConv.h"
|
||||
#include "CSKYConstantPoolValue.h"
|
||||
#include "CSKYMachineFunctionInfo.h"
|
||||
#include "CSKYRegisterInfo.h"
|
||||
#include "CSKYSubtarget.h"
|
||||
|
@ -41,6 +42,63 @@ CSKYTargetLowering::CSKYTargetLowering(const TargetMachine &TM,
|
|||
setOperationAction(ISD::SUBCARRY, MVT::i32, Legal);
|
||||
setOperationAction(ISD::BITREVERSE, MVT::i32, Legal);
|
||||
|
||||
setOperationAction(ISD::SREM, MVT::i32, Expand);
|
||||
setOperationAction(ISD::UREM, MVT::i32, Expand);
|
||||
setOperationAction(ISD::UDIVREM, MVT::i32, Expand);
|
||||
setOperationAction(ISD::SDIVREM, MVT::i32, Expand);
|
||||
setOperationAction(ISD::CTTZ, MVT::i32, Expand);
|
||||
setOperationAction(ISD::CTPOP, MVT::i32, Expand);
|
||||
setOperationAction(ISD::ROTR, MVT::i32, Expand);
|
||||
setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);
|
||||
setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand);
|
||||
setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
|
||||
setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand);
|
||||
setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand);
|
||||
setOperationAction(ISD::SELECT_CC, MVT::i32, Expand);
|
||||
setOperationAction(ISD::BR_CC, MVT::i32, Expand);
|
||||
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
|
||||
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand);
|
||||
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
|
||||
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
|
||||
setOperationAction(ISD::MULHS, MVT::i32, Expand);
|
||||
setOperationAction(ISD::MULHU, MVT::i32, Expand);
|
||||
setOperationAction(ISD::VAARG, MVT::Other, Expand);
|
||||
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
|
||||
setOperationAction(ISD::VAEND, MVT::Other, Expand);
|
||||
|
||||
setLoadExtAction(ISD::EXTLOAD, MVT::i32, MVT::i1, Promote);
|
||||
setLoadExtAction(ISD::SEXTLOAD, MVT::i32, MVT::i1, Promote);
|
||||
setLoadExtAction(ISD::ZEXTLOAD, MVT::i32, MVT::i1, Promote);
|
||||
|
||||
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
|
||||
setOperationAction(ISD::ExternalSymbol, MVT::i32, Custom);
|
||||
setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom);
|
||||
setOperationAction(ISD::BlockAddress, MVT::i32, Custom);
|
||||
setOperationAction(ISD::JumpTable, MVT::i32, Custom);
|
||||
setOperationAction(ISD::VASTART, MVT::Other, Custom);
|
||||
|
||||
if (!Subtarget.hasE2()) {
|
||||
setLoadExtAction(ISD::SEXTLOAD, MVT::i32, MVT::i8, Expand);
|
||||
setLoadExtAction(ISD::SEXTLOAD, MVT::i32, MVT::i16, Expand);
|
||||
setOperationAction(ISD::CTLZ, MVT::i32, Expand);
|
||||
setOperationAction(ISD::BSWAP, MVT::i32, Expand);
|
||||
}
|
||||
|
||||
if (!Subtarget.has2E3()) {
|
||||
setOperationAction(ISD::ABS, MVT::i32, Expand);
|
||||
setOperationAction(ISD::BITREVERSE, MVT::i32, Expand);
|
||||
setOperationAction(ISD::SDIV, MVT::i32, Expand);
|
||||
setOperationAction(ISD::UDIV, MVT::i32, Expand);
|
||||
}
|
||||
|
||||
if (!Subtarget.has3r2E3r3()) {
|
||||
setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand);
|
||||
}
|
||||
|
||||
setOperationAction(ISD::ADDCARRY, MVT::i32, Legal);
|
||||
setOperationAction(ISD::SUBCARRY, MVT::i32, Legal);
|
||||
setOperationAction(ISD::BITREVERSE, MVT::i32, Legal);
|
||||
|
||||
setOperationAction(ISD::SREM, MVT::i32, Expand);
|
||||
setOperationAction(ISD::UREM, MVT::i32, Expand);
|
||||
setOperationAction(ISD::UDIVREM, MVT::i32, Expand);
|
||||
|
@ -95,6 +153,28 @@ CSKYTargetLowering::CSKYTargetLowering(const TargetMachine &TM,
|
|||
setSchedulingPreference(Sched::Source);
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::LowerOperation(SDValue Op,
|
||||
SelectionDAG &DAG) const {
|
||||
switch (Op.getOpcode()) {
|
||||
default:
|
||||
llvm_unreachable("unimplemented op");
|
||||
case ISD::GlobalAddress:
|
||||
return LowerGlobalAddress(Op, DAG);
|
||||
case ISD::ExternalSymbol:
|
||||
return LowerExternalSymbol(Op, DAG);
|
||||
case ISD::JumpTable:
|
||||
return LowerJumpTable(Op, DAG);
|
||||
case ISD::BlockAddress:
|
||||
return LowerBlockAddress(Op, DAG);
|
||||
case ISD::VASTART:
|
||||
return LowerVASTART(Op, DAG);
|
||||
case ISD::FRAMEADDR:
|
||||
return LowerFRAMEADDR(Op, DAG);
|
||||
case ISD::RETURNADDR:
|
||||
return LowerRETURNADDR(Op, DAG);
|
||||
}
|
||||
}
|
||||
|
||||
EVT CSKYTargetLowering::getSetCCResultType(const DataLayout &DL,
|
||||
LLVMContext &Context, EVT VT) const {
|
||||
if (!VT.isVector())
|
||||
|
@ -148,6 +228,14 @@ static SDValue unpackFromRegLoc(const CSKYSubtarget &Subtarget,
|
|||
case MVT::i32:
|
||||
RC = &CSKY::GPRRegClass;
|
||||
break;
|
||||
case MVT::f32:
|
||||
RC = Subtarget.hasFPUv2SingleFloat() ? &CSKY::sFPR32RegClass
|
||||
: &CSKY::FPR32RegClass;
|
||||
break;
|
||||
case MVT::f64:
|
||||
RC = Subtarget.hasFPUv2DoubleFloat() ? &CSKY::sFPR64RegClass
|
||||
: &CSKY::FPR64RegClass;
|
||||
break;
|
||||
}
|
||||
|
||||
Register VReg = RegInfo.createVirtualRegister(RC);
|
||||
|
@ -184,6 +272,44 @@ static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain,
|
|||
return Val;
|
||||
}
|
||||
|
||||
static SDValue unpack64(SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA,
|
||||
const SDLoc &DL) {
|
||||
assert(VA.getLocVT() == MVT::i32 &&
|
||||
(VA.getValVT() == MVT::f64 || VA.getValVT() == MVT::i64) &&
|
||||
"Unexpected VA");
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
MachineRegisterInfo &RegInfo = MF.getRegInfo();
|
||||
|
||||
if (VA.isMemLoc()) {
|
||||
// f64/i64 is passed on the stack.
|
||||
int FI = MFI.CreateFixedObject(8, VA.getLocMemOffset(), /*Immutable=*/true);
|
||||
SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
|
||||
return DAG.getLoad(VA.getValVT(), DL, Chain, FIN,
|
||||
MachinePointerInfo::getFixedStack(MF, FI));
|
||||
}
|
||||
|
||||
assert(VA.isRegLoc() && "Expected register VA assignment");
|
||||
|
||||
Register LoVReg = RegInfo.createVirtualRegister(&CSKY::GPRRegClass);
|
||||
RegInfo.addLiveIn(VA.getLocReg(), LoVReg);
|
||||
SDValue Lo = DAG.getCopyFromReg(Chain, DL, LoVReg, MVT::i32);
|
||||
SDValue Hi;
|
||||
if (VA.getLocReg() == CSKY::R3) {
|
||||
// Second half of f64/i64 is passed on the stack.
|
||||
int FI = MFI.CreateFixedObject(4, 0, /*Immutable=*/true);
|
||||
SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
|
||||
Hi = DAG.getLoad(MVT::i32, DL, Chain, FIN,
|
||||
MachinePointerInfo::getFixedStack(MF, FI));
|
||||
} else {
|
||||
// Second half of f64/i64 is passed in another GPR.
|
||||
Register HiVReg = RegInfo.createVirtualRegister(&CSKY::GPRRegClass);
|
||||
RegInfo.addLiveIn(VA.getLocReg() + 1, HiVReg);
|
||||
Hi = DAG.getCopyFromReg(Chain, DL, HiVReg, MVT::i32);
|
||||
}
|
||||
return DAG.getNode(CSKYISD::BITCAST_FROM_LOHI, DL, VA.getValVT(), Lo, Hi);
|
||||
}
|
||||
|
||||
// Transform physical registers into virtual registers.
|
||||
SDValue CSKYTargetLowering::LowerFormalArguments(
|
||||
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
|
||||
|
@ -213,7 +339,11 @@ SDValue CSKYTargetLowering::LowerFormalArguments(
|
|||
CCValAssign &VA = ArgLocs[i];
|
||||
SDValue ArgValue;
|
||||
|
||||
if (VA.isRegLoc())
|
||||
bool IsF64OnCSKY = VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64;
|
||||
|
||||
if (IsF64OnCSKY)
|
||||
ArgValue = unpack64(DAG, Chain, VA, DL);
|
||||
else if (VA.isRegLoc())
|
||||
ArgValue = unpackFromRegLoc(Subtarget, DAG, Chain, VA, DL);
|
||||
else
|
||||
ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
|
||||
|
@ -357,6 +487,255 @@ CSKYTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
|
|||
return DAG.getNode(CSKYISD::RET, DL, MVT::Other, RetOps);
|
||||
}
|
||||
|
||||
// Lower a call to a callseq_start + CALL + callseq_end chain, and add input
|
||||
// and output parameter nodes.
|
||||
SDValue CSKYTargetLowering::LowerCall(CallLoweringInfo &CLI,
|
||||
SmallVectorImpl<SDValue> &InVals) const {
|
||||
SelectionDAG &DAG = CLI.DAG;
|
||||
SDLoc &DL = CLI.DL;
|
||||
SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
|
||||
SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
|
||||
SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
|
||||
SDValue Chain = CLI.Chain;
|
||||
SDValue Callee = CLI.Callee;
|
||||
bool &IsTailCall = CLI.IsTailCall;
|
||||
CallingConv::ID CallConv = CLI.CallConv;
|
||||
bool IsVarArg = CLI.IsVarArg;
|
||||
EVT PtrVT = getPointerTy(DAG.getDataLayout());
|
||||
MVT XLenVT = MVT::i32;
|
||||
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
|
||||
// Analyze the operands of the call, assigning locations to each operand.
|
||||
SmallVector<CCValAssign, 16> ArgLocs;
|
||||
CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
|
||||
|
||||
ArgCCInfo.AnalyzeCallOperands(Outs, CCAssignFnForCall(CallConv, IsVarArg));
|
||||
|
||||
// Check if it's really possible to do a tail call.
|
||||
if (IsTailCall)
|
||||
IsTailCall = false; // TODO: TailCallOptimization;
|
||||
|
||||
if (IsTailCall)
|
||||
++NumTailCalls;
|
||||
else if (CLI.CB && CLI.CB->isMustTailCall())
|
||||
report_fatal_error("failed to perform tail call elimination on a call "
|
||||
"site marked musttail");
|
||||
|
||||
// Get a count of how many bytes are to be pushed on the stack.
|
||||
unsigned NumBytes = ArgCCInfo.getNextStackOffset();
|
||||
|
||||
// Create local copies for byval args
|
||||
SmallVector<SDValue, 8> ByValArgs;
|
||||
for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
|
||||
ISD::ArgFlagsTy Flags = Outs[i].Flags;
|
||||
if (!Flags.isByVal())
|
||||
continue;
|
||||
|
||||
SDValue Arg = OutVals[i];
|
||||
unsigned Size = Flags.getByValSize();
|
||||
Align Alignment = Flags.getNonZeroByValAlign();
|
||||
|
||||
int FI =
|
||||
MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
|
||||
SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
|
||||
SDValue SizeNode = DAG.getConstant(Size, DL, XLenVT);
|
||||
|
||||
Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment,
|
||||
/*IsVolatile=*/false,
|
||||
/*AlwaysInline=*/false, IsTailCall,
|
||||
MachinePointerInfo(), MachinePointerInfo());
|
||||
ByValArgs.push_back(FIPtr);
|
||||
}
|
||||
|
||||
if (!IsTailCall)
|
||||
Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
|
||||
|
||||
// Copy argument values to their designated locations.
|
||||
SmallVector<std::pair<Register, SDValue>, 8> RegsToPass;
|
||||
SmallVector<SDValue, 8> MemOpChains;
|
||||
SDValue StackPtr;
|
||||
for (unsigned i = 0, j = 0, e = ArgLocs.size(); i != e; ++i) {
|
||||
CCValAssign &VA = ArgLocs[i];
|
||||
SDValue ArgValue = OutVals[i];
|
||||
ISD::ArgFlagsTy Flags = Outs[i].Flags;
|
||||
|
||||
bool IsF64OnCSKY = VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64;
|
||||
|
||||
if (IsF64OnCSKY && VA.isRegLoc()) {
|
||||
SDValue Split64 =
|
||||
DAG.getNode(CSKYISD::BITCAST_TO_LOHI, DL,
|
||||
DAG.getVTList(MVT::i32, MVT::i32), ArgValue);
|
||||
SDValue Lo = Split64.getValue(0);
|
||||
SDValue Hi = Split64.getValue(1);
|
||||
|
||||
Register RegLo = VA.getLocReg();
|
||||
RegsToPass.push_back(std::make_pair(RegLo, Lo));
|
||||
|
||||
if (RegLo == CSKY::R3) {
|
||||
// Second half of f64/i64 is passed on the stack.
|
||||
// Work out the address of the stack slot.
|
||||
if (!StackPtr.getNode())
|
||||
StackPtr = DAG.getCopyFromReg(Chain, DL, CSKY::R14, PtrVT);
|
||||
// Emit the store.
|
||||
MemOpChains.push_back(
|
||||
DAG.getStore(Chain, DL, Hi, StackPtr, MachinePointerInfo()));
|
||||
} else {
|
||||
// Second half of f64/i64 is passed in another GPR.
|
||||
assert(RegLo < CSKY::R31 && "Invalid register pair");
|
||||
Register RegHigh = RegLo + 1;
|
||||
RegsToPass.push_back(std::make_pair(RegHigh, Hi));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL);
|
||||
|
||||
// Use local copy if it is a byval arg.
|
||||
if (Flags.isByVal())
|
||||
ArgValue = ByValArgs[j++];
|
||||
|
||||
if (VA.isRegLoc()) {
|
||||
// Queue up the argument copies and emit them at the end.
|
||||
RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
|
||||
} else {
|
||||
assert(VA.isMemLoc() && "Argument not register or memory");
|
||||
assert(!IsTailCall && "Tail call not allowed if stack is used "
|
||||
"for passing parameters");
|
||||
|
||||
// Work out the address of the stack slot.
|
||||
if (!StackPtr.getNode())
|
||||
StackPtr = DAG.getCopyFromReg(Chain, DL, CSKY::R14, PtrVT);
|
||||
SDValue Address =
|
||||
DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
|
||||
DAG.getIntPtrConstant(VA.getLocMemOffset(), DL));
|
||||
|
||||
// Emit the store.
|
||||
MemOpChains.push_back(
|
||||
DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
|
||||
}
|
||||
}
|
||||
|
||||
// Join the stores, which are independent of one another.
|
||||
if (!MemOpChains.empty())
|
||||
Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
|
||||
|
||||
SDValue Glue;
|
||||
|
||||
// Build a sequence of copy-to-reg nodes, chained and glued together.
|
||||
for (auto &Reg : RegsToPass) {
|
||||
Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
|
||||
Glue = Chain.getValue(1);
|
||||
}
|
||||
|
||||
SmallVector<SDValue, 8> Ops;
|
||||
EVT Ty = getPointerTy(DAG.getDataLayout());
|
||||
bool IsRegCall = false;
|
||||
|
||||
Ops.push_back(Chain);
|
||||
|
||||
if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) {
|
||||
const GlobalValue *GV = S->getGlobal();
|
||||
bool IsLocal =
|
||||
getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV);
|
||||
|
||||
if (isPositionIndependent() || !Subtarget.has2E3()) {
|
||||
IsRegCall = true;
|
||||
Ops.push_back(getAddr<GlobalAddressSDNode, true>(S, DAG, IsLocal));
|
||||
} else {
|
||||
Ops.push_back(getTargetNode(cast<GlobalAddressSDNode>(Callee), DL, Ty,
|
||||
DAG, CSKYII::MO_None));
|
||||
Ops.push_back(getTargetConstantPoolValue(
|
||||
cast<GlobalAddressSDNode>(Callee), Ty, DAG, CSKYII::MO_None));
|
||||
}
|
||||
} else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
|
||||
bool IsLocal = getTargetMachine().shouldAssumeDSOLocal(
|
||||
*MF.getFunction().getParent(), nullptr);
|
||||
|
||||
if (isPositionIndependent() || !Subtarget.has2E3()) {
|
||||
IsRegCall = true;
|
||||
Ops.push_back(getAddr<ExternalSymbolSDNode, true>(S, DAG, IsLocal));
|
||||
} else {
|
||||
Ops.push_back(getTargetNode(cast<ExternalSymbolSDNode>(Callee), DL, Ty,
|
||||
DAG, CSKYII::MO_None));
|
||||
Ops.push_back(getTargetConstantPoolValue(
|
||||
cast<ExternalSymbolSDNode>(Callee), Ty, DAG, CSKYII::MO_None));
|
||||
}
|
||||
} else {
|
||||
IsRegCall = true;
|
||||
Ops.push_back(Callee);
|
||||
}
|
||||
|
||||
// Add argument registers to the end of the list so that they are
|
||||
// known live into the call.
|
||||
for (auto &Reg : RegsToPass)
|
||||
Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
|
||||
|
||||
if (!IsTailCall) {
|
||||
// Add a register mask operand representing the call-preserved registers.
|
||||
const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
|
||||
const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
|
||||
assert(Mask && "Missing call preserved mask for calling convention");
|
||||
Ops.push_back(DAG.getRegisterMask(Mask));
|
||||
}
|
||||
|
||||
// Glue the call to the argument copies, if any.
|
||||
if (Glue.getNode())
|
||||
Ops.push_back(Glue);
|
||||
|
||||
// Emit the call.
|
||||
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
|
||||
|
||||
if (IsTailCall) {
|
||||
MF.getFrameInfo().setHasTailCall();
|
||||
return DAG.getNode(IsRegCall ? CSKYISD::TAILReg : CSKYISD::TAIL, DL,
|
||||
NodeTys, Ops);
|
||||
}
|
||||
|
||||
Chain = DAG.getNode(IsRegCall ? CSKYISD::CALLReg : CSKYISD::CALL, DL, NodeTys,
|
||||
Ops);
|
||||
DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
|
||||
Glue = Chain.getValue(1);
|
||||
|
||||
// Mark the end of the call, which is glued to the call itself.
|
||||
Chain = DAG.getCALLSEQ_END(Chain, DAG.getConstant(NumBytes, DL, PtrVT, true),
|
||||
DAG.getConstant(0, DL, PtrVT, true), Glue, DL);
|
||||
Glue = Chain.getValue(1);
|
||||
|
||||
// Assign locations to each value returned by this call.
|
||||
SmallVector<CCValAssign, 16> CSKYLocs;
|
||||
CCState RetCCInfo(CallConv, IsVarArg, MF, CSKYLocs, *DAG.getContext());
|
||||
RetCCInfo.AnalyzeCallResult(Ins, CCAssignFnForReturn(CallConv, IsVarArg));
|
||||
|
||||
// Copy all of the result registers out of their specified physreg.
|
||||
for (auto &VA : CSKYLocs) {
|
||||
// Copy the value out
|
||||
SDValue RetValue =
|
||||
DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
|
||||
// Glue the RetValue to the end of the call sequence
|
||||
Chain = RetValue.getValue(1);
|
||||
Glue = RetValue.getValue(2);
|
||||
|
||||
bool IsF64OnCSKY = VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64;
|
||||
|
||||
if (IsF64OnCSKY) {
|
||||
assert(VA.getLocReg() == GPRArgRegs[0] && "Unexpected reg assignment");
|
||||
SDValue RetValue2 =
|
||||
DAG.getCopyFromReg(Chain, DL, GPRArgRegs[1], MVT::i32, Glue);
|
||||
Chain = RetValue2.getValue(1);
|
||||
Glue = RetValue2.getValue(2);
|
||||
RetValue = DAG.getNode(CSKYISD::BITCAST_FROM_LOHI, DL, VA.getValVT(),
|
||||
RetValue, RetValue2);
|
||||
}
|
||||
|
||||
RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL);
|
||||
|
||||
InVals.push_back(RetValue);
|
||||
}
|
||||
|
||||
return Chain;
|
||||
}
|
||||
|
||||
CCAssignFn *CSKYTargetLowering::CCAssignFnForReturn(CallingConv::ID CC,
|
||||
bool IsVarArg) const {
|
||||
if (IsVarArg || !Subtarget.useHardFloatABI())
|
||||
|
@ -373,6 +752,165 @@ CCAssignFn *CSKYTargetLowering::CCAssignFnForCall(CallingConv::ID CC,
|
|||
return CC_CSKY_ABIV2_FP;
|
||||
}
|
||||
|
||||
static CSKYCP::CSKYCPModifier getModifier(unsigned Flags) {
|
||||
|
||||
if (Flags == CSKYII::MO_ADDR32)
|
||||
return CSKYCP::ADDR;
|
||||
else if (Flags == CSKYII::MO_GOT32)
|
||||
return CSKYCP::GOT;
|
||||
else if (Flags == CSKYII::MO_GOTOFF)
|
||||
return CSKYCP::GOTOFF;
|
||||
else if (Flags == CSKYII::MO_PLT32)
|
||||
return CSKYCP::PLT;
|
||||
else if (Flags == CSKYII::MO_None)
|
||||
return CSKYCP::NO_MOD;
|
||||
else
|
||||
assert(0 && "unknown CSKYII Modifier");
|
||||
return CSKYCP::NO_MOD;
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::getTargetConstantPoolValue(GlobalAddressSDNode *N,
|
||||
EVT Ty,
|
||||
SelectionDAG &DAG,
|
||||
unsigned Flags) const {
|
||||
CSKYConstantPoolValue *CPV = CSKYConstantPoolConstant::Create(
|
||||
N->getGlobal(), CSKYCP::CPValue, 0, getModifier(Flags), false);
|
||||
|
||||
return DAG.getTargetConstantPool(CPV, Ty);
|
||||
}
|
||||
|
||||
static MachineBasicBlock *
|
||||
emitSelectPseudo(MachineInstr &MI, MachineBasicBlock *BB, unsigned Opcode) {
|
||||
|
||||
const TargetInstrInfo &TII = *BB->getParent()->getSubtarget().getInstrInfo();
|
||||
DebugLoc DL = MI.getDebugLoc();
|
||||
|
||||
// To "insert" a SELECT instruction, we actually have to insert the
|
||||
// diamond control-flow pattern. The incoming instruction knows the
|
||||
// destination vreg to set, the condition code register to branch on, the
|
||||
// true/false values to select between, and a branch opcode to use.
|
||||
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
||||
MachineFunction::iterator It = ++BB->getIterator();
|
||||
|
||||
// thisMBB:
|
||||
// ...
|
||||
// TrueVal = ...
|
||||
// bt32 c, sinkMBB
|
||||
// fallthrough --> copyMBB
|
||||
MachineBasicBlock *thisMBB = BB;
|
||||
MachineFunction *F = BB->getParent();
|
||||
MachineBasicBlock *copyMBB = F->CreateMachineBasicBlock(LLVM_BB);
|
||||
MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB);
|
||||
F->insert(It, copyMBB);
|
||||
F->insert(It, sinkMBB);
|
||||
|
||||
// Transfer the remainder of BB and its successor edges to sinkMBB.
|
||||
sinkMBB->splice(sinkMBB->begin(), BB,
|
||||
std::next(MachineBasicBlock::iterator(MI)), BB->end());
|
||||
sinkMBB->transferSuccessorsAndUpdatePHIs(BB);
|
||||
|
||||
// Next, add the true and fallthrough blocks as its successors.
|
||||
BB->addSuccessor(copyMBB);
|
||||
BB->addSuccessor(sinkMBB);
|
||||
|
||||
// bt32 condition, sinkMBB
|
||||
BuildMI(BB, DL, TII.get(Opcode))
|
||||
.addReg(MI.getOperand(1).getReg())
|
||||
.addMBB(sinkMBB);
|
||||
|
||||
// copyMBB:
|
||||
// %FalseValue = ...
|
||||
// # fallthrough to sinkMBB
|
||||
BB = copyMBB;
|
||||
|
||||
// Update machine-CFG edges
|
||||
BB->addSuccessor(sinkMBB);
|
||||
|
||||
// sinkMBB:
|
||||
// %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copyMBB ]
|
||||
// ...
|
||||
BB = sinkMBB;
|
||||
|
||||
BuildMI(*BB, BB->begin(), DL, TII.get(CSKY::PHI), MI.getOperand(0).getReg())
|
||||
.addReg(MI.getOperand(2).getReg())
|
||||
.addMBB(thisMBB)
|
||||
.addReg(MI.getOperand(3).getReg())
|
||||
.addMBB(copyMBB);
|
||||
|
||||
MI.eraseFromParent(); // The pseudo instruction is gone now.
|
||||
|
||||
return BB;
|
||||
}
|
||||
|
||||
MachineBasicBlock *
|
||||
CSKYTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
|
||||
MachineBasicBlock *BB) const {
|
||||
switch (MI.getOpcode()) {
|
||||
default:
|
||||
llvm_unreachable("Unexpected instr type to insert");
|
||||
case CSKY::ISEL32:
|
||||
return emitSelectPseudo(MI, BB, CSKY::BT32);
|
||||
case CSKY::ISEL16:
|
||||
return emitSelectPseudo(MI, BB, CSKY::BT16);
|
||||
}
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::getTargetConstantPoolValue(ExternalSymbolSDNode *N,
|
||||
EVT Ty,
|
||||
SelectionDAG &DAG,
|
||||
unsigned Flags) const {
|
||||
CSKYConstantPoolValue *CPV =
|
||||
CSKYConstantPoolSymbol::Create(Type::getInt32Ty(*DAG.getContext()),
|
||||
N->getSymbol(), 0, getModifier(Flags));
|
||||
|
||||
return DAG.getTargetConstantPool(CPV, Ty);
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::getTargetConstantPoolValue(JumpTableSDNode *N,
|
||||
EVT Ty,
|
||||
SelectionDAG &DAG,
|
||||
unsigned Flags) const {
|
||||
CSKYConstantPoolValue *CPV =
|
||||
CSKYConstantPoolJT::Create(Type::getInt32Ty(*DAG.getContext()),
|
||||
N->getIndex(), 0, getModifier(Flags));
|
||||
return DAG.getTargetConstantPool(CPV, Ty);
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::getTargetConstantPoolValue(BlockAddressSDNode *N,
|
||||
EVT Ty,
|
||||
SelectionDAG &DAG,
|
||||
unsigned Flags) const {
|
||||
CSKYConstantPoolValue *CPV = CSKYConstantPoolConstant::Create(
|
||||
N->getBlockAddress(), CSKYCP::CPBlockAddress, 0, getModifier(Flags),
|
||||
false);
|
||||
return DAG.getTargetConstantPool(CPV, Ty);
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::getTargetNode(GlobalAddressSDNode *N, SDLoc DL,
|
||||
EVT Ty, SelectionDAG &DAG,
|
||||
unsigned Flags) const {
|
||||
return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::getTargetNode(ExternalSymbolSDNode *N, SDLoc DL,
|
||||
EVT Ty, SelectionDAG &DAG,
|
||||
unsigned Flags) const {
|
||||
return DAG.getTargetExternalSymbol(N->getSymbol(), Ty, Flags);
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::getTargetNode(JumpTableSDNode *N, SDLoc DL, EVT Ty,
|
||||
SelectionDAG &DAG,
|
||||
unsigned Flags) const {
|
||||
return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags);
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::getTargetNode(BlockAddressSDNode *N, SDLoc DL,
|
||||
EVT Ty, SelectionDAG &DAG,
|
||||
unsigned Flags) const {
|
||||
return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
|
||||
Flags);
|
||||
}
|
||||
|
||||
const char *CSKYTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||
switch (Opcode) {
|
||||
default:
|
||||
|
@ -383,7 +921,130 @@ const char *CSKYTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
|||
return "CSKYISD::NIR";
|
||||
case CSKYISD::RET:
|
||||
return "CSKYISD::RET";
|
||||
case CSKYISD::CALL:
|
||||
return "CSKYISD::CALL";
|
||||
case CSKYISD::CALLReg:
|
||||
return "CSKYISD::CALLReg";
|
||||
case CSKYISD::TAIL:
|
||||
return "CSKYISD::TAIL";
|
||||
case CSKYISD::TAILReg:
|
||||
return "CSKYISD::TAILReg";
|
||||
case CSKYISD::LOAD_ADDR:
|
||||
return "CSKYISD::LOAD_ADDR";
|
||||
case CSKYISD::BITCAST_TO_LOHI:
|
||||
return "CSKYISD::BITCAST_TO_LOHI";
|
||||
case CSKYISD::BITCAST_FROM_LOHI:
|
||||
return "CSKYISD::BITCAST_FROM_LOHI";
|
||||
}
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::LowerGlobalAddress(SDValue Op,
|
||||
SelectionDAG &DAG) const {
|
||||
SDLoc DL(Op);
|
||||
EVT Ty = Op.getValueType();
|
||||
GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
|
||||
int64_t Offset = N->getOffset();
|
||||
|
||||
const GlobalValue *GV = N->getGlobal();
|
||||
bool IsLocal = getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV);
|
||||
SDValue Addr = getAddr<GlobalAddressSDNode, false>(N, DAG, IsLocal);
|
||||
|
||||
// In order to maximise the opportunity for common subexpression elimination,
|
||||
// emit a separate ADD node for the global address offset instead of folding
|
||||
// it in the global address node. Later peephole optimisations may choose to
|
||||
// fold it back in when profitable.
|
||||
if (Offset != 0)
|
||||
return DAG.getNode(ISD::ADD, DL, Ty, Addr,
|
||||
DAG.getConstant(Offset, DL, MVT::i32));
|
||||
return Addr;
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::LowerExternalSymbol(SDValue Op,
|
||||
SelectionDAG &DAG) const {
|
||||
ExternalSymbolSDNode *N = cast<ExternalSymbolSDNode>(Op);
|
||||
|
||||
return getAddr(N, DAG, false);
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::LowerJumpTable(SDValue Op,
|
||||
SelectionDAG &DAG) const {
|
||||
JumpTableSDNode *N = cast<JumpTableSDNode>(Op);
|
||||
|
||||
return getAddr<JumpTableSDNode, false>(N, DAG);
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::LowerBlockAddress(SDValue Op,
|
||||
SelectionDAG &DAG) const {
|
||||
BlockAddressSDNode *N = cast<BlockAddressSDNode>(Op);
|
||||
|
||||
return getAddr(N, DAG);
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const {
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
CSKYMachineFunctionInfo *FuncInfo = MF.getInfo<CSKYMachineFunctionInfo>();
|
||||
|
||||
SDLoc DL(Op);
|
||||
SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(),
|
||||
getPointerTy(MF.getDataLayout()));
|
||||
|
||||
// vastart just stores the address of the VarArgsFrameIndex slot into the
|
||||
// memory location argument.
|
||||
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
|
||||
return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1),
|
||||
MachinePointerInfo(SV));
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::LowerFRAMEADDR(SDValue Op,
|
||||
SelectionDAG &DAG) const {
|
||||
const CSKYRegisterInfo &RI = *Subtarget.getRegisterInfo();
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
MFI.setFrameAddressIsTaken(true);
|
||||
|
||||
EVT VT = Op.getValueType();
|
||||
SDLoc dl(Op);
|
||||
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
|
||||
Register FrameReg = RI.getFrameRegister(MF);
|
||||
SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT);
|
||||
while (Depth--)
|
||||
FrameAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), FrameAddr,
|
||||
MachinePointerInfo());
|
||||
return FrameAddr;
|
||||
}
|
||||
|
||||
SDValue CSKYTargetLowering::LowerRETURNADDR(SDValue Op,
|
||||
SelectionDAG &DAG) const {
|
||||
const CSKYRegisterInfo &RI = *Subtarget.getRegisterInfo();
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
MFI.setReturnAddressIsTaken(true);
|
||||
|
||||
if (verifyReturnAddressArgumentIsConstant(Op, DAG))
|
||||
return SDValue();
|
||||
|
||||
EVT VT = Op.getValueType();
|
||||
SDLoc dl(Op);
|
||||
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
|
||||
if (Depth) {
|
||||
SDValue FrameAddr = LowerFRAMEADDR(Op, DAG);
|
||||
SDValue Offset = DAG.getConstant(4, dl, MVT::i32);
|
||||
return DAG.getLoad(VT, dl, DAG.getEntryNode(),
|
||||
DAG.getNode(ISD::ADD, dl, VT, FrameAddr, Offset),
|
||||
MachinePointerInfo());
|
||||
}
|
||||
// Return the value of the return address register, marking it an implicit
|
||||
// live-in.
|
||||
unsigned Reg = MF.addLiveIn(RI.getRARegister(), getRegClassFor(MVT::i32));
|
||||
return DAG.getCopyFromReg(DAG.getEntryNode(), dl, Reg, VT);
|
||||
}
|
||||
|
||||
Register CSKYTargetLowering::getExceptionPointerRegister(
|
||||
const Constant *PersonalityFn) const {
|
||||
return CSKY::R0;
|
||||
}
|
||||
|
||||
Register CSKYTargetLowering::getExceptionSelectorRegister(
|
||||
const Constant *PersonalityFn) const {
|
||||
return CSKY::R1;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,15 @@ enum NodeType : unsigned {
|
|||
NIE,
|
||||
NIR,
|
||||
RET,
|
||||
BITCAST_TO_LOHI
|
||||
CALL,
|
||||
CALLReg,
|
||||
TAIL,
|
||||
TAILReg,
|
||||
LOAD_ADDR,
|
||||
// i32, i32 <-- f64
|
||||
BITCAST_TO_LOHI,
|
||||
// f64 < -- i32, i32
|
||||
BITCAST_FROM_LOHI,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -38,6 +46,8 @@ public:
|
|||
explicit CSKYTargetLowering(const TargetMachine &TM,
|
||||
const CSKYSubtarget &STI);
|
||||
|
||||
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
|
||||
|
||||
EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context,
|
||||
EVT VT) const override;
|
||||
|
||||
|
@ -58,8 +68,92 @@ private:
|
|||
const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
|
||||
SelectionDAG &DAG) const override;
|
||||
|
||||
SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
||||
SmallVectorImpl<SDValue> &InVals) const override;
|
||||
|
||||
const char *getTargetNodeName(unsigned Opcode) const override;
|
||||
|
||||
/// If a physical register, this returns the register that receives the
|
||||
/// exception address on entry to an EH pad.
|
||||
Register
|
||||
getExceptionPointerRegister(const Constant *PersonalityFn) const override;
|
||||
|
||||
/// If a physical register, this returns the register that receives the
|
||||
/// exception typeid on entry to a landing pad.
|
||||
Register
|
||||
getExceptionSelectorRegister(const Constant *PersonalityFn) const override;
|
||||
|
||||
bool isSelectSupported(SelectSupportKind Kind) const override {
|
||||
// CSKY does not support scalar condition selects on vectors.
|
||||
return (Kind != ScalarCondVectorVal);
|
||||
}
|
||||
|
||||
MachineBasicBlock *
|
||||
EmitInstrWithCustomInserter(MachineInstr &MI,
|
||||
MachineBasicBlock *BB) const override;
|
||||
|
||||
SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty,
|
||||
SelectionDAG &DAG, unsigned Flags) const;
|
||||
|
||||
SDValue getTargetNode(ExternalSymbolSDNode *N, SDLoc DL, EVT Ty,
|
||||
SelectionDAG &DAG, unsigned Flags) const;
|
||||
|
||||
SDValue getTargetNode(JumpTableSDNode *N, SDLoc DL, EVT Ty, SelectionDAG &DAG,
|
||||
unsigned Flags) const;
|
||||
|
||||
SDValue getTargetNode(BlockAddressSDNode *N, SDLoc DL, EVT Ty,
|
||||
SelectionDAG &DAG, unsigned Flags) const;
|
||||
|
||||
SDValue getTargetConstantPoolValue(GlobalAddressSDNode *N, EVT Ty,
|
||||
SelectionDAG &DAG, unsigned Flags) const;
|
||||
|
||||
SDValue getTargetConstantPoolValue(ExternalSymbolSDNode *N, EVT Ty,
|
||||
SelectionDAG &DAG, unsigned Flags) const;
|
||||
|
||||
SDValue getTargetConstantPoolValue(JumpTableSDNode *N, EVT Ty,
|
||||
SelectionDAG &DAG, unsigned Flags) const;
|
||||
|
||||
SDValue getTargetConstantPoolValue(BlockAddressSDNode *N, EVT Ty,
|
||||
SelectionDAG &DAG, unsigned Flags) const;
|
||||
|
||||
template <class NodeTy, bool IsCall = false>
|
||||
SDValue getAddr(NodeTy *N, SelectionDAG &DAG, bool IsLocal = true) const {
|
||||
SDLoc DL(N);
|
||||
EVT Ty = getPointerTy(DAG.getDataLayout());
|
||||
|
||||
unsigned Flag = CSKYII::MO_None;
|
||||
bool IsPIC = isPositionIndependent();
|
||||
|
||||
if (IsPIC)
|
||||
Flag = IsLocal ? CSKYII::MO_GOTOFF
|
||||
: IsCall ? CSKYII::MO_PLT32
|
||||
: CSKYII::MO_GOT32;
|
||||
|
||||
SDValue TCPV = getTargetConstantPoolValue(N, Ty, DAG, Flag);
|
||||
SDValue TV = getTargetNode(N, DL, Ty, DAG, Flag);
|
||||
SDValue Addr = DAG.getNode(CSKYISD::LOAD_ADDR, DL, Ty, {TV, TCPV});
|
||||
|
||||
if (!IsPIC)
|
||||
return Addr;
|
||||
|
||||
SDValue Result =
|
||||
DAG.getNode(ISD::ADD, DL, Ty, {DAG.getGLOBAL_OFFSET_TABLE(Ty), Addr});
|
||||
if (IsLocal)
|
||||
return Result;
|
||||
|
||||
return DAG.getLoad(Ty, DL, DAG.getEntryNode(), Result,
|
||||
MachinePointerInfo::getGOT(DAG.getMachineFunction()));
|
||||
}
|
||||
|
||||
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerExternalSymbol(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
|
||||
|
||||
CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const;
|
||||
CCAssignFn *CCAssignFnForReturn(CallingConv::ID CC, bool IsVarArg) const;
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CSKYInstrInfo.h"
|
||||
#include "CSKYConstantPoolValue.h"
|
||||
#include "CSKYMachineFunctionInfo.h"
|
||||
#include "CSKYTargetMachine.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
|
@ -500,3 +501,39 @@ void CSKYInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
|
|||
BuildMI(MBB, I, DL, get(Opcode), DestReg)
|
||||
.addReg(SrcReg, getKillRegState(KillSrc));
|
||||
}
|
||||
|
||||
Register CSKYInstrInfo::getGlobalBaseReg(MachineFunction &MF) const {
|
||||
CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>();
|
||||
MachineConstantPool *MCP = MF.getConstantPool();
|
||||
MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
|
||||
Register GlobalBaseReg = CFI->getGlobalBaseReg();
|
||||
if (GlobalBaseReg != 0)
|
||||
return GlobalBaseReg;
|
||||
|
||||
// Insert a pseudo instruction to set the GlobalBaseReg into the first
|
||||
// MBB of the function
|
||||
MachineBasicBlock &FirstMBB = MF.front();
|
||||
MachineBasicBlock::iterator MBBI = FirstMBB.begin();
|
||||
DebugLoc DL;
|
||||
|
||||
CSKYConstantPoolValue *CPV = CSKYConstantPoolSymbol::Create(
|
||||
Type::getInt32Ty(MF.getFunction().getContext()), "_GLOBAL_OFFSET_TABLE_",
|
||||
0, CSKYCP::ADDR);
|
||||
|
||||
unsigned CPI = MCP->getConstantPoolIndex(CPV, Align(4));
|
||||
|
||||
MachineMemOperand *MO =
|
||||
MF.getMachineMemOperand(MachinePointerInfo::getConstantPool(MF),
|
||||
MachineMemOperand::MOLoad, 4, Align(4));
|
||||
BuildMI(FirstMBB, MBBI, DL, get(CSKY::LRW32), CSKY::R28)
|
||||
.addConstantPoolIndex(CPI)
|
||||
.addMemOperand(MO);
|
||||
|
||||
GlobalBaseReg = MRI.createVirtualRegister(&CSKY::GPRRegClass);
|
||||
BuildMI(FirstMBB, MBBI, DL, get(TargetOpcode::COPY), GlobalBaseReg)
|
||||
.addReg(CSKY::R28);
|
||||
|
||||
CFI->setGlobalBaseReg(GlobalBaseReg);
|
||||
return GlobalBaseReg;
|
||||
}
|
||||
|
|
|
@ -68,6 +68,8 @@ public:
|
|||
|
||||
MachineBasicBlock *getBranchDestBlock(const MachineInstr &MI) const override;
|
||||
|
||||
Register getGlobalBaseReg(MachineFunction &MF) const;
|
||||
|
||||
// Materializes the given integer Val into DstReg.
|
||||
Register movImm(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
|
||||
const DebugLoc &DL, int64_t Val,
|
||||
|
|
|
@ -15,22 +15,42 @@
|
|||
// CSKY specific DAG Nodes.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Target-independent type requirements, but with target-specific formats.
|
||||
def SDT_CallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>,
|
||||
SDTCisVT<1, i32>]>;
|
||||
|
||||
def SDT_CallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>,
|
||||
SDTCisVT<1, i32>]>;
|
||||
|
||||
def SDT_CSKYCall : SDTypeProfile<0, 2, [SDTCisVT<0, iPTR>, SDTCisVT<1, iPTR>]>;
|
||||
|
||||
def SDT_CSKYCallReg : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>;
|
||||
|
||||
def SDT_CSKY_LOADADDR : SDTypeProfile<1, 2, [SDTCisVT<0, i32>,
|
||||
SDTCisVT<1, iPTR>, SDTCisVT<2, iPTR>]>;
|
||||
|
||||
def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_CallSeqStart,
|
||||
[SDNPHasChain, SDNPOutGlue]>;
|
||||
|
||||
def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_CallSeqEnd,
|
||||
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
|
||||
|
||||
// Target-dependent nodes.
|
||||
def CSKY_RET : SDNode<"CSKYISD::RET", SDTNone,
|
||||
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
|
||||
|
||||
def CSKY_CALL : SDNode<"CSKYISD::CALL", SDT_CSKYCall,
|
||||
[SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>;
|
||||
|
||||
def CSKY_CALLReg : SDNode<"CSKYISD::CALLReg", SDT_CSKYCallReg,
|
||||
[SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>;
|
||||
|
||||
def CSKY_TAIL : SDNode<"CSKYISD::TAIL", SDT_CSKYCall,
|
||||
[SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>;
|
||||
|
||||
def CSKY_TAILReg : SDNode<"CSKYISD::TAILReg", SDT_CSKYCallReg,
|
||||
[SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>;
|
||||
|
||||
def CSKY_LOAD_ADDR : SDNode<"CSKYISD::LOAD_ADDR", SDT_CSKY_LOADADDR>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Operand and SDNode transformation definitions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -57,6 +77,24 @@ def to_tframeindex : SDNodeXForm<frameindex, [{
|
|||
return CurDAG->getTargetFrameIndex(FI->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
|
||||
}]>;
|
||||
|
||||
def to_tconstpool : SDNodeXForm<constpool, [{
|
||||
auto CP = cast<ConstantPoolSDNode>(N);
|
||||
return CurDAG->getTargetConstantPool(CP->getConstVal(), TLI->getPointerTy(CurDAG->getDataLayout()),
|
||||
CP->getAlign(), CP->getOffset(), CSKYII::MO_None);
|
||||
}]>;
|
||||
|
||||
def to_tconstpool_hi16 : SDNodeXForm<constpool, [{
|
||||
auto CP = cast<ConstantPoolSDNode>(N);
|
||||
return CurDAG->getTargetConstantPool(CP->getConstVal(), TLI->getPointerTy(CurDAG->getDataLayout()),
|
||||
CP->getAlign(), CP->getOffset(), CSKYII::MO_ADDR_HI16);
|
||||
}]>;
|
||||
|
||||
def to_tconstpool_lo16 : SDNodeXForm<constpool, [{
|
||||
auto CP = cast<ConstantPoolSDNode>(N);
|
||||
return CurDAG->getTargetConstantPool(CP->getConstVal(), TLI->getPointerTy(CurDAG->getDataLayout()),
|
||||
CP->getAlign(), CP->getOffset(), CSKYII::MO_ADDR_LO16);
|
||||
}]>;
|
||||
|
||||
class oimm<int num> : Operand<i32>,
|
||||
ImmLeaf<i32, "return isUInt<"#num#">(Imm - 1);"> {
|
||||
let EncoderMethod = "getOImmOpValue";
|
||||
|
@ -1055,8 +1093,33 @@ let Predicates = [iHas2E3] in {
|
|||
def : Pat<(sext_inreg GPR:$src, i1), (SEXT32 GPR:$src, 0, 0)>;
|
||||
def : Pat<(and GPR:$src, 255), (ZEXT32 GPR:$src, 7, 0)>;
|
||||
def : Pat<(and GPR:$src, 65535), (ZEXT32 GPR:$src, 15, 0)>;
|
||||
|
||||
// Call Patterns
|
||||
def : Pat<(CSKY_CALL tglobaladdr, tconstpool:$src2), (JSRI32 tconstpool:$src2)>;
|
||||
def : Pat<(CSKY_CALL texternalsym, tconstpool:$src2), (JSRI32 tconstpool:$src2)>;
|
||||
def : Pat<(CSKY_TAIL tglobaladdr, tconstpool:$src2), (JMPI32 tconstpool:$src2)>;
|
||||
def : Pat<(CSKY_TAIL texternalsym, tconstpool:$src2), (JMPI32 tconstpool:$src2)>;
|
||||
|
||||
def : Pat<(CSKY_CALLReg GPR:$src), (JSR32 GPR:$src)>;
|
||||
def : Pat<(CSKY_TAILReg GPR:$src), (JMP32 GPR:$src)>;
|
||||
}
|
||||
|
||||
// Symbol address Patterns
|
||||
def : Pat<(CSKY_LOAD_ADDR tglobaladdr, tconstpool:$src2), (LRW32 tconstpool:$src2)>;
|
||||
def : Pat<(CSKY_LOAD_ADDR tblockaddress, tconstpool:$src2), (LRW32 tconstpool:$src2)>;
|
||||
def : Pat<(CSKY_LOAD_ADDR tjumptable:$src1, tconstpool:$src2), (LRW32_Gen tjumptable:$src1, tconstpool:$src2)>;
|
||||
def : Pat<(CSKY_LOAD_ADDR texternalsym, tconstpool:$src2), (LRW32 tconstpool:$src2)>;
|
||||
|
||||
let Predicates = [iHas2E3] in
|
||||
def : Pat<(i32 constpool:$src), (GRS32 (to_tconstpool tconstpool:$src))>;
|
||||
|
||||
let Predicates = [iHasE2] in
|
||||
def : Pat<(i32 constpool:$src),
|
||||
(ORI32 (MOVIH32 (to_tconstpool_hi16 tconstpool:$src)),
|
||||
(to_tconstpool_lo16 tconstpool:$src))>;
|
||||
|
||||
def : Pat<(i32 (load constpool:$src)), (LRW32 (to_tconstpool tconstpool:$src))>;
|
||||
|
||||
// Branch Patterns.
|
||||
let Predicates = [iHasE2] in {
|
||||
def : Pat<(brcond CARRY:$ca, bb:$imm16),
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
||||
; RUN: llc -verify-machineinstrs -csky-no-aliases < %s -mtriple=csky -mattr=+2e3 | FileCheck %s
|
||||
; RUN: llc -verify-machineinstrs -csky-no-aliases < %s -mtriple=csky -relocation-model=pic -code-model=small -mattr=+2e3 | FileCheck %s --check-prefix=CHECK-PIC-SMALL
|
||||
; RUN: llc -verify-machineinstrs -csky-no-aliases < %s -mtriple=csky -relocation-model=pic -code-model=large -mattr=+2e3 | FileCheck %s --check-prefix=CHECK-PIC-LARGE
|
||||
|
||||
@p_fun = global void (i32, i32)* @bar, align 8
|
||||
|
||||
declare void @bar(i32, i32)
|
||||
|
||||
define void @foo(i32 %a, i32* %ptr){
|
||||
; CHECK-LABEL: foo:
|
||||
; CHECK: # %bb.0: # %entry
|
||||
; CHECK-NEXT: subi16 sp, sp, 4
|
||||
; CHECK-NEXT: .cfi_def_cfa_offset 4
|
||||
; CHECK-NEXT: st32.w lr, (sp, 0) # 4-byte Folded Spill
|
||||
; CHECK-NEXT: .cfi_offset lr, -4
|
||||
; CHECK-NEXT: .cfi_def_cfa_offset 4
|
||||
; CHECK-NEXT: ld16.w a1, (a1, 0)
|
||||
; CHECK-NEXT: jsri32 [.LCPI0_0]
|
||||
; CHECK-NEXT: ld32.w lr, (sp, 0) # 4-byte Folded Reload
|
||||
; CHECK-NEXT: addi16 sp, sp, 4
|
||||
; CHECK-NEXT: rts16
|
||||
;
|
||||
; CHECK-PIC-SMALL-LABEL: foo:
|
||||
; CHECK-PIC-SMALL: # %bb.0: # %entry
|
||||
; CHECK-PIC-SMALL-NEXT: subi16 sp, sp, 8
|
||||
; CHECK-PIC-SMALL-NEXT: .cfi_def_cfa_offset 8
|
||||
; CHECK-PIC-SMALL-NEXT: st32.w rgb, (sp, 4) # 4-byte Folded Spill
|
||||
; CHECK-PIC-SMALL-NEXT: st32.w lr, (sp, 0) # 4-byte Folded Spill
|
||||
; CHECK-PIC-SMALL-NEXT: .cfi_offset rgb, -4
|
||||
; CHECK-PIC-SMALL-NEXT: .cfi_offset lr, -8
|
||||
; CHECK-PIC-SMALL-NEXT: .cfi_def_cfa_offset 8
|
||||
; CHECK-PIC-SMALL-NEXT: lrw32 rgb, [.LCPI0_0]
|
||||
; CHECK-PIC-SMALL-NEXT: ld16.w a1, (a1, 0)
|
||||
; CHECK-PIC-SMALL-NEXT: lrw32 a2, [.LCPI0_1]
|
||||
; CHECK-PIC-SMALL-NEXT: ldr32.w a2, (rgb, a2 << 0)
|
||||
; CHECK-PIC-SMALL-NEXT: jsr16 a2
|
||||
; CHECK-PIC-SMALL-NEXT: ld32.w lr, (sp, 0) # 4-byte Folded Reload
|
||||
; CHECK-PIC-SMALL-NEXT: ld32.w rgb, (sp, 4) # 4-byte Folded Reload
|
||||
; CHECK-PIC-SMALL-NEXT: addi16 sp, sp, 8
|
||||
; CHECK-PIC-SMALL-NEXT: rts16
|
||||
;
|
||||
; CHECK-PIC-LARGE-LABEL: foo:
|
||||
; CHECK-PIC-LARGE: # %bb.0: # %entry
|
||||
; CHECK-PIC-LARGE-NEXT: subi16 sp, sp, 8
|
||||
; CHECK-PIC-LARGE-NEXT: .cfi_def_cfa_offset 8
|
||||
; CHECK-PIC-LARGE-NEXT: st32.w rgb, (sp, 4) # 4-byte Folded Spill
|
||||
; CHECK-PIC-LARGE-NEXT: st32.w lr, (sp, 0) # 4-byte Folded Spill
|
||||
; CHECK-PIC-LARGE-NEXT: .cfi_offset rgb, -4
|
||||
; CHECK-PIC-LARGE-NEXT: .cfi_offset lr, -8
|
||||
; CHECK-PIC-LARGE-NEXT: .cfi_def_cfa_offset 8
|
||||
; CHECK-PIC-LARGE-NEXT: lrw32 rgb, [.LCPI0_0]
|
||||
; CHECK-PIC-LARGE-NEXT: ld16.w a1, (a1, 0)
|
||||
; CHECK-PIC-LARGE-NEXT: lrw32 a2, [.LCPI0_1]
|
||||
; CHECK-PIC-LARGE-NEXT: ldr32.w a2, (rgb, a2 << 0)
|
||||
; CHECK-PIC-LARGE-NEXT: jsr16 a2
|
||||
; CHECK-PIC-LARGE-NEXT: ld32.w lr, (sp, 0) # 4-byte Folded Reload
|
||||
; CHECK-PIC-LARGE-NEXT: ld32.w rgb, (sp, 4) # 4-byte Folded Reload
|
||||
; CHECK-PIC-LARGE-NEXT: addi16 sp, sp, 8
|
||||
; CHECK-PIC-LARGE-NEXT: rts16
|
||||
; CHECK-PIC-LABEL: foo:
|
||||
; CHECK-PIC: # %bb.0: # %entry
|
||||
; CHECK-PIC-NEXT: ld32.w a1, a1, 0
|
||||
; CHECK-PIC-NEXT: br32 bar
|
||||
entry:
|
||||
%0 = load i32, i32* %ptr
|
||||
tail call void (i32, i32) @bar(i32 %a, i32 %0)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @foo_indirect(i32 %a, i32* %ptr) {
|
||||
; CHECK-LABEL: foo_indirect:
|
||||
; CHECK: # %bb.0: # %entry
|
||||
; CHECK-NEXT: subi16 sp, sp, 4
|
||||
; CHECK-NEXT: .cfi_def_cfa_offset 4
|
||||
; CHECK-NEXT: st32.w lr, (sp, 0) # 4-byte Folded Spill
|
||||
; CHECK-NEXT: .cfi_offset lr, -4
|
||||
; CHECK-NEXT: .cfi_def_cfa_offset 4
|
||||
; CHECK-NEXT: lrw32 a2, [.LCPI1_0]
|
||||
; CHECK-NEXT: ld16.w a2, (a2, 0)
|
||||
; CHECK-NEXT: ld16.w a1, (a1, 0)
|
||||
; CHECK-NEXT: jsr16 a2
|
||||
; CHECK-NEXT: ld32.w lr, (sp, 0) # 4-byte Folded Reload
|
||||
; CHECK-NEXT: addi16 sp, sp, 4
|
||||
; CHECK-NEXT: rts16
|
||||
;
|
||||
; CHECK-PIC-SMALL-LABEL: foo_indirect:
|
||||
; CHECK-PIC-SMALL: # %bb.0: # %entry
|
||||
; CHECK-PIC-SMALL-NEXT: subi16 sp, sp, 8
|
||||
; CHECK-PIC-SMALL-NEXT: .cfi_def_cfa_offset 8
|
||||
; CHECK-PIC-SMALL-NEXT: st32.w rgb, (sp, 4) # 4-byte Folded Spill
|
||||
; CHECK-PIC-SMALL-NEXT: st32.w lr, (sp, 0) # 4-byte Folded Spill
|
||||
; CHECK-PIC-SMALL-NEXT: .cfi_offset rgb, -4
|
||||
; CHECK-PIC-SMALL-NEXT: .cfi_offset lr, -8
|
||||
; CHECK-PIC-SMALL-NEXT: .cfi_def_cfa_offset 8
|
||||
; CHECK-PIC-SMALL-NEXT: lrw32 rgb, [.LCPI1_0]
|
||||
; CHECK-PIC-SMALL-NEXT: lrw32 a2, [.LCPI1_1]
|
||||
; CHECK-PIC-SMALL-NEXT: ldr32.w a2, (rgb, a2 << 0)
|
||||
; CHECK-PIC-SMALL-NEXT: ld16.w a2, (a2, 0)
|
||||
; CHECK-PIC-SMALL-NEXT: ld16.w a1, (a1, 0)
|
||||
; CHECK-PIC-SMALL-NEXT: jsr16 a2
|
||||
; CHECK-PIC-SMALL-NEXT: ld32.w lr, (sp, 0) # 4-byte Folded Reload
|
||||
; CHECK-PIC-SMALL-NEXT: ld32.w rgb, (sp, 4) # 4-byte Folded Reload
|
||||
; CHECK-PIC-SMALL-NEXT: addi16 sp, sp, 8
|
||||
; CHECK-PIC-SMALL-NEXT: rts16
|
||||
;
|
||||
; CHECK-PIC-LARGE-LABEL: foo_indirect:
|
||||
; CHECK-PIC-LARGE: # %bb.0: # %entry
|
||||
; CHECK-PIC-LARGE-NEXT: subi16 sp, sp, 8
|
||||
; CHECK-PIC-LARGE-NEXT: .cfi_def_cfa_offset 8
|
||||
; CHECK-PIC-LARGE-NEXT: st32.w rgb, (sp, 4) # 4-byte Folded Spill
|
||||
; CHECK-PIC-LARGE-NEXT: st32.w lr, (sp, 0) # 4-byte Folded Spill
|
||||
; CHECK-PIC-LARGE-NEXT: .cfi_offset rgb, -4
|
||||
; CHECK-PIC-LARGE-NEXT: .cfi_offset lr, -8
|
||||
; CHECK-PIC-LARGE-NEXT: .cfi_def_cfa_offset 8
|
||||
; CHECK-PIC-LARGE-NEXT: lrw32 rgb, [.LCPI1_0]
|
||||
; CHECK-PIC-LARGE-NEXT: lrw32 a2, [.LCPI1_1]
|
||||
; CHECK-PIC-LARGE-NEXT: ldr32.w a2, (rgb, a2 << 0)
|
||||
; CHECK-PIC-LARGE-NEXT: ld16.w a2, (a2, 0)
|
||||
; CHECK-PIC-LARGE-NEXT: ld16.w a1, (a1, 0)
|
||||
; CHECK-PIC-LARGE-NEXT: jsr16 a2
|
||||
; CHECK-PIC-LARGE-NEXT: ld32.w lr, (sp, 0) # 4-byte Folded Reload
|
||||
; CHECK-PIC-LARGE-NEXT: ld32.w rgb, (sp, 4) # 4-byte Folded Reload
|
||||
; CHECK-PIC-LARGE-NEXT: addi16 sp, sp, 8
|
||||
; CHECK-PIC-LARGE-NEXT: rts16
|
||||
; CHECK-PIC-LABEL: foo_indirect:
|
||||
; CHECK-PIC: # %bb.0: # %entry
|
||||
; CHECK-PIC-NEXT: movi32 a2, p_fun
|
||||
; CHECK-PIC-NEXT: movih32 a3, p_fun
|
||||
; CHECK-PIC-NEXT: or32 a2, a3, a2
|
||||
; CHECK-PIC-NEXT: ld32.w a2, a2, 0
|
||||
; CHECK-PIC-NEXT: ld32.w a1, a1, 0
|
||||
; CHECK-PIC-NEXT: jmp32 a2
|
||||
entry:
|
||||
%0 = load void (i32, i32)*, void (i32, i32)** @p_fun, align 8
|
||||
%1 = load i32, i32* %ptr
|
||||
tail call void (i32, i32) %0(i32 %a, i32 %1)
|
||||
ret void
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
||||
; RUN: llc -mtriple=csky -verify-machineinstrs -csky-no-aliases -mattr=+2e3 < %s \
|
||||
; RUN: | FileCheck %s
|
||||
|
||||
declare void @notdead(i8*)
|
||||
declare i8* @llvm.frameaddress(i32)
|
||||
declare i8* @llvm.returnaddress(i32)
|
||||
|
||||
define i8* @test_frameaddress_0() nounwind {
|
||||
; CHECK-LABEL: test_frameaddress_0:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: subi16 sp, sp, 4
|
||||
; CHECK-NEXT: st32.w l4, (sp, 0) # 4-byte Folded Spill
|
||||
; CHECK-NEXT: mov16 l4, sp
|
||||
; CHECK-NEXT: mov16 a0, l4
|
||||
; CHECK-NEXT: mov16 sp, l4
|
||||
; CHECK-NEXT: ld32.w l4, (sp, 0) # 4-byte Folded Reload
|
||||
; CHECK-NEXT: addi16 sp, sp, 4
|
||||
; CHECK-NEXT: rts16
|
||||
%1 = call i8* @llvm.frameaddress(i32 0)
|
||||
ret i8* %1
|
||||
}
|
||||
|
||||
define i8* @test_frameaddress_2() nounwind {
|
||||
; CHECK-LABEL: test_frameaddress_2:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: subi16 sp, sp, 4
|
||||
; CHECK-NEXT: st32.w l4, (sp, 0) # 4-byte Folded Spill
|
||||
; CHECK-NEXT: mov16 l4, sp
|
||||
; CHECK-NEXT: ld32.w a0, (l4, 0)
|
||||
; CHECK-NEXT: ld16.w a0, (a0, 0)
|
||||
; CHECK-NEXT: mov16 sp, l4
|
||||
; CHECK-NEXT: ld32.w l4, (sp, 0) # 4-byte Folded Reload
|
||||
; CHECK-NEXT: addi16 sp, sp, 4
|
||||
; CHECK-NEXT: rts16
|
||||
%1 = call i8* @llvm.frameaddress(i32 2)
|
||||
ret i8* %1
|
||||
}
|
||||
|
||||
define i8* @test_frameaddress_3_alloca() nounwind {
|
||||
; CHECK-LABEL: test_frameaddress_3_alloca:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: subi16 sp, sp, 8
|
||||
; CHECK-NEXT: st32.w lr, (sp, 4) # 4-byte Folded Spill
|
||||
; CHECK-NEXT: st32.w l4, (sp, 0) # 4-byte Folded Spill
|
||||
; CHECK-NEXT: mov16 l4, sp
|
||||
; CHECK-NEXT: subi16 sp, sp, 100
|
||||
; CHECK-NEXT: movi16 a0, 0
|
||||
; CHECK-NEXT: addu16 a0, sp
|
||||
; CHECK-NEXT: jsri32 [.LCPI2_0]
|
||||
; CHECK-NEXT: ld32.w a0, (l4, 0)
|
||||
; CHECK-NEXT: ld16.w a0, (a0, 0)
|
||||
; CHECK-NEXT: ld16.w a0, (a0, 0)
|
||||
; CHECK-NEXT: mov16 sp, l4
|
||||
; CHECK-NEXT: ld32.w l4, (sp, 0) # 4-byte Folded Reload
|
||||
; CHECK-NEXT: ld32.w lr, (sp, 4) # 4-byte Folded Reload
|
||||
; CHECK-NEXT: addi16 sp, sp, 8
|
||||
; CHECK-NEXT: rts16
|
||||
%1 = alloca [100 x i8]
|
||||
%2 = bitcast [100 x i8]* %1 to i8*
|
||||
call void @notdead(i8* %2)
|
||||
%3 = call i8* @llvm.frameaddress(i32 3)
|
||||
ret i8* %3
|
||||
}
|
||||
|
||||
define i8* @test_returnaddress_0() nounwind {
|
||||
; CHECK-LABEL: test_returnaddress_0:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: mov16 a0, lr
|
||||
; CHECK-NEXT: rts16
|
||||
%1 = call i8* @llvm.returnaddress(i32 0)
|
||||
ret i8* %1
|
||||
}
|
||||
|
||||
define i8* @test_returnaddress_2() nounwind {
|
||||
; CHECK-LABEL: test_returnaddress_2:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: subi16 sp, sp, 4
|
||||
; CHECK-NEXT: st32.w l4, (sp, 0) # 4-byte Folded Spill
|
||||
; CHECK-NEXT: mov16 l4, sp
|
||||
; CHECK-NEXT: ld32.w a0, (l4, 0)
|
||||
; CHECK-NEXT: ld16.w a0, (a0, 0)
|
||||
; CHECK-NEXT: ld16.w a0, (a0, 4)
|
||||
; CHECK-NEXT: mov16 sp, l4
|
||||
; CHECK-NEXT: ld32.w l4, (sp, 0) # 4-byte Folded Reload
|
||||
; CHECK-NEXT: addi16 sp, sp, 4
|
||||
; CHECK-NEXT: rts16
|
||||
%1 = call i8* @llvm.returnaddress(i32 2)
|
||||
ret i8* %1
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
||||
; RUN: llc -verify-machineinstrs -csky-no-aliases < %s -mtriple=csky -mattr=+2e3 | FileCheck %s
|
||||
; RUN: llc -verify-machineinstrs -csky-no-aliases < %s -mtriple=csky -relocation-model=pic -code-model=small -mattr=+2e3 | FileCheck %s --check-prefix=CHECK-PIC-SMALL
|
||||
; RUN: llc -verify-machineinstrs -csky-no-aliases < %s -mtriple=csky -relocation-model=pic -code-model=large -mattr=+2e3 | FileCheck %s --check-prefix=CHECK-PIC-LARGE
|
||||
|
||||
@f.a = private unnamed_addr constant [2 x i8*] [i8* blockaddress(@f, %return), i8* blockaddress(@f, %l2)], align 16
|
||||
|
||||
define i32 @f(i32 %x) #0 {
|
||||
; CHECK-LABEL: f:
|
||||
; CHECK: # %bb.0: # %entry
|
||||
; CHECK-NEXT: lrw32 a1, [.LCPI0_0]
|
||||
; CHECK-NEXT: ldr32.w a0, (a1, a0 << 2)
|
||||
; CHECK-NEXT: jmp32 a0
|
||||
; CHECK-NEXT: .Ltmp0: # Block address taken
|
||||
; CHECK-NEXT: .LBB0_2: # %return
|
||||
; CHECK-NEXT: movi16 a0, 1
|
||||
; CHECK-NEXT: rts16
|
||||
; CHECK-NEXT: .Ltmp1: # Block address taken
|
||||
; CHECK-NEXT: .LBB0_1: # %l2
|
||||
; CHECK-NEXT: movi16 a0, 2
|
||||
; CHECK-NEXT: rts16
|
||||
;
|
||||
; CHECK-PIC-SMALL-LABEL: f:
|
||||
; CHECK-PIC-SMALL: # %bb.0: # %entry
|
||||
; CHECK-PIC-SMALL-NEXT: subi16 sp, sp, 4
|
||||
; CHECK-PIC-SMALL-NEXT: .cfi_def_cfa_offset 4
|
||||
; CHECK-PIC-SMALL-NEXT: st32.w rgb, (sp, 0) # 4-byte Folded Spill
|
||||
; CHECK-PIC-SMALL-NEXT: .cfi_offset rgb, -4
|
||||
; CHECK-PIC-SMALL-NEXT: .cfi_def_cfa_offset 4
|
||||
; CHECK-PIC-SMALL-NEXT: lrw32 rgb, [.LCPI0_0]
|
||||
; CHECK-PIC-SMALL-NEXT: lrw32 a1, [.LCPI0_1]
|
||||
; CHECK-PIC-SMALL-NEXT: addu32 a1, rgb, a1
|
||||
; CHECK-PIC-SMALL-NEXT: ldr32.w a0, (a1, a0 << 2)
|
||||
; CHECK-PIC-SMALL-NEXT: jmp32 a0
|
||||
; CHECK-PIC-SMALL-NEXT: .Ltmp0: # Block address taken
|
||||
; CHECK-PIC-SMALL-NEXT: .LBB0_2: # %return
|
||||
; CHECK-PIC-SMALL-NEXT: movi16 a0, 1
|
||||
; CHECK-PIC-SMALL-NEXT: br32 .LBB0_3
|
||||
; CHECK-PIC-SMALL-NEXT: .Ltmp1: # Block address taken
|
||||
; CHECK-PIC-SMALL-NEXT: .LBB0_1: # %l2
|
||||
; CHECK-PIC-SMALL-NEXT: movi16 a0, 2
|
||||
; CHECK-PIC-SMALL-NEXT: .LBB0_3: # %.split
|
||||
; CHECK-PIC-SMALL-NEXT: ld32.w rgb, (sp, 0) # 4-byte Folded Reload
|
||||
; CHECK-PIC-SMALL-NEXT: addi16 sp, sp, 4
|
||||
; CHECK-PIC-SMALL-NEXT: rts16
|
||||
;
|
||||
; CHECK-PIC-LARGE-LABEL: f:
|
||||
; CHECK-PIC-LARGE: # %bb.0: # %entry
|
||||
; CHECK-PIC-LARGE-NEXT: subi16 sp, sp, 4
|
||||
; CHECK-PIC-LARGE-NEXT: .cfi_def_cfa_offset 4
|
||||
; CHECK-PIC-LARGE-NEXT: st32.w rgb, (sp, 0) # 4-byte Folded Spill
|
||||
; CHECK-PIC-LARGE-NEXT: .cfi_offset rgb, -4
|
||||
; CHECK-PIC-LARGE-NEXT: .cfi_def_cfa_offset 4
|
||||
; CHECK-PIC-LARGE-NEXT: lrw32 rgb, [.LCPI0_0]
|
||||
; CHECK-PIC-LARGE-NEXT: lrw32 a1, [.LCPI0_1]
|
||||
; CHECK-PIC-LARGE-NEXT: addu32 a1, rgb, a1
|
||||
; CHECK-PIC-LARGE-NEXT: ldr32.w a0, (a1, a0 << 2)
|
||||
; CHECK-PIC-LARGE-NEXT: jmp32 a0
|
||||
; CHECK-PIC-LARGE-NEXT: .Ltmp0: # Block address taken
|
||||
; CHECK-PIC-LARGE-NEXT: .LBB0_2: # %return
|
||||
; CHECK-PIC-LARGE-NEXT: movi16 a0, 1
|
||||
; CHECK-PIC-LARGE-NEXT: br32 .LBB0_3
|
||||
; CHECK-PIC-LARGE-NEXT: .Ltmp1: # Block address taken
|
||||
; CHECK-PIC-LARGE-NEXT: .LBB0_1: # %l2
|
||||
; CHECK-PIC-LARGE-NEXT: movi16 a0, 2
|
||||
; CHECK-PIC-LARGE-NEXT: .LBB0_3: # %.split
|
||||
; CHECK-PIC-LARGE-NEXT: ld32.w rgb, (sp, 0) # 4-byte Folded Reload
|
||||
; CHECK-PIC-LARGE-NEXT: addi16 sp, sp, 4
|
||||
; CHECK-PIC-LARGE-NEXT: rts16
|
||||
entry:
|
||||
%idxprom = sext i32 %x to i64
|
||||
%arrayidx = getelementptr inbounds [2 x i8*], [2 x i8*]* @f.a, i64 0, i64 %idxprom
|
||||
%0 = load i8*, i8** %arrayidx, align 8
|
||||
indirectbr i8* %0, [label %return, label %l2]
|
||||
|
||||
l2: ; preds = %entry
|
||||
br label %return
|
||||
|
||||
return: ; preds = %entry, %l2
|
||||
%retval.0 = phi i32 [ 2, %l2 ], [ 1, %entry ]
|
||||
ret i32 %retval.0
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
||||
; RUN: llc -verify-machineinstrs -csky-no-aliases < %s -mtriple=csky -mattr=+2e3 | FileCheck %s
|
||||
; RUN: llc -verify-machineinstrs -csky-no-aliases < %s -mtriple=csky -relocation-model=pic -code-model=small -mattr=+2e3 | FileCheck %s --check-prefix=CHECK-PIC-SMALL
|
||||
; RUN: llc -verify-machineinstrs -csky-no-aliases < %s -mtriple=csky -relocation-model=pic -code-model=large -mattr=+2e3 | FileCheck %s --check-prefix=CHECK-PIC-LARGE
|
||||
|
||||
define i32 @f(i32 %val) {
|
||||
; CHECK-LABEL: f:
|
||||
; CHECK: # %bb.0: # %entry
|
||||
; CHECK-NEXT: movi16 a1, 4
|
||||
; CHECK-NEXT: cmphs16 a1, a0
|
||||
; CHECK-NEXT: bf32 .LBB0_7
|
||||
; CHECK-NEXT: # %bb.1: # %entry
|
||||
; CHECK-NEXT: lrw32 a1, [.LCPI0_0]
|
||||
; CHECK-NEXT: ldr32.w a0, (a1, a0 << 2)
|
||||
; CHECK-NEXT: jmp32 a0
|
||||
; CHECK-NEXT: .LBB0_4: # %onzero
|
||||
; CHECK-NEXT: movi16 a0, 0
|
||||
; CHECK-NEXT: rts16
|
||||
; CHECK-NEXT: .LBB0_7: # %otherwise
|
||||
; CHECK-NEXT: movih32 a0, 65535
|
||||
; CHECK-NEXT: ori32 a0, a0, 65535
|
||||
; CHECK-NEXT: rts16
|
||||
; CHECK-NEXT: .LBB0_2: # %onone
|
||||
; CHECK-NEXT: movi16 a0, 1
|
||||
; CHECK-NEXT: rts16
|
||||
; CHECK-NEXT: .LBB0_3: # %ontwo
|
||||
; CHECK-NEXT: movi16 a0, 2
|
||||
; CHECK-NEXT: rts16
|
||||
; CHECK-NEXT: .LBB0_5: # %onfour
|
||||
; CHECK-NEXT: movi16 a0, 4
|
||||
; CHECK-NEXT: rts16
|
||||
; CHECK-NEXT: .LBB0_6: # %onthree
|
||||
; CHECK-NEXT: movi16 a0, 3
|
||||
; CHECK-NEXT: rts16
|
||||
;
|
||||
; CHECK-PIC-SMALL-LABEL: f:
|
||||
; CHECK-PIC-SMALL: # %bb.0: # %entry
|
||||
; CHECK-PIC-SMALL-NEXT: subi16 sp, sp, 4
|
||||
; CHECK-PIC-SMALL-NEXT: .cfi_def_cfa_offset 4
|
||||
; CHECK-PIC-SMALL-NEXT: st32.w rgb, (sp, 0) # 4-byte Folded Spill
|
||||
; CHECK-PIC-SMALL-NEXT: .cfi_offset rgb, -4
|
||||
; CHECK-PIC-SMALL-NEXT: .cfi_def_cfa_offset 4
|
||||
; CHECK-PIC-SMALL-NEXT: lrw32 rgb, [.LCPI0_0]
|
||||
; CHECK-PIC-SMALL-NEXT: movi16 a1, 4
|
||||
; CHECK-PIC-SMALL-NEXT: cmphs16 a1, a0
|
||||
; CHECK-PIC-SMALL-NEXT: bf32 .LBB0_8
|
||||
; CHECK-PIC-SMALL-NEXT: # %bb.1: # %entry
|
||||
; CHECK-PIC-SMALL-NEXT: lrw32 a1, [.LCPI0_1]
|
||||
; CHECK-PIC-SMALL-NEXT: addu32 a1, rgb, a1
|
||||
; CHECK-PIC-SMALL-NEXT: ldr32.w a0, (a1, a0 << 2)
|
||||
; CHECK-PIC-SMALL-NEXT: addu16 a0, a1
|
||||
; CHECK-PIC-SMALL-NEXT: jmp32 a0
|
||||
; CHECK-PIC-SMALL-NEXT: .LBB0_5: # %onzero
|
||||
; CHECK-PIC-SMALL-NEXT: movi16 a0, 0
|
||||
; CHECK-PIC-SMALL-NEXT: br32 .LBB0_3
|
||||
; CHECK-PIC-SMALL-NEXT: .LBB0_8: # %otherwise
|
||||
; CHECK-PIC-SMALL-NEXT: movih32 a0, 65535
|
||||
; CHECK-PIC-SMALL-NEXT: ori32 a0, a0, 65535
|
||||
; CHECK-PIC-SMALL-NEXT: br32 .LBB0_3
|
||||
; CHECK-PIC-SMALL-NEXT: .LBB0_2: # %onone
|
||||
; CHECK-PIC-SMALL-NEXT: movi16 a0, 1
|
||||
; CHECK-PIC-SMALL-NEXT: br32 .LBB0_3
|
||||
; CHECK-PIC-SMALL-NEXT: .LBB0_4: # %ontwo
|
||||
; CHECK-PIC-SMALL-NEXT: movi16 a0, 2
|
||||
; CHECK-PIC-SMALL-NEXT: br32 .LBB0_3
|
||||
; CHECK-PIC-SMALL-NEXT: .LBB0_6: # %onfour
|
||||
; CHECK-PIC-SMALL-NEXT: movi16 a0, 4
|
||||
; CHECK-PIC-SMALL-NEXT: br32 .LBB0_3
|
||||
; CHECK-PIC-SMALL-NEXT: .LBB0_7: # %onthree
|
||||
; CHECK-PIC-SMALL-NEXT: movi16 a0, 3
|
||||
; CHECK-PIC-SMALL-NEXT: .LBB0_3: # %onone
|
||||
; CHECK-PIC-SMALL-NEXT: ld32.w rgb, (sp, 0) # 4-byte Folded Reload
|
||||
; CHECK-PIC-SMALL-NEXT: addi16 sp, sp, 4
|
||||
; CHECK-PIC-SMALL-NEXT: rts16
|
||||
;
|
||||
; CHECK-PIC-LARGE-LABEL: f:
|
||||
; CHECK-PIC-LARGE: # %bb.0: # %entry
|
||||
; CHECK-PIC-LARGE-NEXT: subi16 sp, sp, 4
|
||||
; CHECK-PIC-LARGE-NEXT: .cfi_def_cfa_offset 4
|
||||
; CHECK-PIC-LARGE-NEXT: st32.w rgb, (sp, 0) # 4-byte Folded Spill
|
||||
; CHECK-PIC-LARGE-NEXT: .cfi_offset rgb, -4
|
||||
; CHECK-PIC-LARGE-NEXT: .cfi_def_cfa_offset 4
|
||||
; CHECK-PIC-LARGE-NEXT: lrw32 rgb, [.LCPI0_0]
|
||||
; CHECK-PIC-LARGE-NEXT: movi16 a1, 4
|
||||
; CHECK-PIC-LARGE-NEXT: cmphs16 a1, a0
|
||||
; CHECK-PIC-LARGE-NEXT: bf32 .LBB0_8
|
||||
; CHECK-PIC-LARGE-NEXT: # %bb.1: # %entry
|
||||
; CHECK-PIC-LARGE-NEXT: lrw32 a1, [.LCPI0_1]
|
||||
; CHECK-PIC-LARGE-NEXT: addu32 a1, rgb, a1
|
||||
; CHECK-PIC-LARGE-NEXT: ldr32.w a0, (a1, a0 << 2)
|
||||
; CHECK-PIC-LARGE-NEXT: addu16 a0, a1
|
||||
; CHECK-PIC-LARGE-NEXT: jmp32 a0
|
||||
; CHECK-PIC-LARGE-NEXT: .LBB0_5: # %onzero
|
||||
; CHECK-PIC-LARGE-NEXT: movi16 a0, 0
|
||||
; CHECK-PIC-LARGE-NEXT: br32 .LBB0_3
|
||||
; CHECK-PIC-LARGE-NEXT: .LBB0_8: # %otherwise
|
||||
; CHECK-PIC-LARGE-NEXT: movih32 a0, 65535
|
||||
; CHECK-PIC-LARGE-NEXT: ori32 a0, a0, 65535
|
||||
; CHECK-PIC-LARGE-NEXT: br32 .LBB0_3
|
||||
; CHECK-PIC-LARGE-NEXT: .LBB0_2: # %onone
|
||||
; CHECK-PIC-LARGE-NEXT: movi16 a0, 1
|
||||
; CHECK-PIC-LARGE-NEXT: br32 .LBB0_3
|
||||
; CHECK-PIC-LARGE-NEXT: .LBB0_4: # %ontwo
|
||||
; CHECK-PIC-LARGE-NEXT: movi16 a0, 2
|
||||
; CHECK-PIC-LARGE-NEXT: br32 .LBB0_3
|
||||
; CHECK-PIC-LARGE-NEXT: .LBB0_6: # %onfour
|
||||
; CHECK-PIC-LARGE-NEXT: movi16 a0, 4
|
||||
; CHECK-PIC-LARGE-NEXT: br32 .LBB0_3
|
||||
; CHECK-PIC-LARGE-NEXT: .LBB0_7: # %onthree
|
||||
; CHECK-PIC-LARGE-NEXT: movi16 a0, 3
|
||||
; CHECK-PIC-LARGE-NEXT: .LBB0_3: # %onone
|
||||
; CHECK-PIC-LARGE-NEXT: ld32.w rgb, (sp, 0) # 4-byte Folded Reload
|
||||
; CHECK-PIC-LARGE-NEXT: addi16 sp, sp, 4
|
||||
; CHECK-PIC-LARGE-NEXT: rts16
|
||||
entry:
|
||||
switch i32 %val, label %otherwise [ i32 0, label %onzero
|
||||
i32 1, label %onone
|
||||
i32 3, label %onfour
|
||||
i32 4, label %onthree
|
||||
i32 2, label %ontwo ]
|
||||
onone:
|
||||
ret i32 1
|
||||
ontwo:
|
||||
ret i32 2
|
||||
onzero:
|
||||
ret i32 0
|
||||
onfour:
|
||||
ret i32 4
|
||||
onthree:
|
||||
ret i32 3
|
||||
otherwise:
|
||||
ret i32 -1
|
||||
}
|
Loading…
Reference in New Issue