From 8c1a0d70be13cffed4d552148619e62723310996 Mon Sep 17 00:00:00 2001 From: Jeremy Rand Date: Fri, 17 Jul 2015 20:05:36 -0500 Subject: [PATCH] Lots of basic infrastructure. And get it compiling. --- CMakeLists.txt | 1 + include/llvm/ADT/Triple.h | 3 +- lib/Support/Triple.cpp | 4 + lib/Target/WDC65816/CMakeLists.txt | 26 + lib/Target/WDC65816/LLVMBuild.txt | 10 +- .../WDC65816/MCTargetDesc/CMakeLists.txt | 6 + .../WDC65816/MCTargetDesc/LLVMBuild.txt | 23 + lib/Target/WDC65816/MCTargetDesc/Makefile | 16 + .../WDC65816/MCTargetDesc/WDC65816BaseInfo.h | 84 + .../MCTargetDesc/WDC65816MCAsmInfo.cpp | 46 + .../WDC65816/MCTargetDesc/WDC65816MCAsmInfo.h | 30 + .../MCTargetDesc/WDC65816MCTargetDesc.cpp | 85 + .../MCTargetDesc/WDC65816MCTargetDesc.h | 38 + lib/Target/WDC65816/Makefile | 5 +- lib/Target/WDC65816/TargetInfo/CMakeLists.txt | 7 + lib/Target/WDC65816/TargetInfo/LLVMBuild.txt | 23 + lib/Target/WDC65816/TargetInfo/Makefile | 15 + .../TargetInfo/WDC65816TargetInfo.cpp | 24 + lib/Target/WDC65816/WDC65816.h | 5 +- lib/Target/WDC65816/WDC65816.td | 2 +- lib/Target/WDC65816/WDC65816AsmPrinter.cpp | 361 +++ lib/Target/WDC65816/WDC65816CallingConv.td | 5 +- lib/Target/WDC65816/WDC65816FrameLowering.cpp | 18 +- lib/Target/WDC65816/WDC65816FrameLowering.h | 8 +- lib/Target/WDC65816/WDC65816ISelDAGToDAG.cpp | 251 ++ lib/Target/WDC65816/WDC65816ISelLowering.cpp | 2843 +++++++++++++++++ lib/Target/WDC65816/WDC65816ISelLowering.h | 166 + lib/Target/WDC65816/WDC65816InstrFormats.td | 2 +- lib/Target/WDC65816/WDC65816InstrInfo.cpp | 65 + lib/Target/WDC65816/WDC65816InstrInfo.h | 43 + lib/Target/WDC65816/WDC65816InstrInfo.td | 577 ++-- .../WDC65816/WDC65816MachineFunctionInfo.cpp | 14 + .../WDC65816/WDC65816MachineFunctionInfo.h | 69 + lib/Target/WDC65816/WDC65816RegisterInfo.cpp | 210 ++ lib/Target/WDC65816/WDC65816RegisterInfo.h | 55 + lib/Target/WDC65816/WDC65816RegisterInfo.td | 6 +- .../WDC65816/WDC65816SelectionDAGInfo.cpp | 23 + .../WDC65816/WDC65816SelectionDAGInfo.h | 31 + lib/Target/WDC65816/WDC65816TargetMachine.cpp | 6 +- lib/Target/WDC65816/WDC65816TargetMachine.h | 6 +- 40 files changed, 4914 insertions(+), 298 deletions(-) create mode 100644 lib/Target/WDC65816/CMakeLists.txt create mode 100644 lib/Target/WDC65816/MCTargetDesc/CMakeLists.txt create mode 100644 lib/Target/WDC65816/MCTargetDesc/LLVMBuild.txt create mode 100644 lib/Target/WDC65816/MCTargetDesc/Makefile create mode 100644 lib/Target/WDC65816/MCTargetDesc/WDC65816BaseInfo.h create mode 100644 lib/Target/WDC65816/MCTargetDesc/WDC65816MCAsmInfo.cpp create mode 100644 lib/Target/WDC65816/MCTargetDesc/WDC65816MCAsmInfo.h create mode 100644 lib/Target/WDC65816/MCTargetDesc/WDC65816MCTargetDesc.cpp create mode 100644 lib/Target/WDC65816/MCTargetDesc/WDC65816MCTargetDesc.h create mode 100644 lib/Target/WDC65816/TargetInfo/CMakeLists.txt create mode 100644 lib/Target/WDC65816/TargetInfo/LLVMBuild.txt create mode 100644 lib/Target/WDC65816/TargetInfo/Makefile create mode 100644 lib/Target/WDC65816/TargetInfo/WDC65816TargetInfo.cpp create mode 100644 lib/Target/WDC65816/WDC65816AsmPrinter.cpp create mode 100644 lib/Target/WDC65816/WDC65816ISelDAGToDAG.cpp create mode 100644 lib/Target/WDC65816/WDC65816ISelLowering.cpp create mode 100644 lib/Target/WDC65816/WDC65816InstrInfo.cpp create mode 100644 lib/Target/WDC65816/WDC65816InstrInfo.h create mode 100644 lib/Target/WDC65816/WDC65816MachineFunctionInfo.cpp create mode 100644 lib/Target/WDC65816/WDC65816MachineFunctionInfo.h create mode 100644 lib/Target/WDC65816/WDC65816RegisterInfo.cpp create mode 100644 lib/Target/WDC65816/WDC65816RegisterInfo.h create mode 100644 lib/Target/WDC65816/WDC65816SelectionDAGInfo.cpp create mode 100644 lib/Target/WDC65816/WDC65816SelectionDAGInfo.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bd0f846f..bbfbfde6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,6 +110,7 @@ set(LLVM_ALL_TARGETS R600 Sparc SystemZ + WDC65816 X86 XCore ) diff --git a/include/llvm/ADT/Triple.h b/include/llvm/ADT/Triple.h index 84e0b29d..7bde67da 100644 --- a/include/llvm/ADT/Triple.h +++ b/include/llvm/ADT/Triple.h @@ -71,7 +71,8 @@ public: le32, // le32: generic little-endian 32-bit CPU (PNaCl / Emscripten) amdil, // amdil: amd IL spir, // SPIR: standard portable IR for OpenCL 32-bit version - spir64 // SPIR: standard portable IR for OpenCL 64-bit version + spir64, // SPIR: standard portable IR for OpenCL 64-bit version + wdc65816 }; enum VendorType { UnknownVendor, diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp index 6c978a02..b2f47385 100644 --- a/lib/Support/Triple.cpp +++ b/lib/Support/Triple.cpp @@ -45,6 +45,7 @@ const char *Triple::getArchTypeName(ArchType Kind) { case amdil: return "amdil"; case spir: return "spir"; case spir64: return "spir64"; + case wdc65816: return "wdc65816"; } llvm_unreachable("Invalid ArchType!"); @@ -671,6 +672,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { return 0; case llvm::Triple::msp430: + case llvm::Triple::wdc65816: return 16; case llvm::Triple::amdil: @@ -725,6 +727,7 @@ Triple Triple::get32BitArchVariant() const { case Triple::msp430: case Triple::systemz: case Triple::ppc64le: + case Triple::wdc65816: T.setArch(UnknownArch); break; @@ -770,6 +773,7 @@ Triple Triple::get64BitArchVariant() const { case Triple::tce: case Triple::thumb: case Triple::xcore: + case Triple::wdc65816: T.setArch(UnknownArch); break; diff --git a/lib/Target/WDC65816/CMakeLists.txt b/lib/Target/WDC65816/CMakeLists.txt new file mode 100644 index 00000000..b3db38ee --- /dev/null +++ b/lib/Target/WDC65816/CMakeLists.txt @@ -0,0 +1,26 @@ +set(LLVM_TARGET_DEFINITIONS WDC65816.td) + +tablegen(LLVM WDC65816GenRegisterInfo.inc -gen-register-info) +tablegen(LLVM WDC65816GenInstrInfo.inc -gen-instr-info) +tablegen(LLVM WDC65816GenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM WDC65816GenDAGISel.inc -gen-dag-isel) +tablegen(LLVM WDC65816GenSubtargetInfo.inc -gen-subtarget) +tablegen(LLVM WDC65816GenCallingConv.inc -gen-callingconv) +add_public_tablegen_target(WDC65816CommonTableGen) + +add_llvm_target(WDC65816CodeGen + WDC65816AsmPrinter.cpp + WDC65816InstrInfo.cpp + WDC65816ISelDAGToDAG.cpp + WDC65816ISelLowering.cpp + WDC65816FrameLowering.cpp + WDC65816MachineFunctionInfo.cpp + WDC65816RegisterInfo.cpp + WDC65816TargetMachine.cpp + WDC65816SelectionDAGInfo.cpp +) + +add_dependencies(LLVMWDC65816CodeGen WDC65816CommonTableGen intrinsics_gen) + +add_subdirectory(TargetInfo) +add_subdirectory(MCTargetDesc) diff --git a/lib/Target/WDC65816/LLVMBuild.txt b/lib/Target/WDC65816/LLVMBuild.txt index 5aa1fa1d..fbf4106f 100644 --- a/lib/Target/WDC65816/LLVMBuild.txt +++ b/lib/Target/WDC65816/LLVMBuild.txt @@ -1,4 +1,4 @@ -;===- ./lib/Target/WDC65816/LLVMBuild.txt -------------------------*- Conf -*--===; +;===- ./lib/Target/WDC65816/LLVMBuild.txt ----------------------*- Conf -*--===; ; ; The LLVM Compiler Infrastructure ; @@ -16,19 +16,19 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = +subdirectories = MCTargetDesc TargetInfo [component_0] type = TargetGroup name = WDC65816 parent = Target -has_asmprinter = 0 +has_asmprinter = 1 has_jit = 0 [component_1] type = Library name = WDC65816CodeGen parent = WDC65816 -required_libraries = AsmPrinter CodeGen Core MC SelectionDAG - Support Target +required_libraries = AsmPrinter CodeGen Core MC SelectionDAG WDC65816Desc + WDC65816Info Support Target add_to_library_groups = WDC65816 diff --git a/lib/Target/WDC65816/MCTargetDesc/CMakeLists.txt b/lib/Target/WDC65816/MCTargetDesc/CMakeLists.txt new file mode 100644 index 00000000..e8964d20 --- /dev/null +++ b/lib/Target/WDC65816/MCTargetDesc/CMakeLists.txt @@ -0,0 +1,6 @@ +add_llvm_library(LLVMWDC65816Desc + WDC65816MCTargetDesc.cpp + WDC65816MCAsmInfo.cpp + ) + +add_dependencies(LLVMWDC65816Desc WDC65816CommonTableGen) diff --git a/lib/Target/WDC65816/MCTargetDesc/LLVMBuild.txt b/lib/Target/WDC65816/MCTargetDesc/LLVMBuild.txt new file mode 100644 index 00000000..2e4aa6ea --- /dev/null +++ b/lib/Target/WDC65816/MCTargetDesc/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/WDC65816/MCTargetDesc/LLVMBuild.txt ---------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = WDC65816Desc +parent = WDC65816 +required_libraries = MC WDC65816Info Support +add_to_library_groups = WDC65816 diff --git a/lib/Target/WDC65816/MCTargetDesc/Makefile b/lib/Target/WDC65816/MCTargetDesc/Makefile new file mode 100644 index 00000000..7434e29a --- /dev/null +++ b/lib/Target/WDC65816/MCTargetDesc/Makefile @@ -0,0 +1,16 @@ +##===- lib/Target/WDC65816/TargetDesc/Makefile -------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME = LLVMWDC65816Desc + +# Hack: we need to include 'main' target directory to grab private headers +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/lib/Target/WDC65816/MCTargetDesc/WDC65816BaseInfo.h b/lib/Target/WDC65816/MCTargetDesc/WDC65816BaseInfo.h new file mode 100644 index 00000000..f7cba6fc --- /dev/null +++ b/lib/Target/WDC65816/MCTargetDesc/WDC65816BaseInfo.h @@ -0,0 +1,84 @@ +//===-- WDC65816BaseInfo.h - Top level definitions for 65816 - --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains small standalone helper functions and enum definitions +// for the WDC65816 target useful for the compiler back-end and the MC libraries. +// As such, it deliberately does not include references to LLVM core code gen +// types, passes, etc.. +// +//===----------------------------------------------------------------------===// + +#ifndef WDC65816BASEINFO_H +#define WDC65816BASEINFO_H + +namespace llvm { + + /// SPII - This namespace holds target specific flags for instruction info. + namespace SPII { + +#if 0 // WDC_TODO - Do I need any of this? + /// Target Operand Flags. Sparc specific TargetFlags for MachineOperands and + /// SDNodes. + enum TOF { + MO_NO_FLAG, + + // Extract the low 10 bits of an address. + // Assembler: %lo(addr) + MO_LO, + + // Extract bits 31-10 of an address. Only for sethi. + // Assembler: %hi(addr) or %lm(addr) + MO_HI, + + // Extract bits 43-22 of an adress. Only for sethi. + // Assembler: %h44(addr) + MO_H44, + + // Extract bits 21-12 of an address. + // Assembler: %m44(addr) + MO_M44, + + // Extract bits 11-0 of an address. + // Assembler: %l44(addr) + MO_L44, + + // Extract bits 63-42 of an address. Only for sethi. + // Assembler: %hh(addr) + MO_HH, + + // Extract bits 41-32 of an address. + // Assembler: %hm(addr) + MO_HM, + + // TargetFlags for Thread Local Storage. + MO_TLS_GD_HI22, + MO_TLS_GD_LO10, + MO_TLS_GD_ADD, + MO_TLS_GD_CALL, + MO_TLS_LDM_HI22, + MO_TLS_LDM_LO10, + MO_TLS_LDM_ADD, + MO_TLS_LDM_CALL, + MO_TLS_LDO_HIX22, + MO_TLS_LDO_LOX10, + MO_TLS_LDO_ADD, + MO_TLS_IE_HI22, + MO_TLS_IE_LO10, + MO_TLS_IE_LD, + MO_TLS_IE_LDX, + MO_TLS_IE_ADD, + MO_TLS_LE_HIX22, + MO_TLS_LE_LOX10 + }; +#endif + + } // end namespace SPII +} // end namespace llvm + +#endif diff --git a/lib/Target/WDC65816/MCTargetDesc/WDC65816MCAsmInfo.cpp b/lib/Target/WDC65816/MCTargetDesc/WDC65816MCAsmInfo.cpp new file mode 100644 index 00000000..a898b821 --- /dev/null +++ b/lib/Target/WDC65816/MCTargetDesc/WDC65816MCAsmInfo.cpp @@ -0,0 +1,46 @@ +//===-- WDC65816MCAsmInfo.cpp - WDC65816 asm properties -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations of the WDC65816MCAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "WDC65816MCAsmInfo.h" +#include "llvm/ADT/Triple.h" + +using namespace llvm; + +void WDC65816ELFMCAsmInfo::anchor() { } + +WDC65816ELFMCAsmInfo::WDC65816ELFMCAsmInfo(StringRef TT) { + IsLittleEndian = true; + Triple TheTriple(TT); + + PointerSize = CalleeSaveStackSlotSize = 4; + +#if 0 // WDC_TODO - Do I need any of this? + Data16bitsDirective = "\t.half\t"; + Data32bitsDirective = "\t.word\t"; + // .xword is only supported by V9. + Data64bitsDirective = (isV9) ? "\t.xword\t" : 0; + ZeroDirective = "\t.skip\t"; + CommentString = "!"; + HasLEB128 = true; + SupportsDebugInformation = true; + + ExceptionsType = ExceptionHandling::DwarfCFI; + + SunStyleELFSectionSwitchSyntax = true; + UsesELFSectionDirectiveForBSS = true; + + PrivateGlobalPrefix = ".L"; +#endif +} + + diff --git a/lib/Target/WDC65816/MCTargetDesc/WDC65816MCAsmInfo.h b/lib/Target/WDC65816/MCTargetDesc/WDC65816MCAsmInfo.h new file mode 100644 index 00000000..4bbc1541 --- /dev/null +++ b/lib/Target/WDC65816/MCTargetDesc/WDC65816MCAsmInfo.h @@ -0,0 +1,30 @@ +//===-- WDC65816MCAsmInfo.h - WDC65816 asm properties ----------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the WDC65816MCAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef WDC65816TARGETASMINFO_H +#define WDC65816TARGETASMINFO_H + +#include "llvm/MC/MCAsmInfoELF.h" + +namespace llvm { + class StringRef; + + class WDC65816ELFMCAsmInfo : public MCAsmInfoELF { + virtual void anchor(); + public: + explicit WDC65816ELFMCAsmInfo(StringRef TT); + }; + +} // namespace llvm + +#endif diff --git a/lib/Target/WDC65816/MCTargetDesc/WDC65816MCTargetDesc.cpp b/lib/Target/WDC65816/MCTargetDesc/WDC65816MCTargetDesc.cpp new file mode 100644 index 00000000..9c728628 --- /dev/null +++ b/lib/Target/WDC65816/MCTargetDesc/WDC65816MCTargetDesc.cpp @@ -0,0 +1,85 @@ +//===-- WDC65816MCTargetDesc.cpp - WDC65816 Target Descriptions -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides WDC65816 specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#include "WDC65816MCTargetDesc.h" +#include "WDC65816MCAsmInfo.h" +#include "llvm/MC/MCCodeGenInfo.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +#define GET_INSTRINFO_MC_DESC +#include "WDC65816GenInstrInfo.inc" + +#define GET_SUBTARGETINFO_MC_DESC +#include "WDC65816GenSubtargetInfo.inc" + +#define GET_REGINFO_MC_DESC +#include "WDC65816GenRegisterInfo.inc" + +using namespace llvm; + +static MCInstrInfo *createWDC65816MCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitWDC65816MCInstrInfo(X); + return X; +} + +static MCRegisterInfo *createWDC65816MCRegisterInfo(StringRef TT) { + MCRegisterInfo *X = new MCRegisterInfo(); + InitWDC65816MCRegisterInfo(X, WDC::FP); + return X; +} + +static MCSubtargetInfo *createWDC65816MCSubtargetInfo(StringRef TT, StringRef CPU, + StringRef FS) { + MCSubtargetInfo *X = new MCSubtargetInfo(); + InitWDC65816MCSubtargetInfo(X, TT, CPU, FS); + return X; +} + + +static MCCodeGenInfo *createWDC65816MCCodeGenInfo(StringRef TT, Reloc::Model RM, + CodeModel::Model CM, + CodeGenOpt::Level OL) { + MCCodeGenInfo *X = new MCCodeGenInfo(); + + // The default 32-bit code model is abs32/pic32. + if (CM == CodeModel::Default) + CM = CodeModel::Medium; + + X->InitMCCodeGenInfo(RM, CM, OL); + return X; +} + + +extern "C" void LLVMInitializeWDC65816TargetMC() { + // Register the MC asm info. + RegisterMCAsmInfo X(TheWDC65816Target); + + // Register the MC codegen info. + TargetRegistry::RegisterMCCodeGenInfo(TheWDC65816Target, + createWDC65816MCCodeGenInfo); + + // Register the MC instruction info. + TargetRegistry::RegisterMCInstrInfo(TheWDC65816Target, createWDC65816MCInstrInfo); + + // Register the MC register info. + TargetRegistry::RegisterMCRegInfo(TheWDC65816Target, createWDC65816MCRegisterInfo); + + // Register the MC subtarget info. + TargetRegistry::RegisterMCSubtargetInfo(TheWDC65816Target, + createWDC65816MCSubtargetInfo); +} diff --git a/lib/Target/WDC65816/MCTargetDesc/WDC65816MCTargetDesc.h b/lib/Target/WDC65816/MCTargetDesc/WDC65816MCTargetDesc.h new file mode 100644 index 00000000..265c899d --- /dev/null +++ b/lib/Target/WDC65816/MCTargetDesc/WDC65816MCTargetDesc.h @@ -0,0 +1,38 @@ +//===-- WDC65816MCTargetDesc.h - WDC65816 Target Descriptions ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides WDC65816 specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#ifndef WDC65816MCTARGETDESC_H +#define WDC65816MCTARGETDESC_H + +namespace llvm { + class Target; + + extern Target TheWDC65816Target; + +} // End llvm namespace + +// Defines symbolic names for WDC65816 registers. This defines a mapping from +// register name to register number. +// +#define GET_REGINFO_ENUM +#include "WDC65816GenRegisterInfo.inc" + +// Defines symbolic names for the WDC65816 instructions. +// +#define GET_INSTRINFO_ENUM +#include "WDC65816GenInstrInfo.inc" + +#define GET_SUBTARGETINFO_ENUM +#include "WDC65816GenSubtargetInfo.inc" + +#endif diff --git a/lib/Target/WDC65816/Makefile b/lib/Target/WDC65816/Makefile index 378221f1..5e0eaa08 100644 --- a/lib/Target/WDC65816/Makefile +++ b/lib/Target/WDC65816/Makefile @@ -14,10 +14,9 @@ TARGET = WDC65816 # Make sure that tblgen is run, first thing. BUILT_SOURCES = WDC65816GenRegisterInfo.inc WDC65816GenInstrInfo.inc \ WDC65816GenAsmWriter.inc WDC65816GenDAGISel.inc \ - WDC65816GenSubtargetInfo.inc WDC65816GenCallingConv.inc \ - WDC65816GenCodeEmitter.inc + WDC65816GenSubtargetInfo.inc WDC65816GenCallingConv.inc -# DIRS = InstPrinter Disassembler AsmParser TargetInfo MCTargetDesc +DIRS = TargetInfo MCTargetDesc include $(LEVEL)/Makefile.common diff --git a/lib/Target/WDC65816/TargetInfo/CMakeLists.txt b/lib/Target/WDC65816/TargetInfo/CMakeLists.txt new file mode 100644 index 00000000..4ecab7c2 --- /dev/null +++ b/lib/Target/WDC65816/TargetInfo/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMWDC65816Info + WDC65816TargetInfo.cpp +) + +add_dependencies(LLVMWDC65816Info WDC65816CommonTableGen) diff --git a/lib/Target/WDC65816/TargetInfo/LLVMBuild.txt b/lib/Target/WDC65816/TargetInfo/LLVMBuild.txt new file mode 100644 index 00000000..434460f7 --- /dev/null +++ b/lib/Target/WDC65816/TargetInfo/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/WDC65816/TargetInfo/LLVMBuild.txt -----------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = WDC65816Info +parent = WDC65816 +required_libraries = MC Support Target +add_to_library_groups = WDC65816 diff --git a/lib/Target/WDC65816/TargetInfo/Makefile b/lib/Target/WDC65816/TargetInfo/Makefile new file mode 100644 index 00000000..8cab6d40 --- /dev/null +++ b/lib/Target/WDC65816/TargetInfo/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/WDC65816/TargetInfo/Makefile -------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../../.. +LIBRARYNAME = LLVMWDC65816Info + +# Hack: we need to include 'main' target directory to grab private headers +CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/lib/Target/WDC65816/TargetInfo/WDC65816TargetInfo.cpp b/lib/Target/WDC65816/TargetInfo/WDC65816TargetInfo.cpp new file mode 100644 index 00000000..ea485d0d --- /dev/null +++ b/lib/Target/WDC65816/TargetInfo/WDC65816TargetInfo.cpp @@ -0,0 +1,24 @@ +//===-- WDC65816TargetInfo.cpp - WDC65816 Target Implementation -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include +#include "WDC65816.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/TargetRegistry.h" +using namespace llvm; + +Target llvm::TheWDC65816Target; + +extern "C" void LLVMInitializeWDC65816TargetInfo() { + printf("I got called!\n"); + RegisterTarget + X(TheWDC65816Target, "wdc65816", "WDC65816"); + + TargetRegistry::printRegisteredTargetsForVersion(); +} diff --git a/lib/Target/WDC65816/WDC65816.h b/lib/Target/WDC65816/WDC65816.h index 2fbeff85..9636e28f 100644 --- a/lib/Target/WDC65816/WDC65816.h +++ b/lib/Target/WDC65816/WDC65816.h @@ -1,4 +1,4 @@ -//===-- WDC65816.h - Top-level interface for WDC65816 representation --*- C++ -*-===// +//===- WDC65816.h - Top-level interface for WDC65816 representation -*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,6 +15,7 @@ #ifndef WDC65816_H #define WDC65816_H +#include "MCTargetDesc/WDC65816MCTargetDesc.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetMachine.h" @@ -28,7 +29,7 @@ namespace llvm { } // end namespace llvm; namespace llvm { -#if 0 // JSR_TODO - Something here? +#if 0 // WDC_TODO - Something here? // Enums corresponding to Sparc condition codes, both icc's and fcc's. These // values must be kept in sync with the ones in the .td file. namespace SPCC { diff --git a/lib/Target/WDC65816/WDC65816.td b/lib/Target/WDC65816/WDC65816.td index 31800d8f..28e54f1c 100644 --- a/lib/Target/WDC65816/WDC65816.td +++ b/lib/Target/WDC65816/WDC65816.td @@ -1,4 +1,4 @@ -//===-- WDC65816.td - Describe the WDC65816 Target Machine -------*- tablegen -*-===// +//===-- WDC65816.td - Describe the WDC65816 Target Machine -*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/WDC65816/WDC65816AsmPrinter.cpp b/lib/Target/WDC65816/WDC65816AsmPrinter.cpp new file mode 100644 index 00000000..2c1974e1 --- /dev/null +++ b/lib/Target/WDC65816/WDC65816AsmPrinter.cpp @@ -0,0 +1,361 @@ +//===-- WDC65816AsmPrinter.cpp - WDC65816 LLVM assembly writer ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to GAS-format SPARC assembly language. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "WDC65816.h" +#include "WDC65816InstrInfo.h" +#include "WDC65816TargetMachine.h" +#include "MCTargetDesc/WDC65816BaseInfo.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/Mangler.h" +using namespace llvm; + +namespace { + class WDC65816AsmPrinter : public AsmPrinter { + public: + explicit WDC65816AsmPrinter(TargetMachine &TM, MCStreamer &Streamer) + : AsmPrinter(TM, Streamer) {} + + virtual const char *getPassName() const { + return "WDC65816 Assembly Printer"; + } + + void printInstruction(const MachineInstr *MI, raw_ostream &OS);// autogen'd. + void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); + void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS, + const char *Modifier = 0); + + bool printGetPCX(const MachineInstr *MI, unsigned OpNo, raw_ostream &OS); + + static const char *getRegisterName(unsigned RegNo); +#if 0 // WDC_TODO - How much of this do we need? + void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); + + virtual void EmitFunctionBodyStart(); + virtual void EmitInstruction(const MachineInstr *MI) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + printInstruction(MI, OS); + OutStreamer.EmitRawText(OS.str()); + } + + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O); + bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O); + + virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) + const; + void EmitGlobalRegisterDecl(unsigned reg) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + OS << "\t.register " + << "%" << StringRef(getRegisterName(reg)).lower() + << ", " + << ((reg == SP::G6 || reg == SP::G7)? "#ignore" : "#scratch"); + OutStreamer.EmitRawText(OS.str()); + } +#endif + + }; +} // end of anonymous namespace + +#include "WDC65816GenAsmWriter.inc" + + +void WDC65816AsmPrinter::printOperand(const MachineInstr *MI, int opNum, + raw_ostream &O) { + // WDC_TODO - print the operand here... +} + + +void WDC65816AsmPrinter::printMemOperand(const MachineInstr *MI, int opNum, + raw_ostream &O, const char *Modifier) { + // WDC_TODO - print the memory operand here... +} + + +bool WDC65816AsmPrinter::printGetPCX(const MachineInstr *MI, unsigned opNum, + raw_ostream &O) { + // WDC_TODO - print whatever this is here... +} + +#if 0 // WDC_TODO - How much of this do we need? +void WDC65816AsmPrinter::EmitFunctionBodyStart() { + const MachineRegisterInfo &MRI = MF->getRegInfo(); + const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 }; + for (unsigned i = 0; globalRegs[i] != 0; ++i) { + unsigned reg = globalRegs[i]; + if (MRI.use_empty(reg)) + continue; + EmitGlobalRegisterDecl(reg); + } +} + +void WDC65816AsmPrinter::printOperand(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand (opNum); + unsigned TF = MO.getTargetFlags(); +#ifndef NDEBUG + // Verify the target flags. + if (MO.isGlobal() || MO.isSymbol() || MO.isCPI()) { + if (MI->getOpcode() == SP::CALL) + assert(TF == SPII::MO_NO_FLAG && + "Cannot handle target flags on call address"); + else if (MI->getOpcode() == SP::SETHIi) + assert((TF == SPII::MO_HI || TF == SPII::MO_H44 || TF == SPII::MO_HH + || TF == SPII::MO_TLS_GD_HI22 + || TF == SPII::MO_TLS_LDM_HI22 + || TF == SPII::MO_TLS_LDO_HIX22 + || TF == SPII::MO_TLS_IE_HI22 + || TF == SPII::MO_TLS_LE_HIX22) && + "Invalid target flags for address operand on sethi"); + else if (MI->getOpcode() == SP::TLS_CALL) + assert((TF == SPII::MO_NO_FLAG + || TF == SPII::MO_TLS_GD_CALL + || TF == SPII::MO_TLS_LDM_CALL) && + "Cannot handle target flags on tls call address"); + else if (MI->getOpcode() == SP::TLS_ADDrr) + assert((TF == SPII::MO_TLS_GD_ADD || TF == SPII::MO_TLS_LDM_ADD + || TF == SPII::MO_TLS_LDO_ADD || TF == SPII::MO_TLS_IE_ADD) && + "Cannot handle target flags on add for TLS"); + else if (MI->getOpcode() == SP::TLS_LDrr) + assert(TF == SPII::MO_TLS_IE_LD && + "Cannot handle target flags on ld for TLS"); + else if (MI->getOpcode() == SP::TLS_LDXrr) + assert(TF == SPII::MO_TLS_IE_LDX && + "Cannot handle target flags on ldx for TLS"); + else if (MI->getOpcode() == SP::XORri) + assert((TF == SPII::MO_TLS_LDO_LOX10 || TF == SPII::MO_TLS_LE_LOX10) && + "Cannot handle target flags on xor for TLS"); + else + assert((TF == SPII::MO_LO || TF == SPII::MO_M44 || TF == SPII::MO_L44 + || TF == SPII::MO_HM + || TF == SPII::MO_TLS_GD_LO10 + || TF == SPII::MO_TLS_LDM_LO10 + || TF == SPII::MO_TLS_IE_LO10 ) && + "Invalid target flags for small address operand"); + } +#endif + + bool CloseParen = true; + switch (TF) { + default: + llvm_unreachable("Unknown target flags on operand"); + case SPII::MO_NO_FLAG: + CloseParen = false; + break; + case SPII::MO_LO: O << "%lo("; break; + case SPII::MO_HI: O << "%hi("; break; + case SPII::MO_H44: O << "%h44("; break; + case SPII::MO_M44: O << "%m44("; break; + case SPII::MO_L44: O << "%l44("; break; + case SPII::MO_HH: O << "%hh("; break; + case SPII::MO_HM: O << "%hm("; break; + case SPII::MO_TLS_GD_HI22: O << "%tgd_hi22("; break; + case SPII::MO_TLS_GD_LO10: O << "%tgd_lo10("; break; + case SPII::MO_TLS_GD_ADD: O << "%tgd_add("; break; + case SPII::MO_TLS_GD_CALL: O << "%tgd_call("; break; + case SPII::MO_TLS_LDM_HI22: O << "%tldm_hi22("; break; + case SPII::MO_TLS_LDM_LO10: O << "%tldm_lo10("; break; + case SPII::MO_TLS_LDM_ADD: O << "%tldm_add("; break; + case SPII::MO_TLS_LDM_CALL: O << "%tldm_call("; break; + case SPII::MO_TLS_LDO_HIX22: O << "%tldo_hix22("; break; + case SPII::MO_TLS_LDO_LOX10: O << "%tldo_lox10("; break; + case SPII::MO_TLS_LDO_ADD: O << "%tldo_add("; break; + case SPII::MO_TLS_IE_HI22: O << "%tie_hi22("; break; + case SPII::MO_TLS_IE_LO10: O << "%tie_lo10("; break; + case SPII::MO_TLS_IE_LD: O << "%tie_ld("; break; + case SPII::MO_TLS_IE_LDX: O << "%tie_ldx("; break; + case SPII::MO_TLS_IE_ADD: O << "%tie_add("; break; + case SPII::MO_TLS_LE_HIX22: O << "%tle_hix22("; break; + case SPII::MO_TLS_LE_LOX10: O << "%tle_lox10("; break; + } + + switch (MO.getType()) { + case MachineOperand::MO_Register: + O << "%" << StringRef(getRegisterName(MO.getReg())).lower(); + break; + + case MachineOperand::MO_Immediate: + O << (int)MO.getImm(); + break; + case MachineOperand::MO_MachineBasicBlock: + O << *MO.getMBB()->getSymbol(); + return; + case MachineOperand::MO_GlobalAddress: + O << *getSymbol(MO.getGlobal()); + break; + case MachineOperand::MO_BlockAddress: + O << GetBlockAddressSymbol(MO.getBlockAddress())->getName(); + break; + case MachineOperand::MO_ExternalSymbol: + O << MO.getSymbolName(); + break; + case MachineOperand::MO_ConstantPoolIndex: + O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_" + << MO.getIndex(); + break; + default: + llvm_unreachable(""); + } + if (CloseParen) O << ")"; +} + +void WDC65816AsmPrinter::printMemOperand(const MachineInstr *MI, int opNum, + raw_ostream &O, const char *Modifier) { + printOperand(MI, opNum, O); + + // If this is an ADD operand, emit it like normal operands. + if (Modifier && !strcmp(Modifier, "arith")) { + O << ", "; + printOperand(MI, opNum+1, O); + return; + } + + if (MI->getOperand(opNum+1).isReg() && + MI->getOperand(opNum+1).getReg() == SP::G0) + return; // don't print "+%g0" + if (MI->getOperand(opNum+1).isImm() && + MI->getOperand(opNum+1).getImm() == 0) + return; // don't print "+0" + + O << "+"; + printOperand(MI, opNum+1, O); +} + +bool WDC65816AsmPrinter::printGetPCX(const MachineInstr *MI, unsigned opNum, + raw_ostream &O) { + std::string operand = ""; + const MachineOperand &MO = MI->getOperand(opNum); + switch (MO.getType()) { + default: llvm_unreachable("Operand is not a register"); + case MachineOperand::MO_Register: + assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) && + "Operand is not a physical register "); + assert(MO.getReg() != SP::O7 && + "%o7 is assigned as destination for getpcx!"); + operand = "%" + StringRef(getRegisterName(MO.getReg())).lower(); + break; + } + + unsigned mfNum = MI->getParent()->getParent()->getFunctionNumber(); + unsigned bbNum = MI->getParent()->getNumber(); + + O << '\n' << ".LLGETPCH" << mfNum << '_' << bbNum << ":\n"; + O << "\tcall\t.LLGETPC" << mfNum << '_' << bbNum << '\n' ; + + O << "\t sethi\t" + << "%hi(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum + << ")), " << operand << '\n' ; + + O << ".LLGETPC" << mfNum << '_' << bbNum << ":\n" ; + O << "\tor\t" << operand + << ", %lo(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum + << ")), " << operand << '\n'; + O << "\tadd\t" << operand << ", %o7, " << operand << '\n'; + + return true; +} + +void WDC65816AsmPrinter::printCCOperand(const MachineInstr *MI, int opNum, + raw_ostream &O) { + int CC = (int)MI->getOperand(opNum).getImm(); + O << SPARCCondCodeToString((SPCC::CondCodes)CC); +} + +/// PrintAsmOperand - Print out an operand for an inline asm expression. +/// +bool WDC65816AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, + const char *ExtraCode, + raw_ostream &O) { + if (ExtraCode && ExtraCode[0]) { + if (ExtraCode[1] != 0) return true; // Unknown modifier. + + switch (ExtraCode[0]) { + default: + // See if this is a generic print operand + return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); + case 'r': + break; + } + } + + printOperand(MI, OpNo, O); + + return false; +} + +bool WDC65816AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNo, unsigned AsmVariant, + const char *ExtraCode, + raw_ostream &O) { + if (ExtraCode && ExtraCode[0]) + return true; // Unknown modifier + + O << '['; + printMemOperand(MI, OpNo, O); + O << ']'; + + return false; +} + +/// isBlockOnlyReachableByFallthough - Return true if the basic block has +/// exactly one predecessor and the control transfer mechanism between +/// the predecessor and this block is a fall-through. +/// +/// This overrides AsmPrinter's implementation to handle delay slots. +bool WDC65816AsmPrinter:: +isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const { + // If this is a landing pad, it isn't a fall through. If it has no preds, + // then nothing falls through to it. + if (MBB->isLandingPad() || MBB->pred_empty()) + return false; + + // If there isn't exactly one predecessor, it can't be a fall through. + MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI; + ++PI2; + if (PI2 != MBB->pred_end()) + return false; + + // The predecessor has to be immediately before this block. + const MachineBasicBlock *Pred = *PI; + + if (!Pred->isLayoutSuccessor(MBB)) + return false; + + // Check if the last terminator is an unconditional branch. + MachineBasicBlock::const_iterator I = Pred->end(); + while (I != Pred->begin() && !(--I)->isTerminator()) + ; // Noop + return I == Pred->end() || !I->isBarrier(); +} + +#endif + +// Force static initialization. +extern "C" void LLVMInitializeWDC65816AsmPrinter() { + RegisterAsmPrinter X(TheWDC65816Target); +} diff --git a/lib/Target/WDC65816/WDC65816CallingConv.td b/lib/Target/WDC65816/WDC65816CallingConv.td index b20e05cf..17d8de04 100644 --- a/lib/Target/WDC65816/WDC65816CallingConv.td +++ b/lib/Target/WDC65816/WDC65816CallingConv.td @@ -1,4 +1,4 @@ -//===- WDCCallingConv.td - Calling Conventions WDC65816 -----*- tablegen -*-===// +//===- WDCCallingConv.td - Calling Conventions WDC65816 ----*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -27,3 +27,6 @@ def CC_WDC : CallingConv<[ CCIfType<[i16], CCAssignToStack<2, 1>>, CCIfType<[i32, f32], CCAssignToStack<4, 1>> ]>; + + +def CSR_NoRegs : CalleeSavedRegs<(add)>; \ No newline at end of file diff --git a/lib/Target/WDC65816/WDC65816FrameLowering.cpp b/lib/Target/WDC65816/WDC65816FrameLowering.cpp index 1e9d9a08..eb518cdf 100644 --- a/lib/Target/WDC65816/WDC65816FrameLowering.cpp +++ b/lib/Target/WDC65816/WDC65816FrameLowering.cpp @@ -1,4 +1,4 @@ -//===-- WDC65816FrameLowering.cpp - WDC65816 Frame Information ------------------===// +//===-- WDC65816FrameLowering.cpp - WDC65816 Frame Information ------------===// // // The LLVM Compiler Infrastructure // @@ -24,6 +24,22 @@ using namespace llvm; +// hasFP - Whether or not there is a frame pointer. +// WDC_TODO - for now we will say we always have a frame pointer. +bool WDC65816FrameLowering::hasFP(const MachineFunction &MF) const { + return true; +} + + +void WDC65816FrameLowering::emitPrologue(MachineFunction &MF) const { +} + + +void WDC65816FrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { +} + + #if 0 // JSR TODO - Do I need any of this? static cl::opt DisableLeafProc("disable-sparc-leaf-proc", diff --git a/lib/Target/WDC65816/WDC65816FrameLowering.h b/lib/Target/WDC65816/WDC65816FrameLowering.h index dbf689d1..562aed9f 100644 --- a/lib/Target/WDC65816/WDC65816FrameLowering.h +++ b/lib/Target/WDC65816/WDC65816FrameLowering.h @@ -1,4 +1,4 @@ -//===-- WDC65816FrameLowering.h - Define frame lowering for Sparc --*- C++ -*-===// +//===- WDC65816FrameLowering.h - Define frame lowering for Sparc -*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -23,18 +23,20 @@ namespace llvm { public: explicit WDC65816FrameLowering(void) : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 1, 0) {} -#if 0 // JSR TODO - do I need any of this? + + bool hasFP(const MachineFunction &MF) const; + /// emitProlog/emitEpilog - These methods insert prolog and epilog code into /// the function. void emitPrologue(MachineFunction &MF) const; void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; +#if 0 // JSR TODO - do I need any of this? void eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; bool hasReservedCallFrame(const MachineFunction &MF) const; - bool hasFP(const MachineFunction &MF) const; void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, RegScavenger *RS = NULL) const; diff --git a/lib/Target/WDC65816/WDC65816ISelDAGToDAG.cpp b/lib/Target/WDC65816/WDC65816ISelDAGToDAG.cpp new file mode 100644 index 00000000..8ed61cf0 --- /dev/null +++ b/lib/Target/WDC65816/WDC65816ISelDAGToDAG.cpp @@ -0,0 +1,251 @@ +//===- WDC65816ISelDAGToDAG.cpp - A dag to dag inst selector for WDC65816 -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an instruction selector for the WDC65816 target. +// +//===----------------------------------------------------------------------===// + +#include "WDC65816TargetMachine.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Instruction Selector Implementation +//===----------------------------------------------------------------------===// + +//===--------------------------------------------------------------------===// +/// WDC65816DAGToDAGISel - WDC65816 specific code to select WDC65816 machine +/// instructions for SelectionDAG operations. +/// +namespace { + class WDC65816DAGToDAGISel : public SelectionDAGISel { + WDC65816TargetMachine &TM; + public: + explicit WDC65816DAGToDAGISel(WDC65816TargetMachine &tm) + : SelectionDAGISel(tm), + TM(tm) { + } + + SDNode *Select(SDNode *N); + + bool SelectAbs(SDValue N, SDValue &R1); + bool SelectAbsLong(SDValue N, SDValue &R1); + bool SelectDirectPage(SDValue N, SDValue &R1); + +#if 0 // WDC_TODO - we don't need these pattern selectors but we will need some + // Complex Pattern Selectors. + bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2); + bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset); + + /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for + /// inline asm expressions. + virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, + char ConstraintCode, + std::vector &OutOps); +#endif + + virtual const char *getPassName() const { + return "WDC65816 DAG->DAG Pattern Instruction Selection"; + } + + // Include the pieces autogenerated from the target description. +#include "WDC65816GenDAGISel.inc" + + private: + SDNode* getGlobalBaseReg(); + }; +} // end anonymous namespace + +SDNode* WDC65816DAGToDAGISel::getGlobalBaseReg() { + unsigned GlobalBaseReg = TM.getInstrInfo()->getGlobalBaseReg(MF); + return CurDAG->getRegister(GlobalBaseReg, + getTargetLowering()->getPointerTy()).getNode(); +} + + + + +bool WDC65816DAGToDAGISel::SelectAbs(SDValue N, SDValue &R1) { + // WDC_TODO - Write something here + return false; +} + + +bool WDC65816DAGToDAGISel::SelectAbsLong(SDValue N, SDValue &R1) { + // WDC_TODO - Write something here + return false; +} + + +bool WDC65816DAGToDAGISel::SelectDirectPage(SDValue N, SDValue &R1) { + // WDC_TODO - Write something here + return false; +} + + +#if 0 // WDC_TODO - we don't need these exactly, we need out own +bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr, + SDValue &Base, SDValue &Offset) { + if (FrameIndexSDNode *FIN = dyn_cast(Addr)) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), + getTargetLowering()->getPointerTy()); + Offset = CurDAG->getTargetConstant(0, MVT::i32); + return true; + } + if (Addr.getOpcode() == ISD::TargetExternalSymbol || + Addr.getOpcode() == ISD::TargetGlobalAddress || + Addr.getOpcode() == ISD::TargetGlobalTLSAddress) + return false; // direct calls. + + if (Addr.getOpcode() == ISD::ADD) { + if (ConstantSDNode *CN = dyn_cast(Addr.getOperand(1))) { + if (isInt<13>(CN->getSExtValue())) { + if (FrameIndexSDNode *FIN = + dyn_cast(Addr.getOperand(0))) { + // Constant offset from frame ref. + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), + getTargetLowering()->getPointerTy()); + } else { + Base = Addr.getOperand(0); + } + Offset = CurDAG->getTargetConstant(CN->getZExtValue(), MVT::i32); + return true; + } + } + if (Addr.getOperand(0).getOpcode() == SPISD::Lo) { + Base = Addr.getOperand(1); + Offset = Addr.getOperand(0).getOperand(0); + return true; + } + if (Addr.getOperand(1).getOpcode() == SPISD::Lo) { + Base = Addr.getOperand(0); + Offset = Addr.getOperand(1).getOperand(0); + return true; + } + } + Base = Addr; + Offset = CurDAG->getTargetConstant(0, MVT::i32); + return true; +} + +bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) { + if (Addr.getOpcode() == ISD::FrameIndex) return false; + if (Addr.getOpcode() == ISD::TargetExternalSymbol || + Addr.getOpcode() == ISD::TargetGlobalAddress || + Addr.getOpcode() == ISD::TargetGlobalTLSAddress) + return false; // direct calls. + + if (Addr.getOpcode() == ISD::ADD) { + if (ConstantSDNode *CN = dyn_cast(Addr.getOperand(1))) + if (isInt<13>(CN->getSExtValue())) + return false; // Let the reg+imm pattern catch this! + if (Addr.getOperand(0).getOpcode() == SPISD::Lo || + Addr.getOperand(1).getOpcode() == SPISD::Lo) + return false; // Let the reg+imm pattern catch this! + R1 = Addr.getOperand(0); + R2 = Addr.getOperand(1); + return true; + } + + R1 = Addr; + R2 = CurDAG->getRegister(SP::G0, getTargetLowering()->getPointerTy()); + return true; +} +#endif + +SDNode *WDC65816DAGToDAGISel::Select(SDNode *N) { + return NULL; +#if 0 // WDC_TODO - we will definitely need something here + SDLoc dl(N); + if (N->isMachineOpcode()) { + N->setNodeId(-1); + return NULL; // Already selected. + } + + switch (N->getOpcode()) { + default: break; + case SPISD::GLOBAL_BASE_REG: + return getGlobalBaseReg(); + + case ISD::SDIV: + case ISD::UDIV: { + // sdivx / udivx handle 64-bit divides. + if (N->getValueType(0) == MVT::i64) + break; + // FIXME: should use a custom expander to expose the SRA to the dag. + SDValue DivLHS = N->getOperand(0); + SDValue DivRHS = N->getOperand(1); + + // Set the Y register to the high-part. + SDValue TopPart; + if (N->getOpcode() == ISD::SDIV) { + TopPart = SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS, + CurDAG->getTargetConstant(31, MVT::i32)), 0); + } else { + TopPart = CurDAG->getRegister(SP::G0, MVT::i32); + } + TopPart = SDValue(CurDAG->getMachineNode(SP::WRYrr, dl, MVT::Glue, TopPart, + CurDAG->getRegister(SP::G0, MVT::i32)), 0); + + // FIXME: Handle div by immediate. + unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr; + return CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS, + TopPart); + } + case ISD::MULHU: + case ISD::MULHS: { + // FIXME: Handle mul by immediate. + SDValue MulLHS = N->getOperand(0); + SDValue MulRHS = N->getOperand(1); + unsigned Opcode = N->getOpcode() == ISD::MULHU ? SP::UMULrr : SP::SMULrr; + SDNode *Mul = CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::Glue, + MulLHS, MulRHS); + // The high part is in the Y register. + return CurDAG->SelectNodeTo(N, SP::RDY, MVT::i32, SDValue(Mul, 1)); + } + } + + return SelectCode(N); +#endif +} + + +#if 0 // WDC_TODO - Not sure what this is about... +/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for +/// inline asm expressions. +bool +SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op, + char ConstraintCode, + std::vector &OutOps) { + SDValue Op0, Op1; + switch (ConstraintCode) { + default: return true; + case 'm': // memory + if (!SelectADDRrr(Op, Op0, Op1)) + SelectADDRri(Op, Op0, Op1); + break; + } + + OutOps.push_back(Op0); + OutOps.push_back(Op1); + return false; +} +#endif + +/// createWDC65816ISelDag - This pass converts a legalized DAG into a +/// WDC65816-specific DAG, ready for instruction scheduling. +/// +FunctionPass *llvm::createWDC65816ISelDag(WDC65816TargetMachine &TM) { + return new WDC65816DAGToDAGISel(TM); +} diff --git a/lib/Target/WDC65816/WDC65816ISelLowering.cpp b/lib/Target/WDC65816/WDC65816ISelLowering.cpp new file mode 100644 index 00000000..08ae0085 --- /dev/null +++ b/lib/Target/WDC65816/WDC65816ISelLowering.cpp @@ -0,0 +1,2843 @@ +//===-- WDC65816ISelLowering.cpp - WDC65816 DAG Lowering Implementation ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the interfaces that WDC65816 uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#include "WDC65816ISelLowering.h" +#include "WDC65816MachineFunctionInfo.h" +#include "WDC65816RegisterInfo.h" +#include "WDC65816TargetMachine.h" +#include "MCTargetDesc/WDC65816BaseInfo.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/ErrorHandling.h" +using namespace llvm; + + +//===----------------------------------------------------------------------===// +// Calling Convention Implementation +//===----------------------------------------------------------------------===// +#if 0 // WDC_TODO - Disable all of this from Sparc for now... +static bool CC_WDC65816_Assign_SRet(unsigned &ValNo, MVT &ValVT, + MVT &LocVT, CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, CCState &State) +{ + assert (ArgFlags.isSRet()); + + // Assign SRet argument. + State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, + 0, + LocVT, LocInfo)); + return true; +} + +static bool CC_WDC65816_Assign_f64(unsigned &ValNo, MVT &ValVT, + MVT &LocVT, CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, CCState &State) +{ + static const uint16_t RegList[] = { + SP::I0, SP::I1, SP::I2, SP::I3, SP::I4, SP::I5 + }; + // Try to get first reg. + if (unsigned Reg = State.AllocateReg(RegList, 6)) { + State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + } else { + // Assign whole thing in stack. + State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, + State.AllocateStack(8,4), + LocVT, LocInfo)); + return true; + } + + // Try to get second reg. + if (unsigned Reg = State.AllocateReg(RegList, 6)) + State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + else + State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, + State.AllocateStack(4,4), + LocVT, LocInfo)); + return true; +} + +// Allocate a full-sized argument for the 64-bit ABI. +static bool CC_WDC6581664_Full(unsigned &ValNo, MVT &ValVT, + MVT &LocVT, CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, CCState &State) { + assert((LocVT == MVT::f32 || LocVT.getSizeInBits() == 64) && + "Can't handle non-64 bits locations"); + + // Stack space is allocated for all arguments starting from [%fp+BIAS+128]. + unsigned Offset = State.AllocateStack(8, 8); + unsigned Reg = 0; + + if (LocVT == MVT::i64 && Offset < 6*8) + // Promote integers to %i0-%i5. + Reg = SP::I0 + Offset/8; + else if (LocVT == MVT::f64 && Offset < 16*8) + // Promote doubles to %d0-%d30. (Which LLVM calls D0-D15). + Reg = SP::D0 + Offset/8; + else if (LocVT == MVT::f32 && Offset < 16*8) + // Promote floats to %f1, %f3, ... + Reg = SP::F1 + Offset/4; + + // Promote to register when possible, otherwise use the stack slot. + if (Reg) { + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + return true; + } + + // This argument goes on the stack in an 8-byte slot. + // When passing floats, LocVT is smaller than 8 bytes. Adjust the offset to + // the right-aligned float. The first 4 bytes of the stack slot are undefined. + if (LocVT == MVT::f32) + Offset += 4; + + State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); + return true; +} + +// Allocate a half-sized argument for the 64-bit ABI. +// +// This is used when passing { float, int } structs by value in registers. +static bool CC_WDC6581664_Half(unsigned &ValNo, MVT &ValVT, + MVT &LocVT, CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, CCState &State) { + assert(LocVT.getSizeInBits() == 32 && "Can't handle non-32 bits locations"); + unsigned Offset = State.AllocateStack(4, 4); + + if (LocVT == MVT::f32 && Offset < 16*8) { + // Promote floats to %f0-%f31. + State.addLoc(CCValAssign::getReg(ValNo, ValVT, SP::F0 + Offset/4, + LocVT, LocInfo)); + return true; + } + + if (LocVT == MVT::i32 && Offset < 6*8) { + // Promote integers to %i0-%i5, using half the register. + unsigned Reg = SP::I0 + Offset/8; + LocVT = MVT::i64; + LocInfo = CCValAssign::AExt; + + // Set the Custom bit if this i32 goes in the high bits of a register. + if (Offset % 8 == 0) + State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, + LocVT, LocInfo)); + else + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + return true; + } + + State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); + return true; +} +#endif + +#include "WDC65816GenCallingConv.inc" + +#if 0 // WDC_TODO - Get rid of this? +// The calling conventions in WDC65816CallingConv.td are described in terms of the +// callee's register window. This function translates registers to the +// corresponding caller window %o register. +static unsigned toCallerWindow(unsigned Reg) { + assert(SP::I0 + 7 == SP::I7 && SP::O0 + 7 == SP::O7 && "Unexpected enum"); + if (Reg >= SP::I0 && Reg <= SP::I7) + return Reg - SP::I0 + SP::O0; + return Reg; +} +#endif + +#if 0 // WDC_TODO - Disable more stuff +SDValue +WDC65816TargetLowering::LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + SDLoc DL, SelectionDAG &DAG) const { + if (Subtarget->is64Bit()) + return LowerReturn_64(Chain, CallConv, IsVarArg, Outs, OutVals, DL, DAG); + return LowerReturn_32(Chain, CallConv, IsVarArg, Outs, OutVals, DL, DAG); +} + +SDValue +WDC65816TargetLowering::LowerReturn_32(SDValue Chain, + CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + SDLoc DL, SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + + // CCValAssign - represent the assignment of the return value to locations. + SmallVector RVLocs; + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), + DAG.getTarget(), RVLocs, *DAG.getContext()); + + // Analyze return values. + CCInfo.AnalyzeReturn(Outs, RetCC_WDC6581632); + + SDValue Flag; + SmallVector RetOps(1, Chain); + // Make room for the return address offset. + RetOps.push_back(SDValue()); + + // Copy the result values into the output registers. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + CCValAssign &VA = RVLocs[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + + Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), + OutVals[i], Flag); + + // Guarantee that all emitted copies are stuck together with flags. + Flag = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); + } + + unsigned RetAddrOffset = 8; // Call Inst + Delay Slot + // If the function returns a struct, copy the SRetReturnReg to I0 + if (MF.getFunction()->hasStructRetAttr()) { + WDC65816MachineFunctionInfo *SFI = MF.getInfo(); + unsigned Reg = SFI->getSRetReturnReg(); + if (!Reg) + llvm_unreachable("sret virtual register not created in the entry block"); + SDValue Val = DAG.getCopyFromReg(Chain, DL, Reg, getPointerTy()); + Chain = DAG.getCopyToReg(Chain, DL, SP::I0, Val, Flag); + Flag = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(SP::I0, getPointerTy())); + RetAddrOffset = 12; // CallInst + Delay Slot + Unimp + } + + RetOps[0] = Chain; // Update chain. + RetOps[1] = DAG.getConstant(RetAddrOffset, MVT::i32); + + // Add the flag if we have it. + if (Flag.getNode()) + RetOps.push_back(Flag); + + return DAG.getNode(SPISD::RET_FLAG, DL, MVT::Other, + &RetOps[0], RetOps.size()); +} + +// Lower return values for the 64-bit ABI. +// Return values are passed the exactly the same way as function arguments. +SDValue +WDC65816TargetLowering::LowerReturn_64(SDValue Chain, + CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + SDLoc DL, SelectionDAG &DAG) const { + // CCValAssign - represent the assignment of the return value to locations. + SmallVector RVLocs; + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), + DAG.getTarget(), RVLocs, *DAG.getContext()); + + // Analyze return values. + CCInfo.AnalyzeReturn(Outs, CC_WDC6581664); + + SDValue Flag; + SmallVector RetOps(1, Chain); + + // The second operand on the return instruction is the return address offset. + // The return address is always %i7+8 with the 64-bit ABI. + RetOps.push_back(DAG.getConstant(8, MVT::i32)); + + // Copy the result values into the output registers. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + CCValAssign &VA = RVLocs[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + SDValue OutVal = OutVals[i]; + + // Integer return values must be sign or zero extended by the callee. + switch (VA.getLocInfo()) { + case CCValAssign::SExt: + OutVal = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), OutVal); + break; + case CCValAssign::ZExt: + OutVal = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), OutVal); + break; + case CCValAssign::AExt: + OutVal = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), OutVal); + default: + break; + } + + // The custom bit on an i32 return value indicates that it should be passed + // in the high bits of the register. + if (VA.getValVT() == MVT::i32 && VA.needsCustom()) { + OutVal = DAG.getNode(ISD::SHL, DL, MVT::i64, OutVal, + DAG.getConstant(32, MVT::i32)); + + // The next value may go in the low bits of the same register. + // Handle both at once. + if (i+1 < RVLocs.size() && RVLocs[i+1].getLocReg() == VA.getLocReg()) { + SDValue NV = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, OutVals[i+1]); + OutVal = DAG.getNode(ISD::OR, DL, MVT::i64, OutVal, NV); + // Skip the next value, it's already done. + ++i; + } + } + + Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVal, Flag); + + // Guarantee that all emitted copies are stuck together with flags. + Flag = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); + } + + RetOps[0] = Chain; // Update chain. + + // Add the flag if we have it. + if (Flag.getNode()) + RetOps.push_back(Flag); + + return DAG.getNode(SPISD::RET_FLAG, DL, MVT::Other, + &RetOps[0], RetOps.size()); +} + +SDValue WDC65816TargetLowering:: +LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Ins, + SDLoc DL, + SelectionDAG &DAG, + SmallVectorImpl &InVals) const { + if (Subtarget->is64Bit()) + return LowerFormalArguments_64(Chain, CallConv, IsVarArg, Ins, + DL, DAG, InVals); + return LowerFormalArguments_32(Chain, CallConv, IsVarArg, Ins, + DL, DAG, InVals); +} + +/// LowerFormalArguments32 - V8 uses a very simple ABI, where all values are +/// passed in either one or two GPRs, including FP values. TODO: we should +/// pass FP values in FP registers for fastcc functions. +SDValue WDC65816TargetLowering:: +LowerFormalArguments_32(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl &Ins, + SDLoc dl, + SelectionDAG &DAG, + SmallVectorImpl &InVals) const { + MachineFunction &MF = DAG.getMachineFunction(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + WDC65816MachineFunctionInfo *FuncInfo = MF.getInfo(); + + // Assign locations to all of the incoming arguments. + SmallVector ArgLocs; + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), + getTargetMachine(), ArgLocs, *DAG.getContext()); + CCInfo.AnalyzeFormalArguments(Ins, CC_WDC6581632); + + const unsigned StackOffset = 92; + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + + if (i == 0 && Ins[i].Flags.isSRet()) { + // Get SRet from [%fp+64]. + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, 64, true); + SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + SDValue Arg = DAG.getLoad(MVT::i32, dl, Chain, FIPtr, + MachinePointerInfo(), + false, false, false, 0); + InVals.push_back(Arg); + continue; + } + + if (VA.isRegLoc()) { + if (VA.needsCustom()) { + assert(VA.getLocVT() == MVT::f64); + unsigned VRegHi = RegInfo.createVirtualRegister(&SP::IntRegsRegClass); + MF.getRegInfo().addLiveIn(VA.getLocReg(), VRegHi); + SDValue HiVal = DAG.getCopyFromReg(Chain, dl, VRegHi, MVT::i32); + + assert(i+1 < e); + CCValAssign &NextVA = ArgLocs[++i]; + + SDValue LoVal; + if (NextVA.isMemLoc()) { + int FrameIdx = MF.getFrameInfo()-> + CreateFixedObject(4, StackOffset+NextVA.getLocMemOffset(),true); + SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + LoVal = DAG.getLoad(MVT::i32, dl, Chain, FIPtr, + MachinePointerInfo(), + false, false, false, 0); + } else { + unsigned loReg = MF.addLiveIn(NextVA.getLocReg(), + &SP::IntRegsRegClass); + LoVal = DAG.getCopyFromReg(Chain, dl, loReg, MVT::i32); + } + SDValue WholeValue = + DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, LoVal, HiVal); + WholeValue = DAG.getNode(ISD::BITCAST, dl, MVT::f64, WholeValue); + InVals.push_back(WholeValue); + continue; + } + unsigned VReg = RegInfo.createVirtualRegister(&SP::IntRegsRegClass); + MF.getRegInfo().addLiveIn(VA.getLocReg(), VReg); + SDValue Arg = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i32); + if (VA.getLocVT() == MVT::f32) + Arg = DAG.getNode(ISD::BITCAST, dl, MVT::f32, Arg); + else if (VA.getLocVT() != MVT::i32) { + Arg = DAG.getNode(ISD::AssertSext, dl, MVT::i32, Arg, + DAG.getValueType(VA.getLocVT())); + Arg = DAG.getNode(ISD::TRUNCATE, dl, VA.getLocVT(), Arg); + } + InVals.push_back(Arg); + continue; + } + + assert(VA.isMemLoc()); + + unsigned Offset = VA.getLocMemOffset()+StackOffset; + + if (VA.needsCustom()) { + assert(VA.getValVT() == MVT::f64); + // If it is double-word aligned, just load. + if (Offset % 8 == 0) { + int FI = MF.getFrameInfo()->CreateFixedObject(8, + Offset, + true); + SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy()); + SDValue Load = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, + MachinePointerInfo(), + false,false, false, 0); + InVals.push_back(Load); + continue; + } + + int FI = MF.getFrameInfo()->CreateFixedObject(4, + Offset, + true); + SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy()); + SDValue HiVal = DAG.getLoad(MVT::i32, dl, Chain, FIPtr, + MachinePointerInfo(), + false, false, false, 0); + int FI2 = MF.getFrameInfo()->CreateFixedObject(4, + Offset+4, + true); + SDValue FIPtr2 = DAG.getFrameIndex(FI2, getPointerTy()); + + SDValue LoVal = DAG.getLoad(MVT::i32, dl, Chain, FIPtr2, + MachinePointerInfo(), + false, false, false, 0); + + SDValue WholeValue = + DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, LoVal, HiVal); + WholeValue = DAG.getNode(ISD::BITCAST, dl, MVT::f64, WholeValue); + InVals.push_back(WholeValue); + continue; + } + + int FI = MF.getFrameInfo()->CreateFixedObject(4, + Offset, + true); + SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy()); + SDValue Load ; + if (VA.getValVT() == MVT::i32 || VA.getValVT() == MVT::f32) { + Load = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, + MachinePointerInfo(), + false, false, false, 0); + } else { + ISD::LoadExtType LoadOp = ISD::SEXTLOAD; + // WDC65816 is big endian, so add an offset based on the ObjectVT. + unsigned Offset = 4-std::max(1U, VA.getValVT().getSizeInBits()/8); + FIPtr = DAG.getNode(ISD::ADD, dl, MVT::i32, FIPtr, + DAG.getConstant(Offset, MVT::i32)); + Load = DAG.getExtLoad(LoadOp, dl, MVT::i32, Chain, FIPtr, + MachinePointerInfo(), + VA.getValVT(), false, false,0); + Load = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), Load); + } + InVals.push_back(Load); + } + + if (MF.getFunction()->hasStructRetAttr()) { + // Copy the SRet Argument to SRetReturnReg. + WDC65816MachineFunctionInfo *SFI = MF.getInfo(); + unsigned Reg = SFI->getSRetReturnReg(); + if (!Reg) { + Reg = MF.getRegInfo().createVirtualRegister(&SP::IntRegsRegClass); + SFI->setSRetReturnReg(Reg); + } + SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), dl, Reg, InVals[0]); + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Copy, Chain); + } + + // Store remaining ArgRegs to the stack if this is a varargs function. + if (isVarArg) { + static const uint16_t ArgRegs[] = { + SP::I0, SP::I1, SP::I2, SP::I3, SP::I4, SP::I5 + }; + unsigned NumAllocated = CCInfo.getFirstUnallocated(ArgRegs, 6); + const uint16_t *CurArgReg = ArgRegs+NumAllocated, *ArgRegEnd = ArgRegs+6; + unsigned ArgOffset = CCInfo.getNextStackOffset(); + if (NumAllocated == 6) + ArgOffset += StackOffset; + else { + assert(!ArgOffset); + ArgOffset = 68+4*NumAllocated; + } + + // Remember the vararg offset for the va_start implementation. + FuncInfo->setVarArgsFrameOffset(ArgOffset); + + std::vector OutChains; + + for (; CurArgReg != ArgRegEnd; ++CurArgReg) { + unsigned VReg = RegInfo.createVirtualRegister(&SP::IntRegsRegClass); + MF.getRegInfo().addLiveIn(*CurArgReg, VReg); + SDValue Arg = DAG.getCopyFromReg(DAG.getRoot(), dl, VReg, MVT::i32); + + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, ArgOffset, + true); + SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + + OutChains.push_back(DAG.getStore(DAG.getRoot(), dl, Arg, FIPtr, + MachinePointerInfo(), + false, false, 0)); + ArgOffset += 4; + } + + if (!OutChains.empty()) { + OutChains.push_back(Chain); + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + &OutChains[0], OutChains.size()); + } + } + + return Chain; +} + +// Lower formal arguments for the 64 bit ABI. +SDValue WDC65816TargetLowering:: +LowerFormalArguments_64(SDValue Chain, + CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Ins, + SDLoc DL, + SelectionDAG &DAG, + SmallVectorImpl &InVals) const { + MachineFunction &MF = DAG.getMachineFunction(); + + // Analyze arguments according to CC_WDC6581664. + SmallVector ArgLocs; + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), + getTargetMachine(), ArgLocs, *DAG.getContext()); + CCInfo.AnalyzeFormalArguments(Ins, CC_WDC6581664); + + // The argument array begins at %fp+BIAS+128, after the register save area. + const unsigned ArgArea = 128; + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + if (VA.isRegLoc()) { + // This argument is passed in a register. + // All integer register arguments are promoted by the caller to i64. + + // Create a virtual register for the promoted live-in value. + unsigned VReg = MF.addLiveIn(VA.getLocReg(), + getRegClassFor(VA.getLocVT())); + SDValue Arg = DAG.getCopyFromReg(Chain, DL, VReg, VA.getLocVT()); + + // Get the high bits for i32 struct elements. + if (VA.getValVT() == MVT::i32 && VA.needsCustom()) + Arg = DAG.getNode(ISD::SRL, DL, VA.getLocVT(), Arg, + DAG.getConstant(32, MVT::i32)); + + // The caller promoted the argument, so insert an Assert?ext SDNode so we + // won't promote the value again in this function. + switch (VA.getLocInfo()) { + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), Arg, + DAG.getValueType(VA.getValVT())); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), Arg, + DAG.getValueType(VA.getValVT())); + break; + default: + break; + } + + // Truncate the register down to the argument type. + if (VA.isExtInLoc()) + Arg = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Arg); + + InVals.push_back(Arg); + continue; + } + + // The registers are exhausted. This argument was passed on the stack. + assert(VA.isMemLoc()); + // The CC_WDC6581664_Full/Half functions compute stack offsets relative to the + // beginning of the arguments area at %fp+BIAS+128. + unsigned Offset = VA.getLocMemOffset() + ArgArea; + unsigned ValSize = VA.getValVT().getSizeInBits() / 8; + // Adjust offset for extended arguments, WDC65816 is big-endian. + // The caller will have written the full slot with extended bytes, but we + // prefer our own extending loads. + if (VA.isExtInLoc()) + Offset += 8 - ValSize; + int FI = MF.getFrameInfo()->CreateFixedObject(ValSize, Offset, true); + InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, + DAG.getFrameIndex(FI, getPointerTy()), + MachinePointerInfo::getFixedStack(FI), + false, false, false, 0)); + } + + if (!IsVarArg) + return Chain; + + // This function takes variable arguments, some of which may have been passed + // in registers %i0-%i5. Variable floating point arguments are never passed + // in floating point registers. They go on %i0-%i5 or on the stack like + // integer arguments. + // + // The va_start intrinsic needs to know the offset to the first variable + // argument. + unsigned ArgOffset = CCInfo.getNextStackOffset(); + WDC65816MachineFunctionInfo *FuncInfo = MF.getInfo(); + // Skip the 128 bytes of register save area. + FuncInfo->setVarArgsFrameOffset(ArgOffset + ArgArea + + Subtarget->getStackPointerBias()); + + // Save the variable arguments that were passed in registers. + // The caller is required to reserve stack space for 6 arguments regardless + // of how many arguments were actually passed. + SmallVector OutChains; + for (; ArgOffset < 6*8; ArgOffset += 8) { + unsigned VReg = MF.addLiveIn(SP::I0 + ArgOffset/8, &SP::I64RegsRegClass); + SDValue VArg = DAG.getCopyFromReg(Chain, DL, VReg, MVT::i64); + int FI = MF.getFrameInfo()->CreateFixedObject(8, ArgOffset + ArgArea, true); + OutChains.push_back(DAG.getStore(Chain, DL, VArg, + DAG.getFrameIndex(FI, getPointerTy()), + MachinePointerInfo::getFixedStack(FI), + false, false, 0)); + } + + if (!OutChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, + &OutChains[0], OutChains.size()); + + return Chain; +} + +SDValue +WDC65816TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const { + if (Subtarget->is64Bit()) + return LowerCall_64(CLI, InVals); + return LowerCall_32(CLI, InVals); +} + +static bool hasReturnsTwiceAttr(SelectionDAG &DAG, SDValue Callee, + ImmutableCallSite *CS) { + if (CS) + return CS->hasFnAttr(Attribute::ReturnsTwice); + + const Function *CalleeFn = 0; + if (GlobalAddressSDNode *G = dyn_cast(Callee)) { + CalleeFn = dyn_cast(G->getGlobal()); + } else if (ExternalSymbolSDNode *E = + dyn_cast(Callee)) { + const Function *Fn = DAG.getMachineFunction().getFunction(); + const Module *M = Fn->getParent(); + const char *CalleeName = E->getSymbol(); + CalleeFn = M->getFunction(CalleeName); + } + + if (!CalleeFn) + return false; + return CalleeFn->hasFnAttribute(Attribute::ReturnsTwice); +} + +// Lower a call for the 32-bit ABI. +SDValue +WDC65816TargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const { + SelectionDAG &DAG = CLI.DAG; + SDLoc &dl = CLI.DL; + SmallVectorImpl &Outs = CLI.Outs; + SmallVectorImpl &OutVals = CLI.OutVals; + SmallVectorImpl &Ins = CLI.Ins; + SDValue Chain = CLI.Chain; + SDValue Callee = CLI.Callee; + bool &isTailCall = CLI.IsTailCall; + CallingConv::ID CallConv = CLI.CallConv; + bool isVarArg = CLI.IsVarArg; + + // WDC65816 target does not yet support tail call optimization. + isTailCall = false; + + // Analyze operands of the call, assigning locations to each operand. + SmallVector ArgLocs; + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), + DAG.getTarget(), ArgLocs, *DAG.getContext()); + CCInfo.AnalyzeCallOperands(Outs, CC_WDC6581632); + + // Get the size of the outgoing arguments stack space requirement. + unsigned ArgsSize = CCInfo.getNextStackOffset(); + + // Keep stack frames 8-byte aligned. + ArgsSize = (ArgsSize+7) & ~7; + + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + + // Create local copies for byval args. + SmallVector 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(); + unsigned Align = Flags.getByValAlign(); + + int FI = MFI->CreateStackObject(Size, Align, false); + SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy()); + SDValue SizeNode = DAG.getConstant(Size, MVT::i32); + + Chain = DAG.getMemcpy(Chain, dl, FIPtr, Arg, SizeNode, Align, + false, // isVolatile, + (Size <= 32), // AlwaysInline if size <= 32 + MachinePointerInfo(), MachinePointerInfo()); + ByValArgs.push_back(FIPtr); + } + + Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(ArgsSize, true), + dl); + + SmallVector, 8> RegsToPass; + SmallVector MemOpChains; + + const unsigned StackOffset = 92; + bool hasStructRetAttr = false; + // Walk the register/memloc assignments, inserting copies/loads. + for (unsigned i = 0, realArgIdx = 0, byvalArgIdx = 0, e = ArgLocs.size(); + i != e; + ++i, ++realArgIdx) { + CCValAssign &VA = ArgLocs[i]; + SDValue Arg = OutVals[realArgIdx]; + + ISD::ArgFlagsTy Flags = Outs[realArgIdx].Flags; + + // Use local copy if it is a byval arg. + if (Flags.isByVal()) + Arg = ByValArgs[byvalArgIdx++]; + + // Promote the value if needed. + switch (VA.getLocInfo()) { + default: llvm_unreachable("Unknown loc info!"); + case CCValAssign::Full: break; + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg); + break; + case CCValAssign::AExt: + Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg); + break; + case CCValAssign::BCvt: + Arg = DAG.getNode(ISD::BITCAST, dl, VA.getLocVT(), Arg); + break; + } + + if (Flags.isSRet()) { + assert(VA.needsCustom()); + // store SRet argument in %sp+64 + SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); + SDValue PtrOff = DAG.getIntPtrConstant(64); + PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); + MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, + MachinePointerInfo(), + false, false, 0)); + hasStructRetAttr = true; + continue; + } + + if (VA.needsCustom()) { + assert(VA.getLocVT() == MVT::f64); + + if (VA.isMemLoc()) { + unsigned Offset = VA.getLocMemOffset() + StackOffset; + // if it is double-word aligned, just store. + if (Offset % 8 == 0) { + SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); + SDValue PtrOff = DAG.getIntPtrConstant(Offset); + PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); + MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, + MachinePointerInfo(), + false, false, 0)); + continue; + } + } + + SDValue StackPtr = DAG.CreateStackTemporary(MVT::f64, MVT::i32); + SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, + Arg, StackPtr, MachinePointerInfo(), + false, false, 0); + // WDC65816 is big-endian, so the high part comes first. + SDValue Hi = DAG.getLoad(MVT::i32, dl, Store, StackPtr, + MachinePointerInfo(), false, false, false, 0); + // Increment the pointer to the other half. + StackPtr = DAG.getNode(ISD::ADD, dl, StackPtr.getValueType(), StackPtr, + DAG.getIntPtrConstant(4)); + // Load the low part. + SDValue Lo = DAG.getLoad(MVT::i32, dl, Store, StackPtr, + MachinePointerInfo(), false, false, false, 0); + + if (VA.isRegLoc()) { + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Hi)); + assert(i+1 != e); + CCValAssign &NextVA = ArgLocs[++i]; + if (NextVA.isRegLoc()) { + RegsToPass.push_back(std::make_pair(NextVA.getLocReg(), Lo)); + } else { + // Store the low part in stack. + unsigned Offset = NextVA.getLocMemOffset() + StackOffset; + SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); + SDValue PtrOff = DAG.getIntPtrConstant(Offset); + PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); + MemOpChains.push_back(DAG.getStore(Chain, dl, Lo, PtrOff, + MachinePointerInfo(), + false, false, 0)); + } + } else { + unsigned Offset = VA.getLocMemOffset() + StackOffset; + // Store the high part. + SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); + SDValue PtrOff = DAG.getIntPtrConstant(Offset); + PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); + MemOpChains.push_back(DAG.getStore(Chain, dl, Hi, PtrOff, + MachinePointerInfo(), + false, false, 0)); + // Store the low part. + PtrOff = DAG.getIntPtrConstant(Offset+4); + PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); + MemOpChains.push_back(DAG.getStore(Chain, dl, Lo, PtrOff, + MachinePointerInfo(), + false, false, 0)); + } + continue; + } + + // Arguments that can be passed on register must be kept at + // RegsToPass vector + if (VA.isRegLoc()) { + if (VA.getLocVT() != MVT::f32) { + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); + continue; + } + Arg = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Arg); + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); + continue; + } + + assert(VA.isMemLoc()); + + // Create a store off the stack pointer for this argument. + SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); + SDValue PtrOff = DAG.getIntPtrConstant(VA.getLocMemOffset()+StackOffset); + PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); + MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, + MachinePointerInfo(), + false, false, 0)); + } + + + // Emit all stores, make sure the occur before any copies into physregs. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + &MemOpChains[0], MemOpChains.size()); + + // Build a sequence of copy-to-reg nodes chained together with token + // chain and flag operands which copy the outgoing args into registers. + // The InFlag in necessary since all emitted instructions must be + // stuck together. + SDValue InFlag; + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { + unsigned Reg = toCallerWindow(RegsToPass[i].first); + Chain = DAG.getCopyToReg(Chain, dl, Reg, RegsToPass[i].second, InFlag); + InFlag = Chain.getValue(1); + } + + unsigned SRetArgSize = (hasStructRetAttr)? getSRetArgSize(DAG, Callee):0; + bool hasReturnsTwice = hasReturnsTwiceAttr(DAG, Callee, CLI.CS); + + // If the callee is a GlobalAddress node (quite common, every direct call is) + // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. + // Likewise ExternalSymbol -> TargetExternalSymbol. + if (GlobalAddressSDNode *G = dyn_cast(Callee)) + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32); + else if (ExternalSymbolSDNode *E = dyn_cast(Callee)) + Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32); + + // Returns a chain & a flag for retval copy to use + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + SmallVector Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + if (hasStructRetAttr) + Ops.push_back(DAG.getTargetConstant(SRetArgSize, MVT::i32)); + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) + Ops.push_back(DAG.getRegister(toCallerWindow(RegsToPass[i].first), + RegsToPass[i].second.getValueType())); + + // Add a register mask operand representing the call-preserved registers. + const WDC65816RegisterInfo *TRI = + ((const WDC65816TargetMachine&)getTargetMachine()).getRegisterInfo(); + const uint32_t *Mask = ((hasReturnsTwice) + ? TRI->getRTCallPreservedMask(CallConv) + : TRI->getCallPreservedMask(CallConv)); + assert(Mask && "Missing call preserved mask for calling convention"); + Ops.push_back(DAG.getRegisterMask(Mask)); + + if (InFlag.getNode()) + Ops.push_back(InFlag); + + Chain = DAG.getNode(SPISD::CALL, dl, NodeTys, &Ops[0], Ops.size()); + InFlag = Chain.getValue(1); + + Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(ArgsSize, true), + DAG.getIntPtrConstant(0, true), InFlag, dl); + InFlag = Chain.getValue(1); + + // Assign locations to each value returned by this call. + SmallVector RVLocs; + CCState RVInfo(CallConv, isVarArg, DAG.getMachineFunction(), + DAG.getTarget(), RVLocs, *DAG.getContext()); + + RVInfo.AnalyzeCallResult(Ins, RetCC_WDC6581632); + + // Copy all of the result registers out of their specified physreg. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + Chain = DAG.getCopyFromReg(Chain, dl, toCallerWindow(RVLocs[i].getLocReg()), + RVLocs[i].getValVT(), InFlag).getValue(1); + InFlag = Chain.getValue(2); + InVals.push_back(Chain.getValue(0)); + } + + return Chain; +} + +// This functions returns true if CalleeName is a ABI function that returns +// a long double (fp128). +static bool isFP128ABICall(const char *CalleeName) +{ + static const char *const ABICalls[] = + { "_Q_add", "_Q_sub", "_Q_mul", "_Q_div", + "_Q_sqrt", "_Q_neg", + "_Q_itoq", "_Q_stoq", "_Q_dtoq", "_Q_utoq", + "_Q_lltoq", "_Q_ulltoq", + 0 + }; + for (const char * const *I = ABICalls; *I != 0; ++I) + if (strcmp(CalleeName, *I) == 0) + return true; + return false; +} + +unsigned +WDC65816TargetLowering::getSRetArgSize(SelectionDAG &DAG, SDValue Callee) const +{ + const Function *CalleeFn = 0; + if (GlobalAddressSDNode *G = dyn_cast(Callee)) { + CalleeFn = dyn_cast(G->getGlobal()); + } else if (ExternalSymbolSDNode *E = + dyn_cast(Callee)) { + const Function *Fn = DAG.getMachineFunction().getFunction(); + const Module *M = Fn->getParent(); + const char *CalleeName = E->getSymbol(); + CalleeFn = M->getFunction(CalleeName); + if (!CalleeFn && isFP128ABICall(CalleeName)) + return 16; // Return sizeof(fp128) + } + + if (!CalleeFn) + return 0; + + assert(CalleeFn->hasStructRetAttr() && + "Callee does not have the StructRet attribute."); + + PointerType *Ty = cast(CalleeFn->arg_begin()->getType()); + Type *ElementTy = Ty->getElementType(); + return getDataLayout()->getTypeAllocSize(ElementTy); +} + + +// Fixup floating point arguments in the ... part of a varargs call. +// +// The WDC65816 v9 ABI requires that floating point arguments are treated the same +// as integers when calling a varargs function. This does not apply to the +// fixed arguments that are part of the function's prototype. +// +// This function post-processes a CCValAssign array created by +// AnalyzeCallOperands(). +static void fixupVariableFloatArgs(SmallVectorImpl &ArgLocs, + ArrayRef Outs) { + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + const CCValAssign &VA = ArgLocs[i]; + // FIXME: What about f32 arguments? C promotes them to f64 when calling + // varargs functions. + if (!VA.isRegLoc() || VA.getLocVT() != MVT::f64) + continue; + // The fixed arguments to a varargs function still go in FP registers. + if (Outs[VA.getValNo()].IsFixed) + continue; + + // This floating point argument should be reassigned. + CCValAssign NewVA; + + // Determine the offset into the argument array. + unsigned Offset = 8 * (VA.getLocReg() - SP::D0); + assert(Offset < 16*8 && "Offset out of range, bad register enum?"); + + if (Offset < 6*8) { + // This argument should go in %i0-%i5. + unsigned IReg = SP::I0 + Offset/8; + // Full register, just bitconvert into i64. + NewVA = CCValAssign::getReg(VA.getValNo(), VA.getValVT(), + IReg, MVT::i64, CCValAssign::BCvt); + } else { + // This needs to go to memory, we're out of integer registers. + NewVA = CCValAssign::getMem(VA.getValNo(), VA.getValVT(), + Offset, VA.getLocVT(), VA.getLocInfo()); + } + ArgLocs[i] = NewVA; + } +} + +// Lower a call for the 64-bit ABI. +SDValue +WDC65816TargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const { + SelectionDAG &DAG = CLI.DAG; + SDLoc DL = CLI.DL; + SDValue Chain = CLI.Chain; + + // WDC65816 target does not yet support tail call optimization. + CLI.IsTailCall = false; + + // Analyze operands of the call, assigning locations to each operand. + SmallVector ArgLocs; + CCState CCInfo(CLI.CallConv, CLI.IsVarArg, DAG.getMachineFunction(), + DAG.getTarget(), ArgLocs, *DAG.getContext()); + CCInfo.AnalyzeCallOperands(CLI.Outs, CC_WDC6581664); + + // Get the size of the outgoing arguments stack space requirement. + // The stack offset computed by CC_WDC6581664 includes all arguments. + // Called functions expect 6 argument words to exist in the stack frame, used + // or not. + unsigned ArgsSize = std::max(6*8u, CCInfo.getNextStackOffset()); + + // Keep stack frames 16-byte aligned. + ArgsSize = RoundUpToAlignment(ArgsSize, 16); + + // Varargs calls require special treatment. + if (CLI.IsVarArg) + fixupVariableFloatArgs(ArgLocs, CLI.Outs); + + // Adjust the stack pointer to make room for the arguments. + // FIXME: Use hasReservedCallFrame to avoid %sp adjustments around all calls + // with more than 6 arguments. + Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(ArgsSize, true), + DL); + + // Collect the set of registers to pass to the function and their values. + // This will be emitted as a sequence of CopyToReg nodes glued to the call + // instruction. + SmallVector, 8> RegsToPass; + + // Collect chains from all the memory opeations that copy arguments to the + // stack. They must follow the stack pointer adjustment above and precede the + // call instruction itself. + SmallVector MemOpChains; + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + const CCValAssign &VA = ArgLocs[i]; + SDValue Arg = CLI.OutVals[i]; + + // Promote the value if needed. + switch (VA.getLocInfo()) { + default: + llvm_unreachable("Unknown location info!"); + case CCValAssign::Full: + break; + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Arg); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Arg); + break; + case CCValAssign::AExt: + Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg); + break; + case CCValAssign::BCvt: + Arg = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Arg); + break; + } + + if (VA.isRegLoc()) { + // The custom bit on an i32 return value indicates that it should be + // passed in the high bits of the register. + if (VA.getValVT() == MVT::i32 && VA.needsCustom()) { + Arg = DAG.getNode(ISD::SHL, DL, MVT::i64, Arg, + DAG.getConstant(32, MVT::i32)); + + // The next value may go in the low bits of the same register. + // Handle both at once. + if (i+1 < ArgLocs.size() && ArgLocs[i+1].isRegLoc() && + ArgLocs[i+1].getLocReg() == VA.getLocReg()) { + SDValue NV = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, + CLI.OutVals[i+1]); + Arg = DAG.getNode(ISD::OR, DL, MVT::i64, Arg, NV); + // Skip the next value, it's already done. + ++i; + } + } + RegsToPass.push_back(std::make_pair(toCallerWindow(VA.getLocReg()), Arg)); + continue; + } + + assert(VA.isMemLoc()); + + // Create a store off the stack pointer for this argument. + SDValue StackPtr = DAG.getRegister(SP::O6, getPointerTy()); + // The argument area starts at %fp+BIAS+128 in the callee frame, + // %sp+BIAS+128 in ours. + SDValue PtrOff = DAG.getIntPtrConstant(VA.getLocMemOffset() + + Subtarget->getStackPointerBias() + + 128); + PtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr, PtrOff); + MemOpChains.push_back(DAG.getStore(Chain, DL, Arg, PtrOff, + MachinePointerInfo(), + false, false, 0)); + } + + // Emit all stores, make sure they occur before the call. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, + &MemOpChains[0], MemOpChains.size()); + + // Build a sequence of CopyToReg nodes glued together with token chain and + // glue operands which copy the outgoing args into registers. The InGlue is + // necessary since all emitted instructions must be stuck together in order + // to pass the live physical registers. + SDValue InGlue; + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { + Chain = DAG.getCopyToReg(Chain, DL, + RegsToPass[i].first, RegsToPass[i].second, InGlue); + InGlue = Chain.getValue(1); + } + + // If the callee is a GlobalAddress node (quite common, every direct call is) + // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. + // Likewise ExternalSymbol -> TargetExternalSymbol. + SDValue Callee = CLI.Callee; + bool hasReturnsTwice = hasReturnsTwiceAttr(DAG, Callee, CLI.CS); + if (GlobalAddressSDNode *G = dyn_cast(Callee)) + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, getPointerTy()); + else if (ExternalSymbolSDNode *E = dyn_cast(Callee)) + Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy()); + + // Build the operands for the call instruction itself. + SmallVector Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) + Ops.push_back(DAG.getRegister(RegsToPass[i].first, + RegsToPass[i].second.getValueType())); + + // Add a register mask operand representing the call-preserved registers. + const WDC65816RegisterInfo *TRI = + ((const WDC65816TargetMachine&)getTargetMachine()).getRegisterInfo(); + const uint32_t *Mask = ((hasReturnsTwice) + ? TRI->getRTCallPreservedMask(CLI.CallConv) + : TRI->getCallPreservedMask(CLI.CallConv)); + assert(Mask && "Missing call preserved mask for calling convention"); + Ops.push_back(DAG.getRegisterMask(Mask)); + + // Make sure the CopyToReg nodes are glued to the call instruction which + // consumes the registers. + if (InGlue.getNode()) + Ops.push_back(InGlue); + + // Now the call itself. + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + Chain = DAG.getNode(SPISD::CALL, DL, NodeTys, &Ops[0], Ops.size()); + InGlue = Chain.getValue(1); + + // Revert the stack pointer immediately after the call. + Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(ArgsSize, true), + DAG.getIntPtrConstant(0, true), InGlue, DL); + InGlue = Chain.getValue(1); + + // Now extract the return values. This is more or less the same as + // LowerFormalArguments_64. + + // Assign locations to each value returned by this call. + SmallVector RVLocs; + CCState RVInfo(CLI.CallConv, CLI.IsVarArg, DAG.getMachineFunction(), + DAG.getTarget(), RVLocs, *DAG.getContext()); + RVInfo.AnalyzeCallResult(CLI.Ins, CC_WDC6581664); + + // Copy all of the result registers out of their specified physreg. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + CCValAssign &VA = RVLocs[i]; + unsigned Reg = toCallerWindow(VA.getLocReg()); + + // When returning 'inreg {i32, i32 }', two consecutive i32 arguments can + // reside in the same register in the high and low bits. Reuse the + // CopyFromReg previous node to avoid duplicate copies. + SDValue RV; + if (RegisterSDNode *SrcReg = dyn_cast(Chain.getOperand(1))) + if (SrcReg->getReg() == Reg && Chain->getOpcode() == ISD::CopyFromReg) + RV = Chain.getValue(0); + + // But usually we'll create a new CopyFromReg for a different register. + if (!RV.getNode()) { + RV = DAG.getCopyFromReg(Chain, DL, Reg, RVLocs[i].getLocVT(), InGlue); + Chain = RV.getValue(1); + InGlue = Chain.getValue(2); + } + + // Get the high bits for i32 struct elements. + if (VA.getValVT() == MVT::i32 && VA.needsCustom()) + RV = DAG.getNode(ISD::SRL, DL, VA.getLocVT(), RV, + DAG.getConstant(32, MVT::i32)); + + // The callee promoted the return value, so insert an Assert?ext SDNode so + // we won't promote the value again in this function. + switch (VA.getLocInfo()) { + case CCValAssign::SExt: + RV = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), RV, + DAG.getValueType(VA.getValVT())); + break; + case CCValAssign::ZExt: + RV = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), RV, + DAG.getValueType(VA.getValVT())); + break; + default: + break; + } + + // Truncate the register down to the return value type. + if (VA.isExtInLoc()) + RV = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), RV); + + InVals.push_back(RV); + } + + return Chain; +} + +//===----------------------------------------------------------------------===// +// TargetLowering Implementation +//===----------------------------------------------------------------------===// + +/// IntCondCCodeToICC - Convert a DAG integer condition code to a WDC65816 ICC +/// condition. +static SPCC::CondCodes IntCondCCodeToICC(ISD::CondCode CC) { + switch (CC) { + default: llvm_unreachable("Unknown integer condition code!"); + case ISD::SETEQ: return SPCC::ICC_E; + case ISD::SETNE: return SPCC::ICC_NE; + case ISD::SETLT: return SPCC::ICC_L; + case ISD::SETGT: return SPCC::ICC_G; + case ISD::SETLE: return SPCC::ICC_LE; + case ISD::SETGE: return SPCC::ICC_GE; + case ISD::SETULT: return SPCC::ICC_CS; + case ISD::SETULE: return SPCC::ICC_LEU; + case ISD::SETUGT: return SPCC::ICC_GU; + case ISD::SETUGE: return SPCC::ICC_CC; + } +} + +/// FPCondCCodeToFCC - Convert a DAG floatingp oint condition code to a WDC65816 +/// FCC condition. +static SPCC::CondCodes FPCondCCodeToFCC(ISD::CondCode CC) { + switch (CC) { + default: llvm_unreachable("Unknown fp condition code!"); + case ISD::SETEQ: + case ISD::SETOEQ: return SPCC::FCC_E; + case ISD::SETNE: + case ISD::SETUNE: return SPCC::FCC_NE; + case ISD::SETLT: + case ISD::SETOLT: return SPCC::FCC_L; + case ISD::SETGT: + case ISD::SETOGT: return SPCC::FCC_G; + case ISD::SETLE: + case ISD::SETOLE: return SPCC::FCC_LE; + case ISD::SETGE: + case ISD::SETOGE: return SPCC::FCC_GE; + case ISD::SETULT: return SPCC::FCC_UL; + case ISD::SETULE: return SPCC::FCC_ULE; + case ISD::SETUGT: return SPCC::FCC_UG; + case ISD::SETUGE: return SPCC::FCC_UGE; + case ISD::SETUO: return SPCC::FCC_U; + case ISD::SETO: return SPCC::FCC_O; + case ISD::SETONE: return SPCC::FCC_LG; + case ISD::SETUEQ: return SPCC::FCC_UE; + } +} +#endif + +WDC65816TargetLowering::WDC65816TargetLowering(TargetMachine &TM) +: TargetLowering(TM, new TargetLoweringObjectFileELF()) { + +#if 0 // WDC_TODO - For sure we need something here... + // Set up the register classes. + addRegisterClass(MVT::i32, &SP::IntRegsRegClass); + addRegisterClass(MVT::f32, &SP::FPRegsRegClass); + addRegisterClass(MVT::f64, &SP::DFPRegsRegClass); + addRegisterClass(MVT::f128, &SP::QFPRegsRegClass); + if (Subtarget->is64Bit()) + addRegisterClass(MVT::i64, &SP::I64RegsRegClass); + + // Turn FP extload into load/fextend + setLoadExtAction(ISD::EXTLOAD, MVT::f32, Expand); + setLoadExtAction(ISD::EXTLOAD, MVT::f64, Expand); + + // WDC65816 doesn't have i1 sign extending load + setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote); + + // Turn FP truncstore into trunc + store. + setTruncStoreAction(MVT::f64, MVT::f32, Expand); + setTruncStoreAction(MVT::f128, MVT::f32, Expand); + setTruncStoreAction(MVT::f128, MVT::f64, Expand); + + // Custom legalize GlobalAddress nodes into LO/HI parts. + setOperationAction(ISD::GlobalAddress, getPointerTy(), Custom); + setOperationAction(ISD::GlobalTLSAddress, getPointerTy(), Custom); + setOperationAction(ISD::ConstantPool, getPointerTy(), Custom); + setOperationAction(ISD::BlockAddress, getPointerTy(), Custom); + + // WDC65816 doesn't have sext_inreg, replace them with shl/sra + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8 , Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand); + + // WDC65816 has no REM or DIVREM operations. + setOperationAction(ISD::UREM, MVT::i32, Expand); + setOperationAction(ISD::SREM, MVT::i32, Expand); + setOperationAction(ISD::SDIVREM, MVT::i32, Expand); + setOperationAction(ISD::UDIVREM, MVT::i32, Expand); + + // ... nor does WDC65816V9. + if (Subtarget->is64Bit()) { + setOperationAction(ISD::UREM, MVT::i64, Expand); + setOperationAction(ISD::SREM, MVT::i64, Expand); + setOperationAction(ISD::SDIVREM, MVT::i64, Expand); + setOperationAction(ISD::UDIVREM, MVT::i64, Expand); + } + + // Custom expand fp<->sint + setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); + setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom); + setOperationAction(ISD::FP_TO_SINT, MVT::i64, Custom); + setOperationAction(ISD::SINT_TO_FP, MVT::i64, Custom); + + // Custom Expand fp<->uint + setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); + setOperationAction(ISD::UINT_TO_FP, MVT::i32, Custom); + setOperationAction(ISD::FP_TO_UINT, MVT::i64, Custom); + setOperationAction(ISD::UINT_TO_FP, MVT::i64, Custom); + + setOperationAction(ISD::BITCAST, MVT::f32, Expand); + setOperationAction(ISD::BITCAST, MVT::i32, Expand); + + // WDC65816 has no select or setcc: expand to SELECT_CC. + setOperationAction(ISD::SELECT, MVT::i32, Expand); + setOperationAction(ISD::SELECT, MVT::f32, Expand); + setOperationAction(ISD::SELECT, MVT::f64, Expand); + setOperationAction(ISD::SELECT, MVT::f128, Expand); + + setOperationAction(ISD::SETCC, MVT::i32, Expand); + setOperationAction(ISD::SETCC, MVT::f32, Expand); + setOperationAction(ISD::SETCC, MVT::f64, Expand); + setOperationAction(ISD::SETCC, MVT::f128, Expand); + + // WDC65816 doesn't have BRCOND either, it has BR_CC. + setOperationAction(ISD::BRCOND, MVT::Other, Expand); + setOperationAction(ISD::BRIND, MVT::Other, Expand); + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + setOperationAction(ISD::BR_CC, MVT::i32, Custom); + setOperationAction(ISD::BR_CC, MVT::f32, Custom); + setOperationAction(ISD::BR_CC, MVT::f64, Custom); + setOperationAction(ISD::BR_CC, MVT::f128, Custom); + + setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f64, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f128, Custom); + + if (Subtarget->is64Bit()) { + setOperationAction(ISD::ADDC, MVT::i64, Custom); + setOperationAction(ISD::ADDE, MVT::i64, Custom); + setOperationAction(ISD::SUBC, MVT::i64, Custom); + setOperationAction(ISD::SUBE, MVT::i64, Custom); + setOperationAction(ISD::BITCAST, MVT::f64, Expand); + setOperationAction(ISD::BITCAST, MVT::i64, Expand); + setOperationAction(ISD::SELECT, MVT::i64, Expand); + setOperationAction(ISD::SETCC, MVT::i64, Expand); + setOperationAction(ISD::BR_CC, MVT::i64, Custom); + setOperationAction(ISD::SELECT_CC, MVT::i64, Custom); + + setOperationAction(ISD::CTPOP, MVT::i64, Legal); + setOperationAction(ISD::CTTZ , MVT::i64, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Expand); + setOperationAction(ISD::CTLZ , MVT::i64, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i64, Expand); + setOperationAction(ISD::BSWAP, MVT::i64, Expand); + setOperationAction(ISD::ROTL , MVT::i64, Expand); + setOperationAction(ISD::ROTR , MVT::i64, Expand); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom); + } + + // FIXME: There are instructions available for ATOMIC_FENCE + // on WDC65816V8 and later. + setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand); + + if (!Subtarget->isV9()) { + // WDC65816V8 does not have FNEGD and FABSD. + setOperationAction(ISD::FNEG, MVT::f64, Custom); + setOperationAction(ISD::FABS, MVT::f64, Custom); + } + + setOperationAction(ISD::FSIN , MVT::f128, Expand); + setOperationAction(ISD::FCOS , MVT::f128, Expand); + setOperationAction(ISD::FSINCOS, MVT::f128, Expand); + setOperationAction(ISD::FREM , MVT::f128, Expand); + setOperationAction(ISD::FMA , MVT::f128, Expand); + setOperationAction(ISD::FSIN , MVT::f64, Expand); + setOperationAction(ISD::FCOS , MVT::f64, Expand); + setOperationAction(ISD::FSINCOS, MVT::f64, Expand); + setOperationAction(ISD::FREM , MVT::f64, Expand); + setOperationAction(ISD::FMA , MVT::f64, Expand); + setOperationAction(ISD::FSIN , MVT::f32, Expand); + setOperationAction(ISD::FCOS , MVT::f32, Expand); + setOperationAction(ISD::FSINCOS, MVT::f32, Expand); + setOperationAction(ISD::FREM , MVT::f32, Expand); + setOperationAction(ISD::FMA , MVT::f32, Expand); + setOperationAction(ISD::CTPOP, MVT::i32, Expand); + setOperationAction(ISD::CTTZ , MVT::i32, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand); + setOperationAction(ISD::CTLZ , MVT::i32, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Expand); + setOperationAction(ISD::ROTL , MVT::i32, Expand); + setOperationAction(ISD::ROTR , MVT::i32, Expand); + setOperationAction(ISD::BSWAP, MVT::i32, Expand); + setOperationAction(ISD::FCOPYSIGN, MVT::f128, Expand); + setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand); + setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand); + setOperationAction(ISD::FPOW , MVT::f128, Expand); + setOperationAction(ISD::FPOW , MVT::f64, Expand); + setOperationAction(ISD::FPOW , MVT::f32, Expand); + + setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand); + + // FIXME: WDC65816 provides these multiplies, but we don't have them yet. + setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); + + if (Subtarget->is64Bit()) { + setOperationAction(ISD::UMUL_LOHI, MVT::i64, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand); + setOperationAction(ISD::MULHU, MVT::i64, Expand); + setOperationAction(ISD::MULHS, MVT::i64, Expand); + } + + // VASTART needs to be custom lowered to use the VarArgsFrameIndex. + setOperationAction(ISD::VASTART , MVT::Other, Custom); + // VAARG needs to be lowered to not do unaligned accesses for doubles. + setOperationAction(ISD::VAARG , MVT::Other, Custom); + + // Use the default implementation. + setOperationAction(ISD::VACOPY , MVT::Other, Expand); + setOperationAction(ISD::VAEND , MVT::Other, Expand); + setOperationAction(ISD::STACKSAVE , MVT::Other, Expand); + setOperationAction(ISD::STACKRESTORE , MVT::Other, Expand); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32 , Custom); + + setExceptionPointerRegister(SP::I0); + setExceptionSelectorRegister(SP::I1); + + setStackPointerRegisterToSaveRestore(SP::O6); + + if (Subtarget->isV9()) + setOperationAction(ISD::CTPOP, MVT::i32, Legal); + + if (Subtarget->isV9() && Subtarget->hasHardQuad()) { + setOperationAction(ISD::LOAD, MVT::f128, Legal); + setOperationAction(ISD::STORE, MVT::f128, Legal); + } else { + setOperationAction(ISD::LOAD, MVT::f128, Custom); + setOperationAction(ISD::STORE, MVT::f128, Custom); + } + + if (Subtarget->hasHardQuad()) { + setOperationAction(ISD::FADD, MVT::f128, Legal); + setOperationAction(ISD::FSUB, MVT::f128, Legal); + setOperationAction(ISD::FMUL, MVT::f128, Legal); + setOperationAction(ISD::FDIV, MVT::f128, Legal); + setOperationAction(ISD::FSQRT, MVT::f128, Legal); + setOperationAction(ISD::FP_EXTEND, MVT::f128, Legal); + setOperationAction(ISD::FP_ROUND, MVT::f64, Legal); + if (Subtarget->isV9()) { + setOperationAction(ISD::FNEG, MVT::f128, Legal); + setOperationAction(ISD::FABS, MVT::f128, Legal); + } else { + setOperationAction(ISD::FNEG, MVT::f128, Custom); + setOperationAction(ISD::FABS, MVT::f128, Custom); + } + + if (!Subtarget->is64Bit()) { + setLibcallName(RTLIB::FPTOSINT_F128_I64, "_Q_qtoll"); + setLibcallName(RTLIB::FPTOUINT_F128_I64, "_Q_qtoull"); + setLibcallName(RTLIB::SINTTOFP_I64_F128, "_Q_lltoq"); + setLibcallName(RTLIB::UINTTOFP_I64_F128, "_Q_ulltoq"); + } + + } else { + // Custom legalize f128 operations. + + setOperationAction(ISD::FADD, MVT::f128, Custom); + setOperationAction(ISD::FSUB, MVT::f128, Custom); + setOperationAction(ISD::FMUL, MVT::f128, Custom); + setOperationAction(ISD::FDIV, MVT::f128, Custom); + setOperationAction(ISD::FSQRT, MVT::f128, Custom); + setOperationAction(ISD::FNEG, MVT::f128, Custom); + setOperationAction(ISD::FABS, MVT::f128, Custom); + + setOperationAction(ISD::FP_EXTEND, MVT::f128, Custom); + setOperationAction(ISD::FP_ROUND, MVT::f64, Custom); + setOperationAction(ISD::FP_ROUND, MVT::f32, Custom); + + // Setup Runtime library names. + if (Subtarget->is64Bit()) { + setLibcallName(RTLIB::ADD_F128, "_Qp_add"); + setLibcallName(RTLIB::SUB_F128, "_Qp_sub"); + setLibcallName(RTLIB::MUL_F128, "_Qp_mul"); + setLibcallName(RTLIB::DIV_F128, "_Qp_div"); + setLibcallName(RTLIB::SQRT_F128, "_Qp_sqrt"); + setLibcallName(RTLIB::FPTOSINT_F128_I32, "_Qp_qtoi"); + setLibcallName(RTLIB::FPTOUINT_F128_I32, "_Qp_qtoui"); + setLibcallName(RTLIB::SINTTOFP_I32_F128, "_Qp_itoq"); + setLibcallName(RTLIB::UINTTOFP_I32_F128, "_Qp_uitoq"); + setLibcallName(RTLIB::FPTOSINT_F128_I64, "_Qp_qtox"); + setLibcallName(RTLIB::FPTOUINT_F128_I64, "_Qp_qtoux"); + setLibcallName(RTLIB::SINTTOFP_I64_F128, "_Qp_xtoq"); + setLibcallName(RTLIB::UINTTOFP_I64_F128, "_Qp_uxtoq"); + setLibcallName(RTLIB::FPEXT_F32_F128, "_Qp_stoq"); + setLibcallName(RTLIB::FPEXT_F64_F128, "_Qp_dtoq"); + setLibcallName(RTLIB::FPROUND_F128_F32, "_Qp_qtos"); + setLibcallName(RTLIB::FPROUND_F128_F64, "_Qp_qtod"); + } else { + setLibcallName(RTLIB::ADD_F128, "_Q_add"); + setLibcallName(RTLIB::SUB_F128, "_Q_sub"); + setLibcallName(RTLIB::MUL_F128, "_Q_mul"); + setLibcallName(RTLIB::DIV_F128, "_Q_div"); + setLibcallName(RTLIB::SQRT_F128, "_Q_sqrt"); + setLibcallName(RTLIB::FPTOSINT_F128_I32, "_Q_qtoi"); + setLibcallName(RTLIB::FPTOUINT_F128_I32, "_Q_qtou"); + setLibcallName(RTLIB::SINTTOFP_I32_F128, "_Q_itoq"); + setLibcallName(RTLIB::UINTTOFP_I32_F128, "_Q_utoq"); + setLibcallName(RTLIB::FPTOSINT_F128_I64, "_Q_qtoll"); + setLibcallName(RTLIB::FPTOUINT_F128_I64, "_Q_qtoull"); + setLibcallName(RTLIB::SINTTOFP_I64_F128, "_Q_lltoq"); + setLibcallName(RTLIB::UINTTOFP_I64_F128, "_Q_ulltoq"); + setLibcallName(RTLIB::FPEXT_F32_F128, "_Q_stoq"); + setLibcallName(RTLIB::FPEXT_F64_F128, "_Q_dtoq"); + setLibcallName(RTLIB::FPROUND_F128_F32, "_Q_qtos"); + setLibcallName(RTLIB::FPROUND_F128_F64, "_Q_qtod"); + } + } + + setMinFunctionAlignment(2); + + computeRegisterProperties(); +#endif +} + +#if 0 // WDC_TODO - Disable this stuff for now... +const char *WDC65816TargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + default: return 0; + case SPISD::CMPICC: return "SPISD::CMPICC"; + case SPISD::CMPFCC: return "SPISD::CMPFCC"; + case SPISD::BRICC: return "SPISD::BRICC"; + case SPISD::BRXCC: return "SPISD::BRXCC"; + case SPISD::BRFCC: return "SPISD::BRFCC"; + case SPISD::SELECT_ICC: return "SPISD::SELECT_ICC"; + case SPISD::SELECT_XCC: return "SPISD::SELECT_XCC"; + case SPISD::SELECT_FCC: return "SPISD::SELECT_FCC"; + case SPISD::Hi: return "SPISD::Hi"; + case SPISD::Lo: return "SPISD::Lo"; + case SPISD::FTOI: return "SPISD::FTOI"; + case SPISD::ITOF: return "SPISD::ITOF"; + case SPISD::FTOX: return "SPISD::FTOX"; + case SPISD::XTOF: return "SPISD::XTOF"; + case SPISD::CALL: return "SPISD::CALL"; + case SPISD::RET_FLAG: return "SPISD::RET_FLAG"; + case SPISD::GLOBAL_BASE_REG: return "SPISD::GLOBAL_BASE_REG"; + case SPISD::FLUSHW: return "SPISD::FLUSHW"; + case SPISD::TLS_ADD: return "SPISD::TLS_ADD"; + case SPISD::TLS_LD: return "SPISD::TLS_LD"; + case SPISD::TLS_CALL: return "SPISD::TLS_CALL"; + } +} + +EVT WDC65816TargetLowering::getSetCCResultType(LLVMContext &, EVT VT) const { + if (!VT.isVector()) + return MVT::i32; + return VT.changeVectorElementTypeToInteger(); +} + +/// isMaskedValueZeroForTargetNode - Return true if 'Op & Mask' is known to +/// be zero. Op is expected to be a target specific node. Used by DAG +/// combiner. +void WDC65816TargetLowering::computeMaskedBitsForTargetNode +(const SDValue Op, + APInt &KnownZero, + APInt &KnownOne, + const SelectionDAG &DAG, + unsigned Depth) const { + APInt KnownZero2, KnownOne2; + KnownZero = KnownOne = APInt(KnownZero.getBitWidth(), 0); + + switch (Op.getOpcode()) { + default: break; + case SPISD::SELECT_ICC: + case SPISD::SELECT_XCC: + case SPISD::SELECT_FCC: + DAG.ComputeMaskedBits(Op.getOperand(1), KnownZero, KnownOne, Depth+1); + DAG.ComputeMaskedBits(Op.getOperand(0), KnownZero2, KnownOne2, Depth+1); + assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); + assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?"); + + // Only known if known in both the LHS and RHS. + KnownOne &= KnownOne2; + KnownZero &= KnownZero2; + break; + } +} + +// Look at LHS/RHS/CC and see if they are a lowered setcc instruction. If so +// set LHS/RHS and SPCC to the LHS/RHS of the setcc and SPCC to the condition. +static void LookThroughSetCC(SDValue &LHS, SDValue &RHS, + ISD::CondCode CC, unsigned &SPCC) { + if (isa(RHS) && + cast(RHS)->isNullValue() && + CC == ISD::SETNE && + (((LHS.getOpcode() == SPISD::SELECT_ICC || + LHS.getOpcode() == SPISD::SELECT_XCC) && + LHS.getOperand(3).getOpcode() == SPISD::CMPICC) || + (LHS.getOpcode() == SPISD::SELECT_FCC && + LHS.getOperand(3).getOpcode() == SPISD::CMPFCC)) && + isa(LHS.getOperand(0)) && + isa(LHS.getOperand(1)) && + cast(LHS.getOperand(0))->isOne() && + cast(LHS.getOperand(1))->isNullValue()) { + SDValue CMPCC = LHS.getOperand(3); + SPCC = cast(LHS.getOperand(2))->getZExtValue(); + LHS = CMPCC.getOperand(0); + RHS = CMPCC.getOperand(1); + } +} + +// Convert to a target node and set target flags. +SDValue WDC65816TargetLowering::withTargetFlags(SDValue Op, unsigned TF, + SelectionDAG &DAG) const { + if (const GlobalAddressSDNode *GA = dyn_cast(Op)) + return DAG.getTargetGlobalAddress(GA->getGlobal(), + SDLoc(GA), + GA->getValueType(0), + GA->getOffset(), TF); + + if (const ConstantPoolSDNode *CP = dyn_cast(Op)) + return DAG.getTargetConstantPool(CP->getConstVal(), + CP->getValueType(0), + CP->getAlignment(), + CP->getOffset(), TF); + + if (const BlockAddressSDNode *BA = dyn_cast(Op)) + return DAG.getTargetBlockAddress(BA->getBlockAddress(), + Op.getValueType(), + 0, + TF); + + if (const ExternalSymbolSDNode *ES = dyn_cast(Op)) + return DAG.getTargetExternalSymbol(ES->getSymbol(), + ES->getValueType(0), TF); + + llvm_unreachable("Unhandled address SDNode"); +} + +// Split Op into high and low parts according to HiTF and LoTF. +// Return an ADD node combining the parts. +SDValue WDC65816TargetLowering::makeHiLoPair(SDValue Op, + unsigned HiTF, unsigned LoTF, + SelectionDAG &DAG) const { + SDLoc DL(Op); + EVT VT = Op.getValueType(); + SDValue Hi = DAG.getNode(SPISD::Hi, DL, VT, withTargetFlags(Op, HiTF, DAG)); + SDValue Lo = DAG.getNode(SPISD::Lo, DL, VT, withTargetFlags(Op, LoTF, DAG)); + return DAG.getNode(ISD::ADD, DL, VT, Hi, Lo); +} + +// Build SDNodes for producing an address from a GlobalAddress, ConstantPool, +// or ExternalSymbol SDNode. +SDValue WDC65816TargetLowering::makeAddress(SDValue Op, SelectionDAG &DAG) const { + SDLoc DL(Op); + EVT VT = getPointerTy(); + + // Handle PIC mode first. + if (getTargetMachine().getRelocationModel() == Reloc::PIC_) { + // This is the pic32 code model, the GOT is known to be smaller than 4GB. + SDValue HiLo = makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG); + SDValue GlobalBase = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, VT); + SDValue AbsAddr = DAG.getNode(ISD::ADD, DL, VT, GlobalBase, HiLo); + // GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this + // function has calls. + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + MFI->setHasCalls(true); + return DAG.getLoad(VT, DL, DAG.getEntryNode(), AbsAddr, + MachinePointerInfo::getGOT(), false, false, false, 0); + } + + // This is one of the absolute code models. + switch(getTargetMachine().getCodeModel()) { + default: + llvm_unreachable("Unsupported absolute code model"); + case CodeModel::JITDefault: + case CodeModel::Small: + // abs32. + return makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG); + case CodeModel::Medium: { + // abs44. + SDValue H44 = makeHiLoPair(Op, SPII::MO_H44, SPII::MO_M44, DAG); + H44 = DAG.getNode(ISD::SHL, DL, VT, H44, DAG.getConstant(12, MVT::i32)); + SDValue L44 = withTargetFlags(Op, SPII::MO_L44, DAG); + L44 = DAG.getNode(SPISD::Lo, DL, VT, L44); + return DAG.getNode(ISD::ADD, DL, VT, H44, L44); + } + case CodeModel::Large: { + // abs64. + SDValue Hi = makeHiLoPair(Op, SPII::MO_HH, SPII::MO_HM, DAG); + Hi = DAG.getNode(ISD::SHL, DL, VT, Hi, DAG.getConstant(32, MVT::i32)); + SDValue Lo = makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG); + return DAG.getNode(ISD::ADD, DL, VT, Hi, Lo); + } + } +} + +SDValue WDC65816TargetLowering::LowerGlobalAddress(SDValue Op, + SelectionDAG &DAG) const { + return makeAddress(Op, DAG); +} + +SDValue WDC65816TargetLowering::LowerConstantPool(SDValue Op, + SelectionDAG &DAG) const { + return makeAddress(Op, DAG); +} + +SDValue WDC65816TargetLowering::LowerBlockAddress(SDValue Op, + SelectionDAG &DAG) const { + return makeAddress(Op, DAG); +} + +SDValue WDC65816TargetLowering::LowerGlobalTLSAddress(SDValue Op, + SelectionDAG &DAG) const { + + GlobalAddressSDNode *GA = cast(Op); + SDLoc DL(GA); + const GlobalValue *GV = GA->getGlobal(); + EVT PtrVT = getPointerTy(); + + TLSModel::Model model = getTargetMachine().getTLSModel(GV); + + if (model == TLSModel::GeneralDynamic || model == TLSModel::LocalDynamic) { + unsigned HiTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_HI22 + : SPII::MO_TLS_LDM_HI22); + unsigned LoTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_LO10 + : SPII::MO_TLS_LDM_LO10); + unsigned addTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_ADD + : SPII::MO_TLS_LDM_ADD); + unsigned callTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_CALL + : SPII::MO_TLS_LDM_CALL); + + SDValue HiLo = makeHiLoPair(Op, HiTF, LoTF, DAG); + SDValue Base = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, PtrVT); + SDValue Argument = DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, Base, HiLo, + withTargetFlags(Op, addTF, DAG)); + + SDValue Chain = DAG.getEntryNode(); + SDValue InFlag; + + Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(1, true), DL); + Chain = DAG.getCopyToReg(Chain, DL, SP::O0, Argument, InFlag); + InFlag = Chain.getValue(1); + SDValue Callee = DAG.getTargetExternalSymbol("__tls_get_addr", PtrVT); + SDValue Symbol = withTargetFlags(Op, callTF, DAG); + + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + SmallVector Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + Ops.push_back(Symbol); + Ops.push_back(DAG.getRegister(SP::O0, PtrVT)); + const uint32_t *Mask = getTargetMachine() + .getRegisterInfo()->getCallPreservedMask(CallingConv::C); + assert(Mask && "Missing call preserved mask for calling convention"); + Ops.push_back(DAG.getRegisterMask(Mask)); + Ops.push_back(InFlag); + Chain = DAG.getNode(SPISD::TLS_CALL, DL, NodeTys, &Ops[0], Ops.size()); + InFlag = Chain.getValue(1); + Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(1, true), + DAG.getIntPtrConstant(0, true), InFlag, DL); + InFlag = Chain.getValue(1); + SDValue Ret = DAG.getCopyFromReg(Chain, DL, SP::O0, PtrVT, InFlag); + + if (model != TLSModel::LocalDynamic) + return Ret; + + SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT, + withTargetFlags(Op, SPII::MO_TLS_LDO_HIX22, DAG)); + SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT, + withTargetFlags(Op, SPII::MO_TLS_LDO_LOX10, DAG)); + HiLo = DAG.getNode(ISD::XOR, DL, PtrVT, Hi, Lo); + return DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, Ret, HiLo, + withTargetFlags(Op, SPII::MO_TLS_LDO_ADD, DAG)); + } + + if (model == TLSModel::InitialExec) { + unsigned ldTF = ((PtrVT == MVT::i64)? SPII::MO_TLS_IE_LDX + : SPII::MO_TLS_IE_LD); + + SDValue Base = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, PtrVT); + + // GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this + // function has calls. + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + MFI->setHasCalls(true); + + SDValue TGA = makeHiLoPair(Op, + SPII::MO_TLS_IE_HI22, SPII::MO_TLS_IE_LO10, DAG); + SDValue Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, Base, TGA); + SDValue Offset = DAG.getNode(SPISD::TLS_LD, + DL, PtrVT, Ptr, + withTargetFlags(Op, ldTF, DAG)); + return DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, + DAG.getRegister(SP::G7, PtrVT), Offset, + withTargetFlags(Op, SPII::MO_TLS_IE_ADD, DAG)); + } + + assert(model == TLSModel::LocalExec); + SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT, + withTargetFlags(Op, SPII::MO_TLS_LE_HIX22, DAG)); + SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT, + withTargetFlags(Op, SPII::MO_TLS_LE_LOX10, DAG)); + SDValue Offset = DAG.getNode(ISD::XOR, DL, PtrVT, Hi, Lo); + + return DAG.getNode(ISD::ADD, DL, PtrVT, + DAG.getRegister(SP::G7, PtrVT), Offset); +} + +SDValue +WDC65816TargetLowering::LowerF128_LibCallArg(SDValue Chain, ArgListTy &Args, + SDValue Arg, SDLoc DL, + SelectionDAG &DAG) const { + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + EVT ArgVT = Arg.getValueType(); + Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext()); + + ArgListEntry Entry; + Entry.Node = Arg; + Entry.Ty = ArgTy; + + if (ArgTy->isFP128Ty()) { + // Create a stack object and pass the pointer to the library function. + int FI = MFI->CreateStackObject(16, 8, false); + SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy()); + Chain = DAG.getStore(Chain, + DL, + Entry.Node, + FIPtr, + MachinePointerInfo(), + false, + false, + 8); + + Entry.Node = FIPtr; + Entry.Ty = PointerType::getUnqual(ArgTy); + } + Args.push_back(Entry); + return Chain; +} + +SDValue +WDC65816TargetLowering::LowerF128Op(SDValue Op, SelectionDAG &DAG, + const char *LibFuncName, + unsigned numArgs) const { + + ArgListTy Args; + + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + + SDValue Callee = DAG.getExternalSymbol(LibFuncName, getPointerTy()); + Type *RetTy = Op.getValueType().getTypeForEVT(*DAG.getContext()); + Type *RetTyABI = RetTy; + SDValue Chain = DAG.getEntryNode(); + SDValue RetPtr; + + if (RetTy->isFP128Ty()) { + // Create a Stack Object to receive the return value of type f128. + ArgListEntry Entry; + int RetFI = MFI->CreateStackObject(16, 8, false); + RetPtr = DAG.getFrameIndex(RetFI, getPointerTy()); + Entry.Node = RetPtr; + Entry.Ty = PointerType::getUnqual(RetTy); + if (!Subtarget->is64Bit()) + Entry.isSRet = true; + Entry.isReturned = false; + Args.push_back(Entry); + RetTyABI = Type::getVoidTy(*DAG.getContext()); + } + + assert(Op->getNumOperands() >= numArgs && "Not enough operands!"); + for (unsigned i = 0, e = numArgs; i != e; ++i) { + Chain = LowerF128_LibCallArg(Chain, Args, Op.getOperand(i), SDLoc(Op), DAG); + } + TargetLowering:: + CallLoweringInfo CLI(Chain, + RetTyABI, + false, false, false, false, + 0, CallingConv::C, + false, false, true, + Callee, Args, DAG, SDLoc(Op)); + std::pair CallInfo = LowerCallTo(CLI); + + // chain is in second result. + if (RetTyABI == RetTy) + return CallInfo.first; + + assert (RetTy->isFP128Ty() && "Unexpected return type!"); + + Chain = CallInfo.second; + + // Load RetPtr to get the return value. + return DAG.getLoad(Op.getValueType(), + SDLoc(Op), + Chain, + RetPtr, + MachinePointerInfo(), + false, false, false, 8); +} + +SDValue +WDC65816TargetLowering::LowerF128Compare(SDValue LHS, SDValue RHS, + unsigned &SPCC, + SDLoc DL, + SelectionDAG &DAG) const { + + const char *LibCall = 0; + bool is64Bit = Subtarget->is64Bit(); + switch(SPCC) { + default: llvm_unreachable("Unhandled conditional code!"); + case SPCC::FCC_E : LibCall = is64Bit? "_Qp_feq" : "_Q_feq"; break; + case SPCC::FCC_NE : LibCall = is64Bit? "_Qp_fne" : "_Q_fne"; break; + case SPCC::FCC_L : LibCall = is64Bit? "_Qp_flt" : "_Q_flt"; break; + case SPCC::FCC_G : LibCall = is64Bit? "_Qp_fgt" : "_Q_fgt"; break; + case SPCC::FCC_LE : LibCall = is64Bit? "_Qp_fle" : "_Q_fle"; break; + case SPCC::FCC_GE : LibCall = is64Bit? "_Qp_fge" : "_Q_fge"; break; + case SPCC::FCC_UL : + case SPCC::FCC_ULE: + case SPCC::FCC_UG : + case SPCC::FCC_UGE: + case SPCC::FCC_U : + case SPCC::FCC_O : + case SPCC::FCC_LG : + case SPCC::FCC_UE : LibCall = is64Bit? "_Qp_cmp" : "_Q_cmp"; break; + } + + SDValue Callee = DAG.getExternalSymbol(LibCall, getPointerTy()); + Type *RetTy = Type::getInt32Ty(*DAG.getContext()); + ArgListTy Args; + SDValue Chain = DAG.getEntryNode(); + Chain = LowerF128_LibCallArg(Chain, Args, LHS, DL, DAG); + Chain = LowerF128_LibCallArg(Chain, Args, RHS, DL, DAG); + + TargetLowering:: + CallLoweringInfo CLI(Chain, + RetTy, + false, false, false, false, + 0, CallingConv::C, + false, false, true, + Callee, Args, DAG, DL); + + std::pair CallInfo = LowerCallTo(CLI); + + // result is in first, and chain is in second result. + SDValue Result = CallInfo.first; + + switch(SPCC) { + default: { + SDValue RHS = DAG.getTargetConstant(0, Result.getValueType()); + SPCC = SPCC::ICC_NE; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + case SPCC::FCC_UL : { + SDValue Mask = DAG.getTargetConstant(1, Result.getValueType()); + Result = DAG.getNode(ISD::AND, DL, Result.getValueType(), Result, Mask); + SDValue RHS = DAG.getTargetConstant(0, Result.getValueType()); + SPCC = SPCC::ICC_NE; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + case SPCC::FCC_ULE: { + SDValue RHS = DAG.getTargetConstant(2, Result.getValueType()); + SPCC = SPCC::ICC_NE; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + case SPCC::FCC_UG : { + SDValue RHS = DAG.getTargetConstant(1, Result.getValueType()); + SPCC = SPCC::ICC_G; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + case SPCC::FCC_UGE: { + SDValue RHS = DAG.getTargetConstant(1, Result.getValueType()); + SPCC = SPCC::ICC_NE; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + + case SPCC::FCC_U : { + SDValue RHS = DAG.getTargetConstant(3, Result.getValueType()); + SPCC = SPCC::ICC_E; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + case SPCC::FCC_O : { + SDValue RHS = DAG.getTargetConstant(3, Result.getValueType()); + SPCC = SPCC::ICC_NE; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + case SPCC::FCC_LG : { + SDValue Mask = DAG.getTargetConstant(3, Result.getValueType()); + Result = DAG.getNode(ISD::AND, DL, Result.getValueType(), Result, Mask); + SDValue RHS = DAG.getTargetConstant(0, Result.getValueType()); + SPCC = SPCC::ICC_NE; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + case SPCC::FCC_UE : { + SDValue Mask = DAG.getTargetConstant(3, Result.getValueType()); + Result = DAG.getNode(ISD::AND, DL, Result.getValueType(), Result, Mask); + SDValue RHS = DAG.getTargetConstant(0, Result.getValueType()); + SPCC = SPCC::ICC_E; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + } +} + +static SDValue +LowerF128_FPEXTEND(SDValue Op, SelectionDAG &DAG, + const WDC65816TargetLowering &TLI) { + + if (Op.getOperand(0).getValueType() == MVT::f64) + return TLI.LowerF128Op(Op, DAG, + TLI.getLibcallName(RTLIB::FPEXT_F64_F128), 1); + + if (Op.getOperand(0).getValueType() == MVT::f32) + return TLI.LowerF128Op(Op, DAG, + TLI.getLibcallName(RTLIB::FPEXT_F32_F128), 1); + + llvm_unreachable("fpextend with non-float operand!"); + return SDValue(0, 0); +} + +static SDValue +LowerF128_FPROUND(SDValue Op, SelectionDAG &DAG, + const WDC65816TargetLowering &TLI) { + // FP_ROUND on f64 and f32 are legal. + if (Op.getOperand(0).getValueType() != MVT::f128) + return Op; + + if (Op.getValueType() == MVT::f64) + return TLI.LowerF128Op(Op, DAG, + TLI.getLibcallName(RTLIB::FPROUND_F128_F64), 1); + if (Op.getValueType() == MVT::f32) + return TLI.LowerF128Op(Op, DAG, + TLI.getLibcallName(RTLIB::FPROUND_F128_F32), 1); + + llvm_unreachable("fpround to non-float!"); + return SDValue(0, 0); +} + +static SDValue LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG, + const WDC65816TargetLowering &TLI, + bool hasHardQuad) { + SDLoc dl(Op); + EVT VT = Op.getValueType(); + assert(VT == MVT::i32 || VT == MVT::i64); + + // Expand f128 operations to fp128 abi calls. + if (Op.getOperand(0).getValueType() == MVT::f128 + && (!hasHardQuad || !TLI.isTypeLegal(VT))) { + const char *libName = TLI.getLibcallName(VT == MVT::i32 + ? RTLIB::FPTOSINT_F128_I32 + : RTLIB::FPTOSINT_F128_I64); + return TLI.LowerF128Op(Op, DAG, libName, 1); + } + + // Expand if the resulting type is illegal. + if (!TLI.isTypeLegal(VT)) + return SDValue(0, 0); + + // Otherwise, Convert the fp value to integer in an FP register. + if (VT == MVT::i32) + Op = DAG.getNode(SPISD::FTOI, dl, MVT::f32, Op.getOperand(0)); + else + Op = DAG.getNode(SPISD::FTOX, dl, MVT::f64, Op.getOperand(0)); + + return DAG.getNode(ISD::BITCAST, dl, VT, Op); +} + +static SDValue LowerSINT_TO_FP(SDValue Op, SelectionDAG &DAG, + const WDC65816TargetLowering &TLI, + bool hasHardQuad) { + SDLoc dl(Op); + EVT OpVT = Op.getOperand(0).getValueType(); + assert(OpVT == MVT::i32 || (OpVT == MVT::i64)); + + EVT floatVT = (OpVT == MVT::i32) ? MVT::f32 : MVT::f64; + + // Expand f128 operations to fp128 ABI calls. + if (Op.getValueType() == MVT::f128 + && (!hasHardQuad || !TLI.isTypeLegal(OpVT))) { + const char *libName = TLI.getLibcallName(OpVT == MVT::i32 + ? RTLIB::SINTTOFP_I32_F128 + : RTLIB::SINTTOFP_I64_F128); + return TLI.LowerF128Op(Op, DAG, libName, 1); + } + + // Expand if the operand type is illegal. + if (!TLI.isTypeLegal(OpVT)) + return SDValue(0, 0); + + // Otherwise, Convert the int value to FP in an FP register. + SDValue Tmp = DAG.getNode(ISD::BITCAST, dl, floatVT, Op.getOperand(0)); + unsigned opcode = (OpVT == MVT::i32)? SPISD::ITOF : SPISD::XTOF; + return DAG.getNode(opcode, dl, Op.getValueType(), Tmp); +} + +static SDValue LowerFP_TO_UINT(SDValue Op, SelectionDAG &DAG, + const WDC65816TargetLowering &TLI, + bool hasHardQuad) { + SDLoc dl(Op); + EVT VT = Op.getValueType(); + + // Expand if it does not involve f128 or the target has support for + // quad floating point instructions and the resulting type is legal. + if (Op.getOperand(0).getValueType() != MVT::f128 || + (hasHardQuad && TLI.isTypeLegal(VT))) + return SDValue(0, 0); + + assert(VT == MVT::i32 || VT == MVT::i64); + + return TLI.LowerF128Op(Op, DAG, + TLI.getLibcallName(VT == MVT::i32 + ? RTLIB::FPTOUINT_F128_I32 + : RTLIB::FPTOUINT_F128_I64), + 1); +} + +static SDValue LowerUINT_TO_FP(SDValue Op, SelectionDAG &DAG, + const WDC65816TargetLowering &TLI, + bool hasHardQuad) { + SDLoc dl(Op); + EVT OpVT = Op.getOperand(0).getValueType(); + assert(OpVT == MVT::i32 || OpVT == MVT::i64); + + // Expand if it does not involve f128 or the target has support for + // quad floating point instructions and the operand type is legal. + if (Op.getValueType() != MVT::f128 || (hasHardQuad && TLI.isTypeLegal(OpVT))) + return SDValue(0, 0); + + return TLI.LowerF128Op(Op, DAG, + TLI.getLibcallName(OpVT == MVT::i32 + ? RTLIB::UINTTOFP_I32_F128 + : RTLIB::UINTTOFP_I64_F128), + 1); +} + +static SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG, + const WDC65816TargetLowering &TLI, + bool hasHardQuad) { + SDValue Chain = Op.getOperand(0); + ISD::CondCode CC = cast(Op.getOperand(1))->get(); + SDValue LHS = Op.getOperand(2); + SDValue RHS = Op.getOperand(3); + SDValue Dest = Op.getOperand(4); + SDLoc dl(Op); + unsigned Opc, SPCC = ~0U; + + // If this is a br_cc of a "setcc", and if the setcc got lowered into + // an CMP[IF]CC/SELECT_[IF]CC pair, find the original compared values. + LookThroughSetCC(LHS, RHS, CC, SPCC); + + // Get the condition flag. + SDValue CompareFlag; + if (LHS.getValueType().isInteger()) { + CompareFlag = DAG.getNode(SPISD::CMPICC, dl, MVT::Glue, LHS, RHS); + if (SPCC == ~0U) SPCC = IntCondCCodeToICC(CC); + // 32-bit compares use the icc flags, 64-bit uses the xcc flags. + Opc = LHS.getValueType() == MVT::i32 ? SPISD::BRICC : SPISD::BRXCC; + } else { + if (!hasHardQuad && LHS.getValueType() == MVT::f128) { + if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC); + CompareFlag = TLI.LowerF128Compare(LHS, RHS, SPCC, dl, DAG); + Opc = SPISD::BRICC; + } else { + CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS); + if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC); + Opc = SPISD::BRFCC; + } + } + return DAG.getNode(Opc, dl, MVT::Other, Chain, Dest, + DAG.getConstant(SPCC, MVT::i32), CompareFlag); +} + +static SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG, + const WDC65816TargetLowering &TLI, + bool hasHardQuad) { + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + ISD::CondCode CC = cast(Op.getOperand(4))->get(); + SDValue TrueVal = Op.getOperand(2); + SDValue FalseVal = Op.getOperand(3); + SDLoc dl(Op); + unsigned Opc, SPCC = ~0U; + + // If this is a select_cc of a "setcc", and if the setcc got lowered into + // an CMP[IF]CC/SELECT_[IF]CC pair, find the original compared values. + LookThroughSetCC(LHS, RHS, CC, SPCC); + + SDValue CompareFlag; + if (LHS.getValueType().isInteger()) { + CompareFlag = DAG.getNode(SPISD::CMPICC, dl, MVT::Glue, LHS, RHS); + Opc = LHS.getValueType() == MVT::i32 ? + SPISD::SELECT_ICC : SPISD::SELECT_XCC; + if (SPCC == ~0U) SPCC = IntCondCCodeToICC(CC); + } else { + if (!hasHardQuad && LHS.getValueType() == MVT::f128) { + if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC); + CompareFlag = TLI.LowerF128Compare(LHS, RHS, SPCC, dl, DAG); + Opc = SPISD::SELECT_ICC; + } else { + CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS); + Opc = SPISD::SELECT_FCC; + if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC); + } + } + return DAG.getNode(Opc, dl, TrueVal.getValueType(), TrueVal, FalseVal, + DAG.getConstant(SPCC, MVT::i32), CompareFlag); +} + +static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG, + const WDC65816TargetLowering &TLI) { + MachineFunction &MF = DAG.getMachineFunction(); + WDC65816MachineFunctionInfo *FuncInfo = MF.getInfo(); + + // Need frame address to find the address of VarArgsFrameIndex. + MF.getFrameInfo()->setFrameAddressIsTaken(true); + + // vastart just stores the address of the VarArgsFrameIndex slot into the + // memory location argument. + SDLoc DL(Op); + SDValue Offset = + DAG.getNode(ISD::ADD, DL, TLI.getPointerTy(), + DAG.getRegister(SP::I6, TLI.getPointerTy()), + DAG.getIntPtrConstant(FuncInfo->getVarArgsFrameOffset())); + const Value *SV = cast(Op.getOperand(2))->getValue(); + return DAG.getStore(Op.getOperand(0), DL, Offset, Op.getOperand(1), + MachinePointerInfo(SV), false, false, 0); +} + +static SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) { + SDNode *Node = Op.getNode(); + EVT VT = Node->getValueType(0); + SDValue InChain = Node->getOperand(0); + SDValue VAListPtr = Node->getOperand(1); + EVT PtrVT = VAListPtr.getValueType(); + const Value *SV = cast(Node->getOperand(2))->getValue(); + SDLoc DL(Node); + SDValue VAList = DAG.getLoad(PtrVT, DL, InChain, VAListPtr, + MachinePointerInfo(SV), false, false, false, 0); + // Increment the pointer, VAList, to the next vaarg. + SDValue NextPtr = DAG.getNode(ISD::ADD, DL, PtrVT, VAList, + DAG.getIntPtrConstant(VT.getSizeInBits()/8)); + // Store the incremented VAList to the legalized pointer. + InChain = DAG.getStore(VAList.getValue(1), DL, NextPtr, + VAListPtr, MachinePointerInfo(SV), false, false, 0); + // Load the actual argument out of the pointer VAList. + // We can't count on greater alignment than the word size. + return DAG.getLoad(VT, DL, InChain, VAList, MachinePointerInfo(), + false, false, false, + std::min(PtrVT.getSizeInBits(), VT.getSizeInBits())/8); +} + +static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG, + const WDC65816Subtarget *Subtarget) { + SDValue Chain = Op.getOperand(0); // Legalize the chain. + SDValue Size = Op.getOperand(1); // Legalize the size. + EVT VT = Size->getValueType(0); + SDLoc dl(Op); + + unsigned SPReg = SP::O6; + SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, VT); + SDValue NewSP = DAG.getNode(ISD::SUB, dl, VT, SP, Size); // Value + Chain = DAG.getCopyToReg(SP.getValue(1), dl, SPReg, NewSP); // Output chain + + // The resultant pointer is actually 16 words from the bottom of the stack, + // to provide a register spill area. + unsigned regSpillArea = Subtarget->is64Bit() ? 128 : 96; + regSpillArea += Subtarget->getStackPointerBias(); + + SDValue NewVal = DAG.getNode(ISD::ADD, dl, VT, NewSP, + DAG.getConstant(regSpillArea, VT)); + SDValue Ops[2] = { NewVal, Chain }; + return DAG.getMergeValues(Ops, 2, dl); +} + + +static SDValue getFLUSHW(SDValue Op, SelectionDAG &DAG) { + SDLoc dl(Op); + SDValue Chain = DAG.getNode(SPISD::FLUSHW, + dl, MVT::Other, DAG.getEntryNode()); + return Chain; +} + +static SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) { + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + MFI->setFrameAddressIsTaken(true); + + EVT VT = Op.getValueType(); + SDLoc dl(Op); + unsigned FrameReg = SP::I6; + + uint64_t depth = Op.getConstantOperandVal(0); + + SDValue FrameAddr; + if (depth == 0) + FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT); + else { + // flush first to make sure the windowed registers' values are in stack + SDValue Chain = getFLUSHW(Op, DAG); + FrameAddr = DAG.getCopyFromReg(Chain, dl, FrameReg, VT); + + for (uint64_t i = 0; i != depth; ++i) { + SDValue Ptr = DAG.getNode(ISD::ADD, + dl, MVT::i32, + FrameAddr, DAG.getIntPtrConstant(56)); + FrameAddr = DAG.getLoad(MVT::i32, dl, + Chain, + Ptr, + MachinePointerInfo(), false, false, false, 0); + } + } + return FrameAddr; +} + +static SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG, + const WDC65816TargetLowering &TLI) { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MFI->setReturnAddressIsTaken(true); + + EVT VT = Op.getValueType(); + SDLoc dl(Op); + uint64_t depth = Op.getConstantOperandVal(0); + + SDValue RetAddr; + if (depth == 0) { + unsigned RetReg = MF.addLiveIn(SP::I7, + TLI.getRegClassFor(TLI.getPointerTy())); + RetAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, RetReg, VT); + } else { + // Need frame address to find return address of the caller. + MFI->setFrameAddressIsTaken(true); + + // flush first to make sure the windowed registers' values are in stack + SDValue Chain = getFLUSHW(Op, DAG); + RetAddr = DAG.getCopyFromReg(Chain, dl, SP::I6, VT); + + for (uint64_t i = 0; i != depth; ++i) { + SDValue Ptr = DAG.getNode(ISD::ADD, + dl, MVT::i32, + RetAddr, + DAG.getIntPtrConstant((i == depth-1)?60:56)); + RetAddr = DAG.getLoad(MVT::i32, dl, + Chain, + Ptr, + MachinePointerInfo(), false, false, false, 0); + } + } + return RetAddr; +} + +static SDValue LowerF64Op(SDValue Op, SelectionDAG &DAG, unsigned opcode) +{ + SDLoc dl(Op); + + assert(Op.getValueType() == MVT::f64 && "LowerF64Op called on non-double!"); + assert(opcode == ISD::FNEG || opcode == ISD::FABS); + + // Lower fneg/fabs on f64 to fneg/fabs on f32. + // fneg f64 => fneg f32:sub_even, fmov f32:sub_odd. + // fabs f64 => fabs f32:sub_even, fmov f32:sub_odd. + + SDValue SrcReg64 = Op.getOperand(0); + SDValue Hi32 = DAG.getTargetExtractSubreg(SP::sub_even, dl, MVT::f32, + SrcReg64); + SDValue Lo32 = DAG.getTargetExtractSubreg(SP::sub_odd, dl, MVT::f32, + SrcReg64); + + Hi32 = DAG.getNode(opcode, dl, MVT::f32, Hi32); + + SDValue DstReg64 = SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, + dl, MVT::f64), 0); + DstReg64 = DAG.getTargetInsertSubreg(SP::sub_even, dl, MVT::f64, + DstReg64, Hi32); + DstReg64 = DAG.getTargetInsertSubreg(SP::sub_odd, dl, MVT::f64, + DstReg64, Lo32); + return DstReg64; +} + +// Lower a f128 load into two f64 loads. +static SDValue LowerF128Load(SDValue Op, SelectionDAG &DAG) +{ + SDLoc dl(Op); + LoadSDNode *LdNode = dyn_cast(Op.getNode()); + assert(LdNode && LdNode->getOffset().getOpcode() == ISD::UNDEF + && "Unexpected node type"); + + unsigned alignment = LdNode->getAlignment(); + if (alignment > 8) + alignment = 8; + + SDValue Hi64 = DAG.getLoad(MVT::f64, + dl, + LdNode->getChain(), + LdNode->getBasePtr(), + LdNode->getPointerInfo(), + false, false, false, alignment); + EVT addrVT = LdNode->getBasePtr().getValueType(); + SDValue LoPtr = DAG.getNode(ISD::ADD, dl, addrVT, + LdNode->getBasePtr(), + DAG.getConstant(8, addrVT)); + SDValue Lo64 = DAG.getLoad(MVT::f64, + dl, + LdNode->getChain(), + LoPtr, + LdNode->getPointerInfo(), + false, false, false, alignment); + + SDValue SubRegEven = DAG.getTargetConstant(SP::sub_even64, MVT::i32); + SDValue SubRegOdd = DAG.getTargetConstant(SP::sub_odd64, MVT::i32); + + SDNode *InFP128 = DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, + dl, MVT::f128); + InFP128 = DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, dl, + MVT::f128, + SDValue(InFP128, 0), + Hi64, + SubRegEven); + InFP128 = DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, dl, + MVT::f128, + SDValue(InFP128, 0), + Lo64, + SubRegOdd); + SDValue OutChains[2] = { SDValue(Hi64.getNode(), 1), + SDValue(Lo64.getNode(), 1) }; + SDValue OutChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + &OutChains[0], 2); + SDValue Ops[2] = {SDValue(InFP128,0), OutChain}; + return DAG.getMergeValues(Ops, 2, dl); +} + +// Lower a f128 store into two f64 stores. +static SDValue LowerF128Store(SDValue Op, SelectionDAG &DAG) { + SDLoc dl(Op); + StoreSDNode *StNode = dyn_cast(Op.getNode()); + assert(StNode && StNode->getOffset().getOpcode() == ISD::UNDEF + && "Unexpected node type"); + SDValue SubRegEven = DAG.getTargetConstant(SP::sub_even64, MVT::i32); + SDValue SubRegOdd = DAG.getTargetConstant(SP::sub_odd64, MVT::i32); + + SDNode *Hi64 = DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG, + dl, + MVT::f64, + StNode->getValue(), + SubRegEven); + SDNode *Lo64 = DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG, + dl, + MVT::f64, + StNode->getValue(), + SubRegOdd); + + unsigned alignment = StNode->getAlignment(); + if (alignment > 8) + alignment = 8; + + SDValue OutChains[2]; + OutChains[0] = DAG.getStore(StNode->getChain(), + dl, + SDValue(Hi64, 0), + StNode->getBasePtr(), + MachinePointerInfo(), + false, false, alignment); + EVT addrVT = StNode->getBasePtr().getValueType(); + SDValue LoPtr = DAG.getNode(ISD::ADD, dl, addrVT, + StNode->getBasePtr(), + DAG.getConstant(8, addrVT)); + OutChains[1] = DAG.getStore(StNode->getChain(), + dl, + SDValue(Lo64, 0), + LoPtr, + MachinePointerInfo(), + false, false, alignment); + return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + &OutChains[0], 2); +} + +static SDValue LowerFNEG(SDValue Op, SelectionDAG &DAG, + const WDC65816TargetLowering &TLI, + bool is64Bit) { + if (Op.getValueType() == MVT::f64) + return LowerF64Op(Op, DAG, ISD::FNEG); + if (Op.getValueType() == MVT::f128) + return TLI.LowerF128Op(Op, DAG, ((is64Bit) ? "_Qp_neg" : "_Q_neg"), 1); + return Op; +} + +static SDValue LowerFABS(SDValue Op, SelectionDAG &DAG, bool isV9) { + if (Op.getValueType() == MVT::f64) + return LowerF64Op(Op, DAG, ISD::FABS); + if (Op.getValueType() != MVT::f128) + return Op; + + // Lower fabs on f128 to fabs on f64 + // fabs f128 => fabs f64:sub_even64, fmov f64:sub_odd64 + + SDLoc dl(Op); + SDValue SrcReg128 = Op.getOperand(0); + SDValue Hi64 = DAG.getTargetExtractSubreg(SP::sub_even64, dl, MVT::f64, + SrcReg128); + SDValue Lo64 = DAG.getTargetExtractSubreg(SP::sub_odd64, dl, MVT::f64, + SrcReg128); + if (isV9) + Hi64 = DAG.getNode(Op.getOpcode(), dl, MVT::f64, Hi64); + else + Hi64 = LowerF64Op(Hi64, DAG, ISD::FABS); + + SDValue DstReg128 = SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, + dl, MVT::f128), 0); + DstReg128 = DAG.getTargetInsertSubreg(SP::sub_even64, dl, MVT::f128, + DstReg128, Hi64); + DstReg128 = DAG.getTargetInsertSubreg(SP::sub_odd64, dl, MVT::f128, + DstReg128, Lo64); + return DstReg128; +} + +static SDValue LowerADDC_ADDE_SUBC_SUBE(SDValue Op, SelectionDAG &DAG) { + + if (Op.getValueType() != MVT::i64) + return Op; + + SDLoc dl(Op); + SDValue Src1 = Op.getOperand(0); + SDValue Src1Lo = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src1); + SDValue Src1Hi = DAG.getNode(ISD::SRL, dl, MVT::i64, Src1, + DAG.getConstant(32, MVT::i64)); + Src1Hi = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src1Hi); + + SDValue Src2 = Op.getOperand(1); + SDValue Src2Lo = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src2); + SDValue Src2Hi = DAG.getNode(ISD::SRL, dl, MVT::i64, Src2, + DAG.getConstant(32, MVT::i64)); + Src2Hi = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src2Hi); + + + bool hasChain = false; + unsigned hiOpc = Op.getOpcode(); + switch (Op.getOpcode()) { + default: llvm_unreachable("Invalid opcode"); + case ISD::ADDC: hiOpc = ISD::ADDE; break; + case ISD::ADDE: hasChain = true; break; + case ISD::SUBC: hiOpc = ISD::SUBE; break; + case ISD::SUBE: hasChain = true; break; + } + SDValue Lo; + SDVTList VTs = DAG.getVTList(MVT::i32, MVT::Glue); + if (hasChain) { + Lo = DAG.getNode(Op.getOpcode(), dl, VTs, Src1Lo, Src2Lo, + Op.getOperand(2)); + } else { + Lo = DAG.getNode(Op.getOpcode(), dl, VTs, Src1Lo, Src2Lo); + } + SDValue Hi = DAG.getNode(hiOpc, dl, VTs, Src1Hi, Src2Hi, Lo.getValue(1)); + SDValue Carry = Hi.getValue(1); + + Lo = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i64, Lo); + Hi = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i64, Hi); + Hi = DAG.getNode(ISD::SHL, dl, MVT::i64, Hi, + DAG.getConstant(32, MVT::i64)); + + SDValue Dst = DAG.getNode(ISD::OR, dl, MVT::i64, Hi, Lo); + SDValue Ops[2] = { Dst, Carry }; + return DAG.getMergeValues(Ops, 2, dl); +} + +SDValue WDC65816TargetLowering:: +LowerOperation(SDValue Op, SelectionDAG &DAG) const { + + bool hasHardQuad = Subtarget->hasHardQuad(); + bool is64Bit = Subtarget->is64Bit(); + bool isV9 = Subtarget->isV9(); + + switch (Op.getOpcode()) { + default: llvm_unreachable("Should not custom lower this!"); + + case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG, *this); + case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); + case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); + case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); + case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); + case ISD::ConstantPool: return LowerConstantPool(Op, DAG); + case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG, *this, + hasHardQuad); + case ISD::SINT_TO_FP: return LowerSINT_TO_FP(Op, DAG, *this, + hasHardQuad); + case ISD::FP_TO_UINT: return LowerFP_TO_UINT(Op, DAG, *this, + hasHardQuad); + case ISD::UINT_TO_FP: return LowerUINT_TO_FP(Op, DAG, *this, + hasHardQuad); + case ISD::BR_CC: return LowerBR_CC(Op, DAG, *this, + hasHardQuad); + case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG, *this, + hasHardQuad); + case ISD::VASTART: return LowerVASTART(Op, DAG, *this); + case ISD::VAARG: return LowerVAARG(Op, DAG); + case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG, + Subtarget); + + case ISD::LOAD: return LowerF128Load(Op, DAG); + case ISD::STORE: return LowerF128Store(Op, DAG); + case ISD::FADD: return LowerF128Op(Op, DAG, + getLibcallName(RTLIB::ADD_F128), 2); + case ISD::FSUB: return LowerF128Op(Op, DAG, + getLibcallName(RTLIB::SUB_F128), 2); + case ISD::FMUL: return LowerF128Op(Op, DAG, + getLibcallName(RTLIB::MUL_F128), 2); + case ISD::FDIV: return LowerF128Op(Op, DAG, + getLibcallName(RTLIB::DIV_F128), 2); + case ISD::FSQRT: return LowerF128Op(Op, DAG, + getLibcallName(RTLIB::SQRT_F128),1); + case ISD::FNEG: return LowerFNEG(Op, DAG, *this, is64Bit); + case ISD::FABS: return LowerFABS(Op, DAG, isV9); + case ISD::FP_EXTEND: return LowerF128_FPEXTEND(Op, DAG, *this); + case ISD::FP_ROUND: return LowerF128_FPROUND(Op, DAG, *this); + case ISD::ADDC: + case ISD::ADDE: + case ISD::SUBC: + case ISD::SUBE: return LowerADDC_ADDE_SUBC_SUBE(Op, DAG); + } +} + +MachineBasicBlock * +WDC65816TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo(); + unsigned BROpcode; + unsigned CC; + DebugLoc dl = MI->getDebugLoc(); + // Figure out the conditional branch opcode to use for this select_cc. + switch (MI->getOpcode()) { + default: llvm_unreachable("Unknown SELECT_CC!"); + case SP::SELECT_CC_Int_ICC: + case SP::SELECT_CC_FP_ICC: + case SP::SELECT_CC_DFP_ICC: + case SP::SELECT_CC_QFP_ICC: + BROpcode = SP::BCOND; + break; + case SP::SELECT_CC_Int_FCC: + case SP::SELECT_CC_FP_FCC: + case SP::SELECT_CC_DFP_FCC: + case SP::SELECT_CC_QFP_FCC: + BROpcode = SP::FBCOND; + break; + } + + CC = (SPCC::CondCodes)MI->getOperand(3).getImm(); + + // To "insert" a SELECT_CC 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; + ++It; + + // thisMBB: + // ... + // TrueVal = ... + // [f]bCC copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, copy0MBB); + F->insert(It, sinkMBB); + + // Transfer the remainder of BB and its successor edges to sinkMBB. + sinkMBB->splice(sinkMBB->begin(), BB, + llvm::next(MachineBasicBlock::iterator(MI)), + BB->end()); + sinkMBB->transferSuccessorsAndUpdatePHIs(BB); + + // Add the true and fallthrough blocks as its successors. + BB->addSuccessor(copy0MBB); + BB->addSuccessor(sinkMBB); + + BuildMI(BB, dl, TII.get(BROpcode)).addMBB(sinkMBB).addImm(CC); + + // copy0MBB: + // %FalseValue = ... + // # fallthrough to sinkMBB + BB = copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // sinkMBB: + // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] + // ... + BB = sinkMBB; + BuildMI(*BB, BB->begin(), dl, TII.get(SP::PHI), MI->getOperand(0).getReg()) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB) + .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +//===----------------------------------------------------------------------===// +// WDC65816 Inline Assembly Support +//===----------------------------------------------------------------------===// + +/// getConstraintType - Given a constraint letter, return the type of +/// constraint it is for this target. +WDC65816TargetLowering::ConstraintType +WDC65816TargetLowering::getConstraintType(const std::string &Constraint) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + default: break; + case 'r': return C_RegisterClass; + } + } + + return TargetLowering::getConstraintType(Constraint); +} + +std::pair +WDC65816TargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint, + MVT VT) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + case 'r': + return std::make_pair(0U, &SP::IntRegsRegClass); + } + } + + return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); +} + +bool +WDC65816TargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { + // The WDC65816 target isn't yet aware of offsets. + return false; +} + +void WDC65816TargetLowering::ReplaceNodeResults(SDNode *N, + SmallVectorImpl& Results, + SelectionDAG &DAG) const { + + SDLoc dl(N); + + RTLIB::Libcall libCall = RTLIB::UNKNOWN_LIBCALL; + + switch (N->getOpcode()) { + default: + llvm_unreachable("Do not know how to custom type legalize this operation!"); + + case ISD::FP_TO_SINT: + case ISD::FP_TO_UINT: + // Custom lower only if it involves f128 or i64. + if (N->getOperand(0).getValueType() != MVT::f128 + || N->getValueType(0) != MVT::i64) + return; + libCall = ((N->getOpcode() == ISD::FP_TO_SINT) + ? RTLIB::FPTOSINT_F128_I64 + : RTLIB::FPTOUINT_F128_I64); + + Results.push_back(LowerF128Op(SDValue(N, 0), + DAG, + getLibcallName(libCall), + 1)); + return; + + case ISD::SINT_TO_FP: + case ISD::UINT_TO_FP: + // Custom lower only if it involves f128 or i64. + if (N->getValueType(0) != MVT::f128 + || N->getOperand(0).getValueType() != MVT::i64) + return; + + libCall = ((N->getOpcode() == ISD::SINT_TO_FP) + ? RTLIB::SINTTOFP_I64_F128 + : RTLIB::UINTTOFP_I64_F128); + + Results.push_back(LowerF128Op(SDValue(N, 0), + DAG, + getLibcallName(libCall), + 1)); + return; + } +} + +#endif diff --git a/lib/Target/WDC65816/WDC65816ISelLowering.h b/lib/Target/WDC65816/WDC65816ISelLowering.h index e69de29b..d454e13d 100644 --- a/lib/Target/WDC65816/WDC65816ISelLowering.h +++ b/lib/Target/WDC65816/WDC65816ISelLowering.h @@ -0,0 +1,166 @@ +//===- WDC65816ISelLowering.h - WDC65816 DAG Lowering Interface -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that WDC65816 uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef WDC65816_ISELLOWERING_H +#define WDC65816_ISELLOWERING_H + +#include "WDC65816.h" +#include "llvm/Target/TargetLowering.h" + +namespace llvm { +#if 0 // WDC_TODO - Do I need any of this? + namespace SPISD { + enum { + FIRST_NUMBER = ISD::BUILTIN_OP_END, + CMPICC, // Compare two GPR operands, set icc+xcc. + CMPFCC, // Compare two FP operands, set fcc. + BRICC, // Branch to dest on icc condition + BRXCC, // Branch to dest on xcc condition (64-bit only). + BRFCC, // Branch to dest on fcc condition + SELECT_ICC, // Select between two values using the current ICC flags. + SELECT_XCC, // Select between two values using the current XCC flags. + SELECT_FCC, // Select between two values using the current FCC flags. + + Hi, Lo, // Hi/Lo operations, typically on a global address. + + FTOI, // FP to Int within a FP register. + ITOF, // Int to FP within a FP register. + FTOX, // FP to Int64 within a FP register. + XTOF, // Int64 to FP within a FP register. + + CALL, // A call instruction. + RET_FLAG, // Return with a flag operand. + GLOBAL_BASE_REG, // Global base reg for PIC. + FLUSHW, // FLUSH register windows to stack. + + TLS_ADD, // For Thread Local Storage (TLS). + TLS_LD, + TLS_CALL + }; + } +#endif + + class WDC65816TargetLowering : public TargetLowering { + public: + WDC65816TargetLowering(TargetMachine &TM); + +#if 0 // WDC_TODO - Do I need any of this? + virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const; + + /// computeMaskedBitsForTargetNode - Determine which of the bits specified + /// in Mask are known to be either zero or one and return them in the + /// KnownZero/KnownOne bitsets. + virtual void computeMaskedBitsForTargetNode(const SDValue Op, + APInt &KnownZero, + APInt &KnownOne, + const SelectionDAG &DAG, + unsigned Depth = 0) const; + + virtual MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *MBB) const; + + virtual const char *getTargetNodeName(unsigned Opcode) const; + + ConstraintType getConstraintType(const std::string &Constraint) const; + std::pair + getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const; + + virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; + virtual MVT getScalarShiftAmountTy(EVT LHSTy) const { return MVT::i32; } + + /// getSetCCResultType - Return the ISD::SETCC ValueType + virtual EVT getSetCCResultType(LLVMContext &Context, EVT VT) const; + + virtual SDValue + LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl &Ins, + SDLoc dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + SDValue LowerFormalArguments_32(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl &Ins, + SDLoc dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + SDValue LowerFormalArguments_64(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl &Ins, + SDLoc dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + + virtual SDValue + LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const; + SDValue LowerCall_32(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const; + SDValue LowerCall_64(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const; + + virtual SDValue + LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + SDLoc dl, SelectionDAG &DAG) const; + SDValue LowerReturn_32(SDValue Chain, + CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + SDLoc DL, SelectionDAG &DAG) const; + SDValue LowerReturn_64(SDValue Chain, + CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + SDLoc DL, SelectionDAG &DAG) const; + + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; + + unsigned getSRetArgSize(SelectionDAG &DAG, SDValue Callee) const; + SDValue withTargetFlags(SDValue Op, unsigned TF, SelectionDAG &DAG) const; + SDValue makeHiLoPair(SDValue Op, unsigned HiTF, unsigned LoTF, + SelectionDAG &DAG) const; + SDValue makeAddress(SDValue Op, SelectionDAG &DAG) const; + + SDValue LowerF128_LibCallArg(SDValue Chain, ArgListTy &Args, + SDValue Arg, SDLoc DL, + SelectionDAG &DAG) const; + SDValue LowerF128Op(SDValue Op, SelectionDAG &DAG, + const char *LibFuncName, + unsigned numArgs) const; + SDValue LowerF128Compare(SDValue LHS, SDValue RHS, + unsigned &SPCC, + SDLoc DL, + SelectionDAG &DAG) const; + + bool ShouldShrinkFPConstant(EVT VT) const { + // Do not shrink FP constpool if VT == MVT::f128. + // (ldd, call _Q_fdtoq) is more expensive than two ldds. + return VT != MVT::f128; + } + + virtual void ReplaceNodeResults(SDNode *N, + SmallVectorImpl& Results, + SelectionDAG &DAG) const; +#endif + }; +} // end namespace llvm + +#endif // WDC65816_ISELLOWERING_H diff --git a/lib/Target/WDC65816/WDC65816InstrFormats.td b/lib/Target/WDC65816/WDC65816InstrFormats.td index c035853b..67ef10ec 100644 --- a/lib/Target/WDC65816/WDC65816InstrFormats.td +++ b/lib/Target/WDC65816/WDC65816InstrFormats.td @@ -1,4 +1,4 @@ -//===- WDCInstrFormats.td - WDC 65816 Instruction Formats ----*- tablegen -*-===// +//===- WDCInstrFormats.td - WDC 65816 Instruction Formats --*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/WDC65816/WDC65816InstrInfo.cpp b/lib/Target/WDC65816/WDC65816InstrInfo.cpp new file mode 100644 index 00000000..d3227fb6 --- /dev/null +++ b/lib/Target/WDC65816/WDC65816InstrInfo.cpp @@ -0,0 +1,65 @@ +//===-- WDC65816InstrInfo.cpp - WDC65816 Instruction Information ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the WDC65816 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "WDC65816InstrInfo.h" +#include "WDC65816.h" +#include "WDC65816MachineFunctionInfo.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +#define GET_INSTRINFO_CTOR_DTOR +#include "WDC65816GenInstrInfo.inc" + +using namespace llvm; + + +// Pin the vtable to this file. +void WDC65816InstrInfo::anchor() {} + +WDC65816InstrInfo::WDC65816InstrInfo(void) +: WDC65816GenInstrInfo(WDC::ADJCALLSTACKDOWN, WDC::ADJCALLSTACKUP), +RI() { +} + + +unsigned WDC65816InstrInfo::getGlobalBaseReg(MachineFunction *MF) const +{ + WDC65816MachineFunctionInfo *WDC65816FI = MF->getInfo(); + + return WDC65816FI->getGlobalBaseReg(); + +#if 0 // WDC_TODO - Do something better here... + unsigned GlobalBaseReg = WDC65816FI->getGlobalBaseReg(); + if (GlobalBaseReg != 0) + return GlobalBaseReg; + + // Insert the set of GlobalBaseReg into the first MBB of the function + MachineBasicBlock &FirstMBB = MF->front(); + MachineBasicBlock::iterator MBBI = FirstMBB.begin(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + + GlobalBaseReg = RegInfo.createVirtualRegister(&SP::IntRegsRegClass); + + DebugLoc dl; + + BuildMI(FirstMBB, MBBI, dl, get(SP::GETPCX), GlobalBaseReg); + SparcFI->setGlobalBaseReg(GlobalBaseReg); + return GlobalBaseReg; +#endif +} diff --git a/lib/Target/WDC65816/WDC65816InstrInfo.h b/lib/Target/WDC65816/WDC65816InstrInfo.h new file mode 100644 index 00000000..ad614137 --- /dev/null +++ b/lib/Target/WDC65816/WDC65816InstrInfo.h @@ -0,0 +1,43 @@ +//===-- WDC65816InstrInfo.h - WDC65816 Instruction Information --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the WDC65816 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef WDC65816INSTRUCTIONINFO_H +#define WDC65816INSTRUCTIONINFO_H + +#include "WDC65816RegisterInfo.h" +#include "llvm/Target/TargetInstrInfo.h" + +#define GET_INSTRINFO_HEADER +#include "WDC65816GenInstrInfo.inc" + +namespace llvm { + + class WDC65816InstrInfo : public WDC65816GenInstrInfo { + const WDC65816RegisterInfo RI; + virtual void anchor(); + public: + explicit WDC65816InstrInfo(void); + + /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As + /// such, whenever a client has an instance of instruction info, it should + /// always be able to get register info as well (through this method). + /// + virtual const WDC65816RegisterInfo &getRegisterInfo() const { return RI; } + + unsigned getGlobalBaseReg(MachineFunction *MF) const; + + }; + +} + +#endif diff --git a/lib/Target/WDC65816/WDC65816InstrInfo.td b/lib/Target/WDC65816/WDC65816InstrInfo.td index 5eb98c2e..1c1fe5ac 100644 --- a/lib/Target/WDC65816/WDC65816InstrInfo.td +++ b/lib/Target/WDC65816/WDC65816InstrInfo.td @@ -1,4 +1,4 @@ -//===- WDCInstrInfo.td - Target Description for WDC 65816 Target ------------===// +//===- WDCInstrInfo.td - Target Description for WDC 65816 Target ----------===// // // The LLVM Compiler Infrastructure // @@ -28,24 +28,23 @@ include "WDC65816InstrFormats.td" //===----------------------------------------------------------------------===// // Adressing modes. -//def ADDRabs : ComplexPattern; -//def ADDRabsl : ComplexPattern; -//def ADDRdp : ComplexPattern; - -def addr : ComplexPattern; +def ADDRabs : ComplexPattern; +def ADDRabsl : ComplexPattern; +def ADDRdp : ComplexPattern; +//def addr : ComplexPattern; // Address operands -def ADDRabs : Operand { +def MEMabs : Operand { let PrintMethod = "printMemOperand"; //let MIOperandInfo = (ops ptr_rc, ptr_rc); } -def ADDRabsl : Operand { +def MEMabsl : Operand { let PrintMethod = "printMemOperand"; //let MIOperandInfo = (ops ptr_rc, ptr_rc); } -def ADDRdp : Operand { +def MEMdp : Operand { let PrintMethod = "printMemOperand"; //let MIOperandInfo = (ops ptr_rc, ptr_rc); } @@ -69,6 +68,38 @@ def ADDRdp : Operand { //===----------------------------------------------------------------------===// +// Pseudo instructions. +class Pseudo pattern> +: InstWDC; + + +def SDT_SPCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>; +def SDT_SPCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>, + SDTCisVT<1, i32> ]>; + +def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_SPCallSeqStart, + [SDNPHasChain, SDNPOutGlue]>; +def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_SPCallSeqEnd, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; + +def getPCX : Operand { + let PrintMethod = "printGetPCX"; +} + +// GETPCX for PIC +let Defs = [PC] in { + def GETPCX : Pseudo<(outs getPCX:$getpcseq), (ins), "$getpcseq", [] >; +} + +let Defs = [S], Uses = [S] in { + def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt), + "!ADJCALLSTACKDOWN $amt", + [(callseq_start timm:$amt)]>; + def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), + "!ADJCALLSTACKUP $amt1", + [(callseq_end timm:$amt1, timm:$amt2)]>; +} + // Group #1 Instructions // JSR TODO - Need to set all of the DAG patterns @@ -78,150 +109,150 @@ def ADDRdp : Operand { def ADCimm : Group1$src2", - [(set AccRegs:$dst, (add AccRegs:$src1, i16:$src2))]>; + [(set i16:$dst, (add i16:$src1, i16:$src2))]>; def ADCabs : Group1; + [(set i16:$dst, (add i16:$src1, (load ADDRabs:$src2)))]>; def ADCabsl : Group1$src2", - [(set AccRegs:$dst, (add AccRegs:$src1, (load addr:$src2)))]>; + [(set i16:$dst, (add i16:$src1, (load ADDRabsl:$src2)))]>; def ADCdp : Group1; + [(set i16:$dst, (add i16:$src1, (load ADDRdp:$src2)))]>; def ADCdpindir : Group1; def ADCdpindirl : Group1; def ADCabsix : Group1; def ADCabsiy : Group1; def ADCabsixl : Group1$src2,$src3", []>; def ADCdpix : Group1; def ADCdpiindirx : Group1; def ADCdpindiriy : Group1; def ADCdpindirliy : Group1; def ADCsr : Group1; def ADCsrindir : Group1; def ANDimm : Group1$src2", - [(set AccRegs:$dst, (and AccRegs:$src1, i16:$src2))]>; + [(set i16:$dst, (and i16:$src1, i16:$src2))]>; def ANDabs : Group1; + [(set i16:$dst, (and i16:$src1, (load ADDRabs:$src2)))]>; def ANDabsl : Group1$src2", - [(set AccRegs:$dst, (and AccRegs:$src1, (load addr:$src2)))]>; + [(set i16:$dst, (and i16:$src1, (load ADDRabsl:$src2)))]>; def ANDdp : Group1; + [(set i16:$dst, (and i16:$src1, (load ADDRdp:$src2)))]>; def ANDdpindir : Group1; def ANDdpindirl : Group1; def ANDabsix : Group1; def ANDabsiy : Group1; def ANDabsixl : Group1$src2,$src3", []>; def ANDdpix : Group1; def ANDdpiindirx : Group1; def ANDdpindiriy : Group1; def ANDdpindirliy : Group1; def ANDsr : Group1; def ANDsrindir : Group1; @@ -231,442 +262,442 @@ def CMPimm : Group1; def CMPabs : Group1; def CMPabsl : Group1$src2", []>; def CMPdp : Group1; def CMPdpindir : Group1; def CMPdpindirl : Group1; def CMPabsix : Group1; def CMPabsiy : Group1; def CMPabsixl : Group1$src2,$src3", []>; def CMPdpix : Group1; def CMPdpiindirx : Group1; def CMPdpindiriy : Group1; def CMPdpindirliy : Group1; def CMPsr : Group1; def CMPsrindir : Group1; def EORimm : Group1$src2", - [(set AccRegs:$dst, (xor AccRegs:$src1, i16:$src2))]>; + [(set i16:$dst, (xor i16:$src1, i16:$src2))]>; def EORabs : Group1; + [(set i16:$dst, (xor i16:$src1, (load ADDRabs:$src2)))]>; def EORabsl : Group1$src2", - [(set AccRegs:$dst, (xor AccRegs:$src1, (load addr:$src2)))]>; + [(set i16:$dst, (xor i16:$src1, (load ADDRabsl:$src2)))]>; def EORdp : Group1; + [(set i16:$dst, (xor i16:$src1, (load ADDRdp:$src2)))]>; def EORdpindir : Group1; def EORdpindirl : Group1; def EORabsix : Group1; def EORabsiy : Group1; def EORabsixl : Group1$src2,$src3", []>; def EORdpix : Group1; def EORdpiindirx : Group1; def EORdpindiriy : Group1; def EORdpindirliy : Group1; def EORsr : Group1; def EORsrindir : Group1; def LDAimm : Group1$src", - [(set AccRegs:$dst, i16:$src)]>; + [(set i16:$dst, i16:$src)]>; def LDAabs : Group1; + [(set i16:$dst, (load ADDRabs:$src))]>; def LDAabsl : Group1$src", - [(set AccRegs:$dst, (load addr:$src))]>; + [(set i16:$dst, (load ADDRabsl:$src))]>; def LDAdp : Group1; + [(set i16:$dst, (load ADDRdp:$src))]>; def LDAdpindir : Group1; def LDAdpindirl : Group1; def LDAabsix : Group1; def LDAabsiy : Group1; def LDAabsixl : Group1$src2,$src3", []>; def LDAdpix : Group1; def LDAdpiindirx : Group1; def LDAdpindiriy : Group1; def LDAdpindirliy : Group1; def LDAsr : Group1; def LDAsrindir : Group1; def ORAimm : Group1$src2", - [(set AccRegs:$dst, (or AccRegs:$src1, i16:$src2))]>; + [(set i16:$dst, (or i16:$src1, i16:$src2))]>; def ORAabs : Group1; + [(set i16:$dst, (or i16:$src1, (load ADDRabs:$src2)))]>; def ORAabsl : Group1$src2", - [(set AccRegs:$dst, (or AccRegs:$src1, (load addr:$src2)))]>; + [(set i16:$dst, (or i16:$src1, (load ADDRabsl:$src2)))]>; def ORAdp : Group1; + [(set i16:$dst, (or i16:$src1, (load ADDRdp:$src2)))]>; def ORAdpindir : Group1; def ORAdpindirl : Group1; def ORAabsix : Group1; def ORAabsiy : Group1; def ORAabsixl : Group1$src2,$src3", []>; def ORAdpix : Group1; def ORAdpiindirx : Group1; def ORAdpindiriy : Group1; def ORAdpindirliy : Group1; def ORAsr : Group1; def ORAsrindir : Group1; def SBCimm : Group1$src2", - [(set AccRegs:$dst, (sub AccRegs:$src1, i16:$src2))]>; + [(set i16:$dst, (sub i16:$src1, i16:$src2))]>; def SBCabs : Group1; + [(set i16:$dst, (sub i16:$src1, (load ADDRabs:$src2)))]>; def SBCabsl : Group1$src2", - [(set AccRegs:$dst, (sub AccRegs:$src1, (load addr:$src2)))]>; + [(set i16:$dst, (sub i16:$src1, (load ADDRabsl:$src2)))]>; def SBCdp : Group1; + [(set i16:$dst, (sub i16:$src1, (load ADDRdp:$src2)))]>; def SBCdpindir : Group1; def SBCdpindirl : Group1; def SBCabsix : Group1; def SBCabsiy : Group1; def SBCabsixl : Group1$src2,$src3", []>; def SBCdpix : Group1; def SBCdpiindirx : Group1; def SBCdpindiriy : Group1; def SBCdpindirliy : Group1; def SBCsr : Group1; def SBCsrindir : Group1; + []>; def STAabs : Group1; + [(store i16:$src, ADDRabs:$dst)]>; def STAabsl : Group1$dst", - [(store AccRegs:$src, ADDRabsl:$dst)]>; + [(store i16:$src, ADDRabsl:$dst)]>; def STAdp : Group1; + [(store i16:$src, ADDRdp:$dst)]>; def STAdpindir : Group1; def STAdpindirl : Group1; def STAabsix : Group1; def STAabsiy : Group1; def STAabsixl : Group1$src2,$src3", []>; def STAdpix : Group1; def STAdpiindirx : Group1; def STAdpindiriy : Group1; def STAdpindirliy : Group1; def STAsr : Group1; def STAsrindir : Group1; @@ -675,242 +706,242 @@ def STAsrindir : Group1; + [(set i16:$dst, (shl i16:$src, (i16 1)))]>; def ASLabs : Group2; - // JSR TODO - [(store (shl (load addr:$dst), (i16 1)), addr:$dst)]>; + // JSR TODO - [(store (shl (load ADDRabs:$dst), (i16 1)), ADDRabs:$dst)]>; def ASLdp : Group2; - // JSR TODO - [(store (shl (load addr:$dst), (i8 1)), addr:$dst)]>; + // JSR TODO - [(store (shl (load ADDRdp:$dst), (i8 1)), ADDRdp:$dst)]>; def ASLabsix : Group2; def ASLdpix : Group2; def DECacc : Group2; + [(set i16:$dst, (sub i16:$src, 1))]>; def DECabs : Group2; - // JSR TODO - [(store (sub (load addr:$dst), 1), addr:$dst)]>; + // JSR TODO - [(store (sub (load ADDRabs:$dst), 1), ADDRabs:$dst)]>; def DECdp : Group2; - // JSR TODO - [(store (sub (load addr:$dst), 1), addr:$dst)]>; + // JSR TODO - [(store (sub (load ADDRdp:$dst), 1), ADDRdp:$dst)]>; def DECabsix : Group2; def DECdpix : Group2; def INCacc : Group2; + [(set i16:$dst, (add i16:$src, 1))]>; def INCabs : Group2; - // JSR TODO - [(store (add (load addr:$dst), 1), addr:$dst)]>; + // JSR TODO - [(store (add (load ADDRabs:$dst), 1), ADDRabs:$dst)]>; def INCdp : Group2; - // JSR TODO - [(store (add (load addr:$dst), 1), addr:$dst)]>; + // JSR TODO - [(store (add (load ADDRdp:$dst), 1), ADDRdp:$dst)]>; def INCabsix : Group2; def INCdpix : Group2; def LDXimm : Group2; + [(set i16:$dst, i16:$src)]>; def LDXabs : Group2; + [(set i16:$dst, (load ADDRabs:$src))]>; def LDXdp : Group2; + [(set i16:$dst, (load ADDRdp:$src))]>; def LDXabsiy : Group2; def LDXdpiy : Group2; def LDYimm : Group2_Y; + [(set i16:$dst, i16:$src)]>; def LDYabs : Group2_Y; + [(set i16:$dst, (load ADDRabs:$src))]>; def LDYdp : Group2_Y; + [(set i16:$dst, (load ADDRdp:$src))]>; def LDYabsix : Group2_Y; def LDYdpix : Group2_Y; def LSRacc : Group2; + [(set i16:$dst, (srl i16:$src, (i8 1)))]>; def LSRabs : Group2; - // JSR TODO - [(store (srl (load addr:$dst), (i8 1)), addr:$dst)]>; + // JSR TODO - [(store (srl (load ADDRabs:$dst), (i8 1)), ADDRabs:$dst)]>; def LSRdp : Group2; - // JSR TODO - [(store (srl (load addr:$dst), (i8 1)), addr:$dst)]>; + // JSR TODO - [(store (srl (load ADDRdp:$dst), (i8 1)), ADDRdp:$dst)]>; def LSRabsix : Group2; def LSRdpix : Group2; def ROLacc : Group2; + [(set i16:$dst, (rotl i16:$src, (i8 1)))]>; def ROLabs : Group2; - // JSR TODO - [(store (rotl (load addr:$dst), (i8 1)), addr:$dst)]>; + // JSR TODO - [(store (rotl (load ADDRabs:$dst), (i8 1)), ADDRabs:$dst)]>; def ROLdp : Group2; - // JSR TODO - [(store (rotl (load addr:$dst), (i8 1)), addr:$dst)]>; + // JSR TODO - [(store (rotl (load ADDRdp:$dst), (i8 1)), ADDRdp:$dst)]>; def ROLabsix : Group2; def ROLdpix : Group2; def RORacc : Group2; + [(set i16:$dst, (rotr i16:$src, (i8 1)))]>; def RORabs : Group2; - // JSR TODO - [(store (rotr (load addr:$dst), (i8 1)), addr:$dst)]>; + // JSR TODO - [(store (rotr (load ADDRabs:$dst), (i8 1)), ADDRabs:$dst)]>; def RORdp : Group2; - // JSR TODO - [(store (rotr (load addr:$dst), (i8 1)), addr:$dst)]>; + // JSR TODO - [(store (rotr (load ADDRdp:$dst), (i8 1)), ADDRdp:$dst)]>; def RORabsix : Group2; def RORdpix : Group2; def STXabs : Group2; + [(store i16:$src, ADDRabs:$dst)]>; def STXdp : Group2; + [(store i16:$src, ADDRdp:$dst)]>; def STXdpiy : Group2; def STYabs : Group2_Y; + [(store i16:$src, ADDRabs:$dst)]>; def STYdp : Group2_Y; + [(store i16:$src, ADDRdp:$dst)]>; def STYdpix : Group2_Y; @@ -919,17 +950,17 @@ def STYdpix : Group2_Y; def BCS : Group3; def BEQ : Group3; @@ -939,42 +970,42 @@ def BITimm : Group3; def BITabs : Group3; def BITdp : Group3; def BITabsix : Group3; def BITdpix : Group3; def BMI : Group3; def BNE : Group3; def BPL : Group3; def BRA : Group3; @@ -984,17 +1015,17 @@ def BRK : Group3; def BRL : Group3; def BVC : Group3; def BVS : Group3; @@ -1029,12 +1060,12 @@ def CPXimm : Group3; def CPXabs : Group3; def CPXdp : Group3; @@ -1044,82 +1075,82 @@ def CPYimm : Group3; def CPYabs : Group3; def CPYdp : Group3; def DEX : Group3; + [(set i16:$dst, (sub i16:$src, 1))]>; def DEY : Group3; + [(set i16:$dst, (sub i16:$src, 1))]>; def INX : Group3; + [(set i16:$dst, (add i16:$src, 1))]>; def INY : Group3; + [(set i16:$dst, (add i16:$src, 1))]>; def JMPabs : Group3; def JMPindir : Group3; def JMPindiri : Group3; def JMLabs : Group3$src", []>; def JMLindirl : Group3$src]", []>; def JSL : Group3$src", []>; def JSRabs : Group3; def JSRindiri : Group3; def MVN : Group3; def MVP : Group3; @@ -1254,104 +1285,106 @@ def STP : Group3; def STZabs : Group3; + []>; + // How to do literal zero? [(store i16:0, ADDRabs:$dst)]>; def STZdp : Group3; + []>; + // How to do literal zero? [(store i16:0, ADDRdp:$dst)]>; def STZabsi : Group3; def STZdpi : Group3; def TAX : Group3; + [(set i16:$dst, i16:$src)]>; def TAY : Group3; + [(set i16:$dst, i16:$src)]>; def TCD : Group3; + [(set i16:$dst, i16:$src)]>; def TCS : Group3; + [(set i16:$dst, i16:$src)]>; def TDC : Group3; + [(set i16:$dst, i16:$src)]>; def TRBabs : Group3; def TRBdp : Group3; def TSBabs : Group3; def TSBdp : Group3; def TSC : Group3; + [(set i16:$dst, i16:$src)]>; def TSX : Group3; + [(set i16:$dst, i16:$src)]>; def TXA : Group3; + [(set i16:$dst, i16:$src)]>; def TXS : Group3; + [(set i16:$dst, i16:$src)]>; def TXY : Group3; + [(set i16:$dst, i16:$src)]>; def TYA : Group3; + [(set i16:$dst, i16:$src)]>; def TYX : Group3; + [(set i16:$dst, i16:$src)]>; def WAI : Group3 +ReserveAppRegisters("sparc-reserve-app-registers", cl::Hidden, cl::init(false), + cl::desc("Reserve application registers (%g2-%g4)")); +#endif + +WDC65816RegisterInfo::WDC65816RegisterInfo(void) +: WDC65816GenRegisterInfo(WDC::P) { +} + +const uint16_t* WDC65816RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) +const { + return CSR_NoRegs_SaveList; +} + +const uint32_t* +WDC65816RegisterInfo::getCallPreservedMask(CallingConv::ID CC) const { + return CSR_NoRegs_RegMask; +} + +const uint32_t* +WDC65816RegisterInfo::getRTCallPreservedMask(CallingConv::ID CC) const { + return CSR_NoRegs_RegMask; +} + +BitVector WDC65816RegisterInfo::getReservedRegs(const MachineFunction &MF) const { + BitVector Reserved(getNumRegs()); + // FIXME: G1 reserved for now for large imm generation by frame code. + Reserved.set(WDC::P); + Reserved.set(WDC::S); + Reserved.set(WDC::D); + Reserved.set(WDC::K); + Reserved.set(WDC::B); + Reserved.set(WDC::PC); + Reserved.set(WDC::FP); + + return Reserved; +} + + +unsigned WDC65816RegisterInfo::getFrameRegister(const MachineFunction &MF) const { + return WDC::FP; +} + + +const TargetRegisterClass* +WDC65816RegisterInfo::getPointerRegClass(const MachineFunction &MF, + unsigned Kind) const { + // WDC_TODO - this is not a pointer reg actually. This should end up being the + // 32-bit direct page registers which are not defined yet. + return &WDC::IndexRegsRegClass; +} + + +void +WDC65816RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, unsigned FIOperandNum, + RegScavenger *RS) const { + // WDC_TODO - Write something here... +} + +#if 0 // TODO - How much of this stuff do I need? +static void replaceFI(MachineFunction &MF, + MachineBasicBlock::iterator II, + MachineInstr &MI, + DebugLoc dl, + unsigned FIOperandNum, int Offset, + unsigned FramePtr) +{ + // Replace frame index with a frame pointer reference. + if (Offset >= -4096 && Offset <= 4095) { + // If the offset is small enough to fit in the immediate field, directly + // encode it. + MI.getOperand(FIOperandNum).ChangeToRegister(FramePtr, false); + MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); + return; + } + + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + + // FIXME: it would be better to scavenge a register here instead of + // reserving G1 all of the time. + if (Offset >= 0) { + // Emit nonnegaive immediates with sethi + or. + // sethi %hi(Offset), %g1 + // add %g1, %fp, %g1 + // Insert G1+%lo(offset) into the user. + BuildMI(*MI.getParent(), II, dl, TII.get(SP::SETHIi), SP::G1) + .addImm(HI22(Offset)); + + + // Emit G1 = G1 + I6 + BuildMI(*MI.getParent(), II, dl, TII.get(SP::ADDrr), SP::G1).addReg(SP::G1) + .addReg(FramePtr); + // Insert: G1+%lo(offset) into the user. + MI.getOperand(FIOperandNum).ChangeToRegister(SP::G1, false); + MI.getOperand(FIOperandNum + 1).ChangeToImmediate(LO10(Offset)); + return; + } + + // Emit Negative numbers with sethi + xor + // sethi %hix(Offset), %g1 + // xor %g1, %lox(offset), %g1 + // add %g1, %fp, %g1 + // Insert: G1 + 0 into the user. + BuildMI(*MI.getParent(), II, dl, TII.get(SP::SETHIi), SP::G1) + .addImm(HIX22(Offset)); + BuildMI(*MI.getParent(), II, dl, TII.get(SP::XORri), SP::G1) + .addReg(SP::G1).addImm(LOX10(Offset)); + + BuildMI(*MI.getParent(), II, dl, TII.get(SP::ADDrr), SP::G1).addReg(SP::G1) + .addReg(FramePtr); + // Insert: G1+%lo(offset) into the user. + MI.getOperand(FIOperandNum).ChangeToRegister(SP::G1, false); + MI.getOperand(FIOperandNum + 1).ChangeToImmediate(0); +} + + +void +SparcRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, unsigned FIOperandNum, + RegScavenger *RS) const { + assert(SPAdj == 0 && "Unexpected"); + + MachineInstr &MI = *II; + DebugLoc dl = MI.getDebugLoc(); + int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); + + // Addressable stack objects are accessed using neg. offsets from %fp + MachineFunction &MF = *MI.getParent()->getParent(); + int64_t Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) + + MI.getOperand(FIOperandNum + 1).getImm() + + Subtarget.getStackPointerBias(); + SparcMachineFunctionInfo *FuncInfo = MF.getInfo(); + unsigned FramePtr = SP::I6; + if (FuncInfo->isLeafProc()) { + // Use %sp and adjust offset if needed. + FramePtr = SP::O6; + int stackSize = MF.getFrameInfo()->getStackSize(); + Offset += (stackSize) ? Subtarget.getAdjustedFrameSize(stackSize) : 0 ; + } + + if (!Subtarget.isV9() || !Subtarget.hasHardQuad()) { + if (MI.getOpcode() == SP::STQFri) { + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + unsigned SrcReg = MI.getOperand(2).getReg(); + unsigned SrcEvenReg = getSubReg(SrcReg, SP::sub_even64); + unsigned SrcOddReg = getSubReg(SrcReg, SP::sub_odd64); + MachineInstr *StMI = + BuildMI(*MI.getParent(), II, dl, TII.get(SP::STDFri)) + .addReg(FramePtr).addImm(0).addReg(SrcEvenReg); + replaceFI(MF, II, *StMI, dl, 0, Offset, FramePtr); + MI.setDesc(TII.get(SP::STDFri)); + MI.getOperand(2).setReg(SrcOddReg); + Offset += 8; + } else if (MI.getOpcode() == SP::LDQFri) { + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + unsigned DestReg = MI.getOperand(0).getReg(); + unsigned DestEvenReg = getSubReg(DestReg, SP::sub_even64); + unsigned DestOddReg = getSubReg(DestReg, SP::sub_odd64); + MachineInstr *StMI = + BuildMI(*MI.getParent(), II, dl, TII.get(SP::LDDFri), DestEvenReg) + .addReg(FramePtr).addImm(0); + replaceFI(MF, II, *StMI, dl, 1, Offset, FramePtr); + + MI.setDesc(TII.get(SP::LDDFri)); + MI.getOperand(0).setReg(DestOddReg); + Offset += 8; + } + } + + replaceFI(MF, II, MI, dl, FIOperandNum, Offset, FramePtr); + +} + +unsigned SparcRegisterInfo::getFrameRegister(const MachineFunction &MF) const { + return SP::I6; +} +#endif + diff --git a/lib/Target/WDC65816/WDC65816RegisterInfo.h b/lib/Target/WDC65816/WDC65816RegisterInfo.h new file mode 100644 index 00000000..81d927a0 --- /dev/null +++ b/lib/Target/WDC65816/WDC65816RegisterInfo.h @@ -0,0 +1,55 @@ +//===- WDC65816RegisterInfo.h - WDC65816 Register Information Impl -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the WDC65816 implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef WDC65816REGISTERINFO_H +#define WDC65816REGISTERINFO_H + +#include "llvm/Target/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "WDC65816GenRegisterInfo.inc" + +namespace llvm { + + class TargetInstrInfo; + class Type; + + struct WDC65816RegisterInfo : public WDC65816GenRegisterInfo { + + WDC65816RegisterInfo(void); + + /// Code Generation virtual methods... + const uint16_t *getCalleeSavedRegs(const MachineFunction *MF = 0) const; + const uint32_t* getCallPreservedMask(CallingConv::ID CC) const; + + const uint32_t* getRTCallPreservedMask(CallingConv::ID CC) const; + + BitVector getReservedRegs(const MachineFunction &MF) const; + + const TargetRegisterClass *getPointerRegClass(const MachineFunction &MF, + unsigned Kind) const; + + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, unsigned FIOperandNum, + RegScavenger *RS = NULL) const; + + void processFunctionBeforeFrameFinalized(MachineFunction &MF, + RegScavenger *RS = NULL) const; + + // Debug information queries. + unsigned getFrameRegister(const MachineFunction &MF) const; + }; + +} // end namespace llvm + +#endif diff --git a/lib/Target/WDC65816/WDC65816RegisterInfo.td b/lib/Target/WDC65816/WDC65816RegisterInfo.td index 74b23d39..265cc4b6 100644 --- a/lib/Target/WDC65816/WDC65816RegisterInfo.td +++ b/lib/Target/WDC65816/WDC65816RegisterInfo.td @@ -1,4 +1,4 @@ -//===- WDC65816RegisterInfo.td - WDC65816 Register defs ----------*- tablegen -*-===// +//===- WDC65816RegisterInfo.td - WDC65816 Register defs ----*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -21,8 +21,12 @@ let Namespace = "WDC" in { def K : Register<"K">; def B : Register<"B">; def PC : Register<"PC">; + def FP : Register<"FP">; // WDC_TODO - this will end up being a 32-bit zero page value } +// WDC_TODO - model all zero page values as a series of 16-bit, 32-bit, 64-bit registers +// Also model them as floating point registers. + def IntRegs : RegisterClass<"WDC", [i16], 8, (add A, X, Y)>; diff --git a/lib/Target/WDC65816/WDC65816SelectionDAGInfo.cpp b/lib/Target/WDC65816/WDC65816SelectionDAGInfo.cpp new file mode 100644 index 00000000..3599fdc6 --- /dev/null +++ b/lib/Target/WDC65816/WDC65816SelectionDAGInfo.cpp @@ -0,0 +1,23 @@ +//===- WDC65816SelectionDAGInfo.cpp - WDC 65816 SelectionDAG Info ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the WDC65816SelectionDAGInfo class. +// +//===----------------------------------------------------------------------===// + +//#define DEBUG_TYPE "sparc-selectiondag-info" +#include "WDC65816TargetMachine.h" +using namespace llvm; + +WDC65816SelectionDAGInfo::WDC65816SelectionDAGInfo(const WDC65816TargetMachine &TM) +: TargetSelectionDAGInfo(TM) { +} + +WDC65816SelectionDAGInfo::~WDC65816SelectionDAGInfo() { +} diff --git a/lib/Target/WDC65816/WDC65816SelectionDAGInfo.h b/lib/Target/WDC65816/WDC65816SelectionDAGInfo.h new file mode 100644 index 00000000..b082e185 --- /dev/null +++ b/lib/Target/WDC65816/WDC65816SelectionDAGInfo.h @@ -0,0 +1,31 @@ +//===- WDC65816SelectionDAGInfo.h - WDC 65816 SelectionDAG Info -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the WDC 65816 subclass for TargetSelectionDAGInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef WDC65816SELECTIONDAGINFO_H +#define WDC65816SELECTIONDAGINFO_H + +#include "llvm/Target/TargetSelectionDAGInfo.h" + +namespace llvm { + + class WDC65816TargetMachine; + + class WDC65816SelectionDAGInfo : public TargetSelectionDAGInfo { + public: + explicit WDC65816SelectionDAGInfo(const WDC65816TargetMachine &TM); + ~WDC65816SelectionDAGInfo(); + }; + +} + +#endif diff --git a/lib/Target/WDC65816/WDC65816TargetMachine.cpp b/lib/Target/WDC65816/WDC65816TargetMachine.cpp index 503f6245..79bb2baf 100644 --- a/lib/Target/WDC65816/WDC65816TargetMachine.cpp +++ b/lib/Target/WDC65816/WDC65816TargetMachine.cpp @@ -1,4 +1,4 @@ -//===-- WDC65816TargetMachine.cpp - Define TargetMachine for WDC65816 -----------===// +//===- WDC65816TargetMachine.cpp - Define TargetMachine for WDC65816 ------===// // // The LLVM Compiler Infrastructure // @@ -54,10 +54,6 @@ namespace { }; } // namespace -TargetPassConfig *WDC65816TargetMachine::createPassConfig(PassManagerBase &PM) { - return new WDC65816PassConfig(this, PM); -} - bool WDC65816PassConfig::addInstSelector() { addPass(createWDC65816ISelDag(getWDC65816TargetMachine())); return false; diff --git a/lib/Target/WDC65816/WDC65816TargetMachine.h b/lib/Target/WDC65816/WDC65816TargetMachine.h index c8d4b228..edc359f5 100644 --- a/lib/Target/WDC65816/WDC65816TargetMachine.h +++ b/lib/Target/WDC65816/WDC65816TargetMachine.h @@ -1,4 +1,4 @@ -//===-- WDC65816TargetMachine.h - Define TargetMachine for WDC65816 ---*- C++ -*-===// +//===- WDC65816TargetMachine.h - Define TargetMachine for WDC65816 -*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -25,7 +25,7 @@ namespace llvm { class WDC65816TargetMachine : public LLVMTargetMachine { - // SparcSubtarget Subtarget; JSR_TODO - Do I need this? + // SparcSubtarget Subtarget; WDC_TODO - Do I need this? const DataLayout DL; // Calculates type size & alignment WDC65816InstrInfo InstrInfo; WDC65816TargetLowering TLInfo; @@ -52,9 +52,11 @@ namespace llvm { } virtual const DataLayout *getDataLayout() const { return &DL; } +#if 0 // WDC_TODO - Do I need this? I think these are both related to JIT // Pass Pipeline Configuration virtual TargetPassConfig *createPassConfig(PassManagerBase &PM); virtual bool addCodeEmitter(PassManagerBase &PM, JITCodeEmitter &JCE); +#endif }; } // end namespace llvm