Index: lib/Target/NDS32/MCTargetDesc/CMakeLists.txt =================================================================== --- lib/Target/NDS32/MCTargetDesc/CMakeLists.txt +++ lib/Target/NDS32/MCTargetDesc/CMakeLists.txt @@ -1,4 +1,5 @@ add_llvm_library(LLVMNDS32Desc NDS32MCTargetDesc.cpp NDS32MCAsmInfo.cpp + NDS32MCExpr.cpp ) Index: lib/Target/NDS32/MCTargetDesc/NDS32MCExpr.h =================================================================== --- /dev/null +++ lib/Target/NDS32/MCTargetDesc/NDS32MCExpr.h @@ -0,0 +1,58 @@ +//===-- NDS32MCExpr.h - NDS32 specific MC expression classes ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_NDS32_MCTARGETDESC_NDS32MCEXPR_H +#define LLVM_LIB_TARGET_NDS32_MCTARGETDESC_NDS32MCEXPR_H + +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCValue.h" + +namespace llvm { + +class NDS32MCExpr : public MCTargetExpr { +public: + enum NDS32ExprKind { + MEK_None, + MEK_HI, + MEK_LO, + MEK_Special, + }; + +private: + const NDS32ExprKind Kind; + const MCExpr *Expr; + + explicit NDS32MCExpr(NDS32ExprKind Kind, const MCExpr *Expr) + : Kind(Kind), Expr(Expr) {} + +public: + static const NDS32MCExpr *create(NDS32ExprKind Kind, const MCExpr *Expr, + MCContext &Ctx); + + /// Get the kind of this expression. + NDS32ExprKind getKind() const { return Kind; } + + /// Get the child of this expression. + const MCExpr *getSubExpr() const { return Expr; } + + void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override; + + bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, + const MCFixup *Fixup) const override; + void visitUsedExpr(MCStreamer &Streamer) const override; + // There are no TLS NDS32MCExprs at the moment. + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {} + MCFragment *findAssociatedFragment() const override { + return getSubExpr()->findAssociatedFragment(); + } +}; +} // end namespace llvm + +#endif Index: lib/Target/NDS32/MCTargetDesc/NDS32MCExpr.cpp =================================================================== --- /dev/null +++ lib/Target/NDS32/MCTargetDesc/NDS32MCExpr.cpp @@ -0,0 +1,68 @@ +//===-- NDS32MCExpr.cpp - NDS32 specific MC expression classes ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "NDS32MCExpr.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/Support/ELF.h" + +using namespace llvm; + +#define DEBUG_TYPE "nds32mcexpr" + +const NDS32MCExpr *NDS32MCExpr::create(NDS32MCExpr::NDS32ExprKind Kind, + const MCExpr *Expr, MCContext &Ctx) { + return new (Ctx) NDS32MCExpr(Kind, Expr); +} + +void NDS32MCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { + int64_t AbsVal; + + switch (Kind) { + case MEK_None: + case MEK_Special: + break; + case MEK_HI: + OS << "hi20("; + break; + case MEK_LO: + OS << "lo12("; + break; + default: + break; + } + + if (Expr->evaluateAsAbsolute(AbsVal)) + OS << AbsVal; + else + Expr->print(OS, MAI, true); + + switch (Kind) { + case MEK_HI: + case MEK_LO: + OS << ")"; + break; + default: + break; + } +} + +bool +NDS32MCExpr::evaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout, + const MCFixup *Fixup) const { + return false; +} + +void NDS32MCExpr::visitUsedExpr(MCStreamer &Streamer) const { + Streamer.visitUsedExpr(*getSubExpr()); +} Index: lib/Target/NDS32/NDS32AsmPrinter.cpp =================================================================== --- lib/Target/NDS32/NDS32AsmPrinter.cpp +++ lib/Target/NDS32/NDS32AsmPrinter.cpp @@ -46,6 +46,12 @@ raw_ostream &O, const char *Modifier) { const MachineOperand &MO = MI->getOperand(OpNum); + switch(MO.getTargetFlags()) { + case NDS32II::MO_HI20: O << "hi20("; break; + case NDS32II::MO_LO12: O << "lo12("; break; + default: break; + } + switch (MO.getType()) { default: llvm_unreachable("Not implemented yet!"); case MachineOperand::MO_Register: Index: lib/Target/NDS32/NDS32ISelLowering.h =================================================================== --- lib/Target/NDS32/NDS32ISelLowering.h +++ lib/Target/NDS32/NDS32ISelLowering.h @@ -67,6 +67,10 @@ /// LowerOperation - Provide custom lowering hooks for some operations. SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerExternalSymbol(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerDIVREM(SDValue Op, SelectionDAG &DAG) const; /// getTargetNodeName - This method returns the name of a target specific @@ -100,12 +104,38 @@ return NDS32::R1; } + protected: + // This method creates the following nodes, which are necessary for + // computing a symbol's address in non-PIC mode: + // + // (or %hi(sym), %lo(sym)) + template + SDValue getAddrNonPIC(NodeTy *N, const SDLoc &DL, EVT Ty, + SelectionDAG &DAG) const { + SDValue Hi = getTargetNode(N, Ty, DAG, NDS32II::MO_HI20); + SDValue Lo = getTargetNode(N, Ty, DAG, NDS32II::MO_LO12); + return DAG.getNode(ISD::OR, DL, Ty, + DAG.getNode(NDS32ISD::Hi20, DL, Ty, Hi), + DAG.getNode(NDS32ISD::Lo12, DL, Ty, Lo)); + } private: /// Subtarget - Keep a pointer to the NDS32Subtarget around so that we can /// make the right decision when generating code for different targets. const NDS32Subtarget *Subtarget; + // Create a TargetGlobalAddress node. + SDValue getTargetNode(GlobalAddressSDNode *N, EVT Ty, SelectionDAG &DAG, + unsigned Flag) const; + + // Create a TargetExternalSymbol node. + SDValue getTargetNode(ExternalSymbolSDNode *N, EVT Ty, SelectionDAG &DAG, + unsigned Flag) const; + + // Create a TargetBlockAddress node. + SDValue getTargetNode(BlockAddressSDNode *N, EVT Ty, SelectionDAG &DAG, + unsigned Flag) const; + SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl &Ins, Index: lib/Target/NDS32/NDS32ISelLowering.cpp =================================================================== --- lib/Target/NDS32/NDS32ISelLowering.cpp +++ lib/Target/NDS32/NDS32ISelLowering.cpp @@ -143,6 +143,9 @@ SDValue NDS32TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { + case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); + case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); + case ISD::ExternalSymbol: return LowerExternalSymbol(Op, DAG); case ISD::UDIVREM: return LowerDIVREM(Op, DAG); case ISD::SDIVREM: return LowerDIVREM(Op, DAG); default: @@ -161,6 +164,51 @@ return DAG.getNode(Opc, dl, vts, Ra, Rb); } +SDValue NDS32TargetLowering::LowerGlobalAddress(SDValue Op, + SelectionDAG &DAG) const { + EVT Ty = Op.getValueType(); + GlobalAddressSDNode *N = cast(Op); + + return getAddrNonPIC(N, SDLoc(N), Ty, DAG); +} + +SDValue NDS32TargetLowering::LowerExternalSymbol(SDValue Op, + SelectionDAG &DAG) const { + SDLoc dl(Op); + const char *Sym = cast(Op)->getSymbol(); + auto PtrVT = getPointerTy(DAG.getDataLayout()); + SDValue Result = DAG.getTargetExternalSymbol(Sym, PtrVT); + + return DAG.getNode(NDS32ISD::Wrapper, dl, PtrVT, Result); +} + +SDValue NDS32TargetLowering::LowerBlockAddress(SDValue Op, + SelectionDAG &DAG) const { + BlockAddressSDNode *N = cast(Op); + EVT Ty = Op.getValueType(); + + return getAddrNonPIC(N, SDLoc(N), Ty, DAG); +} + +SDValue NDS32TargetLowering::getTargetNode(GlobalAddressSDNode *N, EVT Ty, + SelectionDAG &DAG, + unsigned Flag) const { + return DAG.getTargetGlobalAddress(N->getGlobal(), SDLoc(N), Ty, 0, Flag); +} + +SDValue NDS32TargetLowering::getTargetNode(ExternalSymbolSDNode *N, EVT Ty, + SelectionDAG &DAG, + unsigned Flag) const { + return DAG.getTargetExternalSymbol(N->getSymbol(), Ty, Flag); +} + +SDValue NDS32TargetLowering::getTargetNode(BlockAddressSDNode *N, EVT Ty, + SelectionDAG &DAG, + unsigned Flag) const { + return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, 0, Flag); +} + + //===----------------------------------------------------------------------===// // NDS32 Addressing Mode Support //===----------------------------------------------------------------------===// Index: lib/Target/NDS32/NDS32InstrInfo.td =================================================================== --- lib/Target/NDS32/NDS32InstrInfo.td +++ lib/Target/NDS32/NDS32InstrInfo.td @@ -32,6 +32,12 @@ SDNode<"ISD::CALLSEQ_END", SDT_NDS32CallSeqEnd, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; +// Hi20 and Lo12 nodes are used to handle global addresses. Used on +// NDS32ISelLowering to lower stuff like GlobalAddress, ExternalSymbol +// static model. +def NDS32hi20 : SDNode<"NDS32ISD::Hi20", SDTIntUnaryOp>; +def NDS32lo12 : SDNode<"NDS32ISD::Lo12", SDTIntUnaryOp>; + def NDS32sdivrem : SDNode<"NDS32ISD::SDIVREM", SDTIntBinHiLoOp>; def NDS32udivrem : SDNode<"NDS32ISD::UDIVREM", SDTIntBinHiLoOp>; @@ -324,6 +330,18 @@ // Pattern Transformation //===----------------------------------------------------------------------===// +// hi/lo relocs +def : Pat<(NDS32hi20 tglobaladdr:$in), (SETHI tglobaladdr:$in)>; +def : Pat<(NDS32hi20 tblockaddress:$in), (SETHI tblockaddress:$in)>; +def : Pat<(NDS32hi20 texternalsym:$in), (SETHI texternalsym:$in)>; + +def : Pat<(or GPR:$hi, (NDS32lo12 tglobaladdr:$lo)), + (ORI GPR:$hi, tglobaladdr:$lo)>; +def : Pat<(or GPR:$hi, (NDS32lo12 tblockaddress:$lo)), + (ORI GPR:$hi, tblockaddress:$lo)>; +def : Pat<(or GPR:$hi, (NDS32lo12 texternalsym:$lo)), + (ORI GPR:$hi, texternalsym:$lo)>; + // Arbitrary immediates def : Pat<(i32 imm:$imm), (ORI (SETHI (HI20 imm:$imm)), (LO12 imm:$imm))>; Index: lib/Target/NDS32/NDS32MCInstLower.h =================================================================== --- lib/Target/NDS32/NDS32MCInstLower.h +++ lib/Target/NDS32/NDS32MCInstLower.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIB_TARGET_NDS32_NDS32MCINSTLOWER_H #define LLVM_LIB_TARGET_NDS32_NDS32MCINSTLOWER_H +#include "MCTargetDesc/NDS32MCExpr.h" #include "llvm/Support/Compiler.h" #include "llvm/CodeGen/MachineOperand.h" Index: lib/Target/NDS32/NDS32MCInstLower.cpp =================================================================== --- lib/Target/NDS32/NDS32MCInstLower.cpp +++ lib/Target/NDS32/NDS32MCInstLower.cpp @@ -35,9 +35,20 @@ MCOperand NDS32MCInstLower:: LowerSymbolOperand(const MachineOperand &MO, MachineOperandType MOTy, unsigned Offset) const { - + NDS32MCExpr::NDS32ExprKind TargetKind = NDS32MCExpr::MEK_None; const MCSymbol *Symbol; + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case NDS32II::MO_HI20: + TargetKind = NDS32MCExpr::MEK_HI; + break; + case NDS32II::MO_LO12: + TargetKind = NDS32MCExpr::MEK_LO; + break; + case 0: break; + } + switch (MOTy) { case MachineOperand::MO_MachineBasicBlock: Symbol = MO.getMBB()->getSymbol(); @@ -87,6 +98,9 @@ Ctx); } + if (TargetKind != NDS32MCExpr::MEK_None) + Expr = NDS32MCExpr::create(TargetKind, Expr, Ctx); + return MCOperand::createExpr(Expr); } Index: test/CodeGen/NDS32/sethi-ori-symbol.ll =================================================================== --- /dev/null +++ test/CodeGen/NDS32/sethi-ori-symbol.ll @@ -0,0 +1,15 @@ + ; RUN: llc < %s | FileCheck %s + target datalayout = "e-m:e-p:32:32-i64:64-a:0:32-n32-S64" + target triple = "nds32le---elf" + +@a = common local_unnamed_addr global [100000 x i32] zeroinitializer, align 4 + +; Function Attrs: norecurse nounwind readonly +define i32 @sethi_ori_symbol() local_unnamed_addr #1 { +entry: + %0 = load i32, i32* getelementptr inbounds ([100000 x i32], [100000 x i32]* @a, i32 0, i32 99999), align 4 +; CHECK: sethi $r0, hi20(a) +; CHECK: ori $r0, $r0, lo12(a) + ret i32 %0 +} +