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.
181 lines
5.8 KiB
C++
181 lines
5.8 KiB
C++
//===-- CSKYISelDAGToDAG.cpp - A dag to dag inst selector for CSKY---------===//
|
|
//
|
|
// 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 defines an instruction selector for the CSKY target.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "CSKY.h"
|
|
#include "CSKYSubtarget.h"
|
|
#include "CSKYTargetMachine.h"
|
|
#include "MCTargetDesc/CSKYMCTargetDesc.h"
|
|
#include "llvm/CodeGen/SelectionDAG.h"
|
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
|
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "csky-isel"
|
|
|
|
namespace {
|
|
class CSKYDAGToDAGISel : public SelectionDAGISel {
|
|
const CSKYSubtarget *Subtarget;
|
|
|
|
public:
|
|
explicit CSKYDAGToDAGISel(CSKYTargetMachine &TM) : SelectionDAGISel(TM) {}
|
|
|
|
StringRef getPassName() const override {
|
|
return "CSKY DAG->DAG Pattern Instruction Selection";
|
|
}
|
|
|
|
bool runOnMachineFunction(MachineFunction &MF) override {
|
|
// Reset the subtarget each time through.
|
|
Subtarget = &MF.getSubtarget<CSKYSubtarget>();
|
|
SelectionDAGISel::runOnMachineFunction(MF);
|
|
return true;
|
|
}
|
|
|
|
void Select(SDNode *N) override;
|
|
bool selectAddCarry(SDNode *N);
|
|
bool selectSubCarry(SDNode *N);
|
|
|
|
#include "CSKYGenDAGISel.inc"
|
|
};
|
|
} // namespace
|
|
|
|
void CSKYDAGToDAGISel::Select(SDNode *N) {
|
|
// If we have a custom node, we have already selected
|
|
if (N->isMachineOpcode()) {
|
|
LLVM_DEBUG(dbgs() << "== "; N->dump(CurDAG); dbgs() << "\n");
|
|
N->setNodeId(-1);
|
|
return;
|
|
}
|
|
|
|
SDLoc Dl(N);
|
|
unsigned Opcode = N->getOpcode();
|
|
bool IsSelected = false;
|
|
|
|
switch (Opcode) {
|
|
default:
|
|
break;
|
|
case ISD::ADDCARRY:
|
|
IsSelected = selectAddCarry(N);
|
|
break;
|
|
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();
|
|
SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32);
|
|
ReplaceNode(N, CurDAG->getMachineNode(Subtarget->hasE2() ? CSKY::ADDI32
|
|
: CSKY::ADDI16XZ,
|
|
Dl, MVT::i32, TFI, Imm));
|
|
|
|
IsSelected = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (IsSelected)
|
|
return;
|
|
|
|
// Select the default instruction.
|
|
SelectCode(N);
|
|
}
|
|
|
|
bool CSKYDAGToDAGISel::selectAddCarry(SDNode *N) {
|
|
MachineSDNode *NewNode = nullptr;
|
|
auto Type0 = N->getValueType(0);
|
|
auto Type1 = N->getValueType(1);
|
|
auto Op0 = N->getOperand(0);
|
|
auto Op1 = N->getOperand(1);
|
|
auto Op2 = N->getOperand(2);
|
|
|
|
SDLoc Dl(N);
|
|
|
|
if (isNullConstant(Op2)) {
|
|
auto *CA = CurDAG->getMachineNode(
|
|
Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
|
|
NewNode = CurDAG->getMachineNode(
|
|
Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
|
|
{Op0, Op1, SDValue(CA, 0)});
|
|
} else if (isOneConstant(Op2)) {
|
|
auto *CA = CurDAG->getMachineNode(
|
|
Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
|
|
NewNode = CurDAG->getMachineNode(
|
|
Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
|
|
{Op0, Op1, SDValue(CA, 0)});
|
|
} else {
|
|
NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32
|
|
: CSKY::ADDC16,
|
|
Dl, {Type0, Type1}, {Op0, Op1, Op2});
|
|
}
|
|
ReplaceNode(N, NewNode);
|
|
return true;
|
|
}
|
|
|
|
static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget,
|
|
SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry) {
|
|
auto NewCarryReg =
|
|
DAG->getMachineNode(Subtarget->has2E3() ? CSKY::MVCV32 : CSKY::MVCV16, Dl,
|
|
MVT::i32, OldCarry);
|
|
auto NewCarry =
|
|
DAG->getMachineNode(Subtarget->hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16,
|
|
Dl, OldCarry.getValueType(), SDValue(NewCarryReg, 0),
|
|
DAG->getTargetConstant(0, Dl, MVT::i32));
|
|
return SDValue(NewCarry, 0);
|
|
}
|
|
|
|
bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) {
|
|
MachineSDNode *NewNode = nullptr;
|
|
auto Type0 = N->getValueType(0);
|
|
auto Type1 = N->getValueType(1);
|
|
auto Op0 = N->getOperand(0);
|
|
auto Op1 = N->getOperand(1);
|
|
auto Op2 = N->getOperand(2);
|
|
|
|
SDLoc Dl(N);
|
|
|
|
if (isNullConstant(Op2)) {
|
|
auto *CA = CurDAG->getMachineNode(
|
|
Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
|
|
NewNode = CurDAG->getMachineNode(
|
|
Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
|
|
{Op0, Op1, SDValue(CA, 0)});
|
|
} else if (isOneConstant(Op2)) {
|
|
auto *CA = CurDAG->getMachineNode(
|
|
Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
|
|
NewNode = CurDAG->getMachineNode(
|
|
Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
|
|
{Op0, Op1, SDValue(CA, 0)});
|
|
} else {
|
|
auto CarryIn = InvertCarryFlag(Subtarget, CurDAG, Dl, Op2);
|
|
NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32
|
|
: CSKY::SUBC16,
|
|
Dl, {Type0, Type1}, {Op0, Op1, CarryIn});
|
|
}
|
|
auto CarryOut = InvertCarryFlag(Subtarget, CurDAG, Dl, SDValue(NewNode, 1));
|
|
|
|
ReplaceUses(SDValue(N, 0), SDValue(NewNode, 0));
|
|
ReplaceUses(SDValue(N, 1), CarryOut);
|
|
CurDAG->RemoveDeadNode(N);
|
|
|
|
return true;
|
|
}
|
|
|
|
FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM) {
|
|
return new CSKYDAGToDAGISel(TM);
|
|
}
|