Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -321,6 +321,7 @@ AMDGPU ARM BPF + Connex Hexagon Lanai Mips Index: include/llvm/ADT/Triple.h =================================================================== --- include/llvm/ADT/Triple.h +++ include/llvm/ADT/Triple.h @@ -53,6 +53,7 @@ avr, // AVR: Atmel AVR microcontroller bpfel, // eBPF or extended BPF or 64-bit BPF (little endian) bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian) + connex, // Connex vector processor hexagon, // Hexagon: hexagon mips, // MIPS: mips, mipsallegrex, mipsr6 mipsel, // MIPSEL: mipsel, mipsallegrexe, mipsr6el Index: include/llvm/CodeGen/SelectionDAG.h =================================================================== --- include/llvm/CodeGen/SelectionDAG.h +++ include/llvm/CodeGen/SelectionDAG.h @@ -270,6 +270,12 @@ uint16_t NextPersistentId = 0; public: + DenseMap *crtNodeMapPtr; + + void SetNodeMap(DenseMap *aCrtNodeMapPtr); + + void UpdateNodeMapSDValue(SDNode *oldSDN, SDValue &newSDV); + /// Clients of various APIs that cause global effects on /// the DAG can optionally implement this interface. This allows the clients /// to handle the various sorts of updates that happen. @@ -1217,6 +1223,12 @@ MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT, SDValue Op1, SDValue Op2, SDValue Op3); MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT, + SDValue Op1, SDValue Op2, + SDValue Op3, SDValue Op4); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, SDValue Op1, SDValue Op2, + SDValue Op3, SDValue Op4); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT, ArrayRef Ops); MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, EVT VT2, SDValue Op1, SDValue Op2); Index: include/llvm/CodeGen/SelectionDAGISel.h =================================================================== --- include/llvm/CodeGen/SelectionDAGISel.h +++ include/llvm/CodeGen/SelectionDAGISel.h @@ -56,6 +56,7 @@ const TargetLowering *TLI; bool FastISelFailed; SmallPtrSet ElidedArgCopyInstrs; + DenseMap crtNodeMap; /// Current optimization remark emitter. /// Used to report things like combines and FastISel failures. Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -1182,6 +1182,7 @@ include "llvm/IR/IntrinsicsMips.td" include "llvm/IR/IntrinsicsAMDGPU.td" include "llvm/IR/IntrinsicsBPF.td" +include "llvm/IR/IntrinsicsConnex.td" include "llvm/IR/IntrinsicsSystemZ.td" include "llvm/IR/IntrinsicsWebAssembly.td" include "llvm/IR/IntrinsicsRISCV.td" Index: include/llvm/IR/IntrinsicsConnex.td =================================================================== --- include/llvm/IR/IntrinsicsConnex.td +++ include/llvm/IR/IntrinsicsConnex.td @@ -0,0 +1,106 @@ +//===- IntrinsicsConnex.td - Defines Connex-S intrinsics ---*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines all of the Connex-specific intrinsics. +// +//===----------------------------------------------------------------------===// + +// All Connex-S vector processor intrinsics start with "llvm.connex." +// +let TargetPrefix = "connex" in { + + /* + * Note: all intrinsics defined in these .td files start with + * the int_ prefix (from intrinsic). For this file they start with + * int_connex prefix - otherwise we get the following TableGen error + * <> + * + * The LLVM IR intrinsics extend the LLVM language s.t. we can use + * these instructions in an LLVM IR program. We also need to define the + * corresponding assembly instructions in the back end TableGen files. + */ + + /* Alex: following Intrinsics.td: + class Intrinsic ret_types, + list param_types = [], + list properties = [], + string name = ""> + */ + + + /* Small-note: + llvm_i64_ty makes simpler my LLVM IR generation in the LoopVectorize.cpp + module: + def int_connex_repeat_x_times : Intrinsic<[], [llvm_i64_ty], []>; + But llvm_i32_ty is in accordance to the original i32 type of n.vec in the + LoopVectorize.cpp module: + def int_connex_repeat_x_times : Intrinsic<[], [llvm_i32_ty], []>; + + Small-note: We get inspired from include/llvm/IR/IntrinsicsPowerPC.td: + // Intrinsics used to generate ctrl-based loops. + def int_ppc_mtctr : Intrinsic<[], [llvm_anyint_ty], []>; + + Small-note: Trying to use a polymorphic definition, which requires + specifying the actual type in Function::Create(FunctionType::get(), ...) + is: + def int_connex_repeat_x_times : Intrinsic<[], [llvm_anyint_ty], []>; + When instantiating it in LoopVectorize.cpp like this: + Value *instrinsicFunc = Intrinsic::getDeclaration(M, + Intrinsic::connex_repeat_x_times); + it gives error at runtime: + llvm::ArrayRef::operator[](size_t) const [with T = llvm::Type*; + size_t = long unsigned int]: Assertion `Index < Length && + "Invalid index!"' failed. + */ + def int_connex_repeat_x_times : Intrinsic<[], [llvm_i64_ty], []>; + def int_connex_end_repeat : Intrinsic<[], [], []>; + + /* Note: Possibly useful in the future. + Connex Opincaa's END_REPEAT does not have a relative offset, + as the standard Connex assembly ijmpnzdec instruction, + since it falls on Opincaa to compute the jump back relative offset. + We can also use a setlc to position it outside the loop created by the + ijmpnzdec instruction by using it inside a delay-slot instruction. + + def int_connex_setlc : Intrinsic<[], [llvm_i16_ty], []>; + def int_connex_ijmpnzdec : Intrinsic<[], [], []>; + */ + + + + /* IMPORTANT: REDUCE cannot return a value. It is the duty of the host (CPU) + to read the result itself from the REDUCE issued by Connex-S. + Therefore this definition is incorrect: + def int_connex_reduce : Intrinsic<[llvm_i32_ty], [llvm_v128i16_ty], []>; + */ + /* GOOD: + def int_connex_reduce : Intrinsic<[], [llvm_v128i16_ty], []>; + def int_connex_reduce_i32 : Intrinsic<[], [llvm_v64i32_ty], []>; + def int_connex_reduce_f16 : Intrinsic<[], [llvm_v128f16_ty], []>; + */ + def int_connex_reduce : Intrinsic<[], [llvm_anyvector_ty], []>; + + /* Note: ctpop is already defined in Intrinsics.td. + So the below definition is not required: + def int_connex_ctpop : Intrinsic<[llvm_v8i16_ty], + [llvm_v8i16_ty], []>; + */ + + + // Inherited BPF scalar intrinsics: Specialized loads from packet + def int_connex_load_byte : GCCBuiltin<"__builtin_connex_load_byte">, + Intrinsic<[llvm_i64_ty], [llvm_ptr_ty, llvm_i64_ty], [IntrReadMem]>; + def int_connex_load_half : GCCBuiltin<"__builtin_connex_load_half">, + Intrinsic<[llvm_i64_ty], [llvm_ptr_ty, llvm_i64_ty], [IntrReadMem]>; + def int_connex_load_word : GCCBuiltin<"__builtin_connex_load_word">, + Intrinsic<[llvm_i64_ty], [llvm_ptr_ty, llvm_i64_ty], [IntrReadMem]>; + def int_connex_pseudo : GCCBuiltin<"__builtin_connex_pseudo">, + Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty]>; +} + Index: lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -1469,6 +1469,9 @@ LLVM_DEBUG(dbgs() << " ... into: "; RV.getNode()->dump(&DAG)); + // Replacing SDNode N with RV in crtNodeMap + DAG.UpdateNodeMapSDValue(N, RV); + if (N->getNumValues() == RV.getNode()->getNumValues()) DAG.ReplaceAllUsesWith(N, RV.getNode()); else { Index: lib/CodeGen/SelectionDAG/SelectionDAG.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -82,6 +82,33 @@ return Res; } +void SelectionDAG::SetNodeMap(DenseMap *aCrtNodeMapPtr) { + crtNodeMapPtr = aCrtNodeMapPtr; +} + +void SelectionDAG::UpdateNodeMapSDValue(SDNode *oldSDN, SDValue &newSDV) { + /* NOTE: SelectionDAGBuilder defines DenseMap NodeMap. + * I added in SelectionDAGISel a copy of it, crtNodeMap. + * The pointer crtNodeMapPtr here is the pointer of crtNodeMap + * initialized in SelectionDAGISel::CodeGenAndEmitDAG(). + */ + for (auto iterNodeMap = crtNodeMapPtr->begin(); + iterNodeMap != crtNodeMapPtr->end(); iterNodeMap++) { + auto tmp1 = (*iterNodeMap); + + const Value *crtValue = (const Value *)(tmp1.first); + + SDValue crtSDValue = tmp1.second; + SDNode *crtSDNode = crtSDValue.getNode(); + + if (crtSDNode == oldSDN) { + (*crtNodeMapPtr)[crtValue] = newSDV; + break; + } + } +} + + // Default null implementations of the callbacks. void SelectionDAG::DAGUpdateListener::NodeDeleted(SDNode*, SDNode*) {} void SelectionDAG::DAGUpdateListener::NodeUpdated(SDNode*) {} @@ -7803,6 +7830,24 @@ } MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &dl, + EVT VT, + SDValue Op1, SDValue Op2, + SDValue Op3, SDValue Op4) { + SDVTList VTs = getVTList(VT); + SDValue Ops[] = { Op1, Op2, Op3, Op4 }; + return getMachineNode(Opcode, dl, VTs, Ops); +} + +MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &dl, + EVT VT1, EVT VT2, + SDValue Op1, SDValue Op2, + SDValue Op3, SDValue Op4) { + SDVTList VTs = getVTList(VT1, VT2); + SDValue Ops[] = { Op1, Op2, Op3, Op4 }; + return getMachineNode(Opcode, dl, VTs, Ops); +} + +MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, EVT VT2, EVT VT3, ArrayRef Ops) { SDVTList VTs = getVTList(VT1, VT2, VT3); Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -38,6 +38,7 @@ #include #include #include +#include "llvm/Support/Debug.h" namespace llvm { @@ -125,6 +126,11 @@ MapVector DanglingDebugInfoMap; public: + // Add a getter for NodeMap + DenseMap &getNodeMap() { + return NodeMap; + } + /// Loads are not emitted to the program immediately. We bunch them up and /// then emit token factor nodes when possible. This allows us to get simple /// disambiguation between loads without worrying about alias analysis. Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -9090,8 +9090,15 @@ void TargetLowering::LowerOperationWrapper(SDNode *N, SmallVectorImpl &Results, SelectionDAG &DAG) const { - if (SDValue Res = LowerOperation(SDValue(N, 0), DAG)) - Results.push_back(Res); + SDValue Res1 = LowerOperation(SDValue(N, 0), DAG); + if (Res1.getNode()) + Results.push_back(Res1); + + if (N->getNumValues() > 1) { + SDValue Res2 = LowerOperation(SDValue(N, 1), DAG); + if (Res2.getNode()) + Results.push_back(Res2); + } } SDValue TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -692,6 +692,9 @@ CurDAG->setRoot(SDB->getControlRoot()); HadTailCall = SDB->HasTailCall; SDB->resolveOrClearDbgInfo(); + + crtNodeMap = SDB->getNodeMap(); + SDB->clear(); // Final step, emit the lowered DAG as machine code. @@ -778,6 +781,9 @@ // Run the DAG combiner in pre-legalize mode. { + // We should do this only once + CurDAG->SetNodeMap(&crtNodeMap); + NamedRegionTimer T("combine1", "DAG Combining 1", GroupName, GroupDescription, TimePassesIsEnabled); CurDAG->Combine(BeforeLegalizeTypes, AA, OptLevel); Index: lib/Target/Connex/Connex.h =================================================================== --- lib/Target/Connex/Connex.h +++ lib/Target/Connex/Connex.h @@ -0,0 +1,31 @@ +//===-- Connex.h - Top-level interface for Connex representation ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_CONNEX_CONNEX_H +#define LLVM_LIB_TARGET_CONNEX_CONNEX_H + +#include "MCTargetDesc/ConnexMCTargetDesc.h" +#include "llvm/Target/TargetMachine.h" + + +// We define reserved register(s) of Connex to use for: +// - handling COPY instructions in WHERE blocks +// (see ConnexTargetMachine.cpp and ConnexISelLowering.cpp), etc +#define CONNEX_RESERVED_REGISTER_01 Connex::Wh30 +#define CONNEX_RESERVED_REGISTER_02 Connex::Wh31 +#define CONNEX_RESERVED_REGISTER_03 Connex::Wh29 + +#define COPY_REGISTER_IMPLEMENTED_WITH_ORV_H + +namespace llvm { +class ConnexTargetMachine; + +FunctionPass *createConnexISelDag(ConnexTargetMachine &TM); +} + +#endif Index: lib/Target/Connex/Connex.td =================================================================== --- lib/Target/Connex/Connex.td +++ lib/Target/Connex/Connex.td @@ -0,0 +1,64 @@ +//===-- Connex.td - Describe the Connex Target Machine -----------*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + + + + + + + + + + + + + +include "ConnexRegisterInfo.td" +include "ConnexCallingConv.td" + +include "ConnexSchedule.td" + +include "ConnexInstrInfo.td" + + +def ConnexInstrInfo : InstrInfo; + + + + +class Proc Features> + : Processor; + +def : Proc<"generic", []>; + +def ConnexInstPrinter : AsmWriter { + string AsmWriterClassName = "InstPrinter"; + bit isMCAsmWriter = 1; +} + +// Inspired from https://github.com/llvm-mirror/llvm/commit/5ef1349 +// (see also https://groups.google.com/forum/#!topic/llvm-dev/_Zr4Oe5MLkE) +def ConnexAsmParser : AsmParser { + bit HasMnemonicFirst = 0; +} + +def ConnexAsmParserVariant : AsmParserVariant { + int Variant = 0; + string Name = "Connex"; + string BreakCharacters = "."; +} + +def Connex : Target { + let InstructionSet = ConnexInstrInfo; + let AssemblyWriters = [ConnexInstPrinter]; + // Inspired from llvm/lib/Target/Hexagon/Hexagon.td + let AssemblyParsers = [ConnexAsmParser]; + let AssemblyParserVariants = [ConnexAsmParserVariant]; +} Index: lib/Target/Connex/ConnexInstrFormats.td =================================================================== --- lib/Target/Connex/ConnexInstrFormats.td +++ lib/Target/Connex/ConnexInstrFormats.td @@ -0,0 +1,274 @@ +//===-- ConnexInstrFormats.td - Connex Instruction Formats -------*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +class InstConnex pattern> + : Instruction { + field bits<64> Inst; + field bits<64> SoftFail = 0; + let Size = 8; + + let Namespace = "Connex"; + let DecoderNamespace = "Connex"; + + bits<3> ConnexClass; + let Inst{58-56} = ConnexClass; + + dag OutOperandList = outs; + dag InOperandList = ins; + let AsmString = asmstr; + let Pattern = pattern; +} + +// Pseudo instructions +class Pseudo pattern> + : InstConnex { + let Inst{63-0} = 0; + let isPseudo = 1; +} + + + + + +// Inspired from book "Getting started with LLVM Core Libraries", 2014, page 141 + + + + + +// Inspired from SparcInstrFormats.td: + + +class NonImmediateInstruction opcode, dag outs, dag ins, + string asmstr, list pattern> + : Instruction { + field bits<32> Inst; + let Inst{31-23} = opcode; + + // We require to put the Namespace field, otherwise we receive: + // "error:No instructions defined!" + let Namespace = "Connex"; + let DecoderNamespace = "Connex"; + + dag OutOperandList = outs; + dag InOperandList = ins; + let AsmString = asmstr; + let Pattern = pattern; +} + + +class ImmediateInstruction opcode, dag outs, dag ins, string asmstr, + list pattern> + : Instruction { + field bits<32> Inst; + let Inst{31-26} = opcode; + + let Namespace = "Connex"; + let DecoderNamespace = "Connex"; + + dag OutOperandList = outs; + dag InOperandList = ins; + let AsmString = asmstr; + let Pattern = pattern; +} + + + + + + + +// From Mips.td +// The overall idea of the PredicateControl class is to chop the Predicates list +// into subsets that are usually overridden independently. This allows +// subclasses to partially override the predicates of their superclasses without +// having to re-add all the existing predicates. +class PredicateControl { + // Predicates for the encoding scheme in use such as HasStdEnc + list EncodingPredicates = []; + // Predicates for the GPR size such as IsGP64bit + list GPRPredicates = []; + // Predicates for the FGR size and layout such as IsFP64bit + list FGRPredicates = []; + // Predicates for the instruction group membership such as ISA's and ASE's + list InsnPredicates = []; + // Predicate for marking the instruction as usable in hard-float mode only. + list HardFloatPredicate = []; + // Predicates for anything else + list AdditionalPredicates = []; + list Predicates = !listconcat(EncodingPredicates, + GPRPredicates, + FGRPredicates, + InsnPredicates, + HardFloatPredicate, + AdditionalPredicates); +} + + +// From lib/Target/Mips/MipsInstrFormats.td +// Format specifies the encoding used by the instruction. This is part of the +// ad-hoc solution used to emit machine instruction encodings by our machine +// code emitter. +class Format val> { + bits<4> Value = val; +} + +def FrmOther : Format<6>; // Instruction w/ a custom format + +class MipsInst pattern, + InstrItinClass itin, Format f>: Instruction +{ + field bits<32> Inst; + Format Form = f; + + //let Namespace = "Mips"; + let Namespace = "Connex"; + + let Size = 4; + + bits<6> Opcode = 0; + + // Top 6 bits are the 'opcode' field + let Inst{31-26} = Opcode; + + let OutOperandList = outs; + let InOperandList = ins; + + let AsmString = asmstr; + let Pattern = pattern; + let Itinerary = itin; + + // + // Attributes specific to Mips instructions... + // + bits<4> FormBits = Form.Value; + + // TSFlags layout should be kept in sync with MipsInstrInfo.h. + let TSFlags{3-0} = FormBits; + + //let DecoderNamespace = "Mips"; + let DecoderNamespace = "Connex"; + + field bits<32> SoftFail = 0; +} + +// From lib/Target/Mips/MipsInstrInfo.td +def HasStdEnc : Predicate<"true">, // Alex: !!!! TODO TODO TODO: Predicate<"Subtarget->hasStandardEncoding()">, + AssemblerPredicate<"!FeatureMips16">; + +def HasMSA : Predicate<"true">, // Alex: !!!! TODO TODO TODO Subtarget->hasMSA()">, + AssemblerPredicate<"FeatureMSA">; + +// From lib/Target/Mips/MipsMSAInstrFormats.td: +class MSAInst : MipsInst<(outs), (ins), "", [], NoItinerary, FrmOther>, +// PredicateControl, ASE_MSA { + PredicateControl { + //let EncodingPredicates = [HasStdEnc]; + let Inst{31-26} = 0b011110; +} + +class MSA_2R_FMT opcode>: MSAInst { + bits<5> ws; + bits<5> wd; + + let Inst{31-23} = opcode; + + let Namespace = "Connex"; + let DecoderNamespace = "Connex"; + + //let Inst{25-10} = immVal; + let Inst{9-5} = ws; + let Inst{4-0} = wd; +} + +class MSA_RR_FMT opcode>: MSAInst { + bits<5> ws1; + bits<5> ws2; + + let Inst{31-23} = opcode; + + let Namespace = "Connex"; + let DecoderNamespace = "Connex"; + + //let Inst{25-10} = immVal; + let Inst{9-5} = ws1; + let Inst{4-0} = ws2; +} + +class MSA_3R_FMT opcode>: MSAInst { + bits<5> wt; + bits<5> ws; + bits<5> wd; + + let Inst{31-23} = opcode; + + let Namespace = "Connex"; + + let DecoderNamespace = "Connex"; + + let Inst{14-10} = wt; + let Inst{9-5} = ws; + let Inst{4-0} = wd; +} + +class MSA_I5_FMT major, bits<2> df, bits<6> minor>: MSAInst { + bits<5> imm; + bits<5> ws; + bits<5> wd; + + let Inst{25-23} = major; + let Inst{22-21} = df; + let Inst{20-16} = imm; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + + +class MSA_LDIX_LDSH_MULT_H_DESC_BASE { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins); + //string AsmString = !strconcat(instr_asm, "\t$wd ; // MSA_I10"); + //string AsmString = "$wd = INDEX ; // MSA_I10"; + string AsmString = !strconcat(!strconcat("$wd = ", instr_asm), + " ; // MSA_LDIX_LDSH_MULT"); + // Note: LDI is matched using custom matching code in MipsSEISelDAGToDAG.cpp + list Pattern = []; + + bit hasSideEffects = 1; // We need to put this since we don't specify a DAG pattern in Pattern + InstrItinClass Itinerary = itin; +} + +class MSA_RR_PREFIX_DESC_BASE { + dag OutOperandList = (outs); + dag InOperandList = (ins ROWS:$ws1, ROWS:$ws2); + string AsmString = !strconcat(instr_asm, " ( $ws1, $ws2 ); // MSA_RR generic instruction"); + list Pattern = []; + + bit hasSideEffects = 1; + + InstrItinClass Itinerary = itin; +} + +class MSA_RR_INFIX_DESC_BASE { + dag OutOperandList = (outs); + dag InOperandList = (ins ROWS:$ws1, ROWS:$ws2); + string AsmString = !strconcat( !strconcat("$ws1 ", instr_asm), " $ws2 ; // MSA_RR_INFIX instruction"); + list Pattern = []; + + bit hasSideEffects = 1; + + InstrItinClass Itinerary = itin; +} + Index: lib/Target/Connex/ConnexInstrInfo.td =================================================================== --- lib/Target/Connex/ConnexInstrInfo.td +++ lib/Target/Connex/ConnexInstrInfo.td @@ -0,0 +1,22 @@ +//===-- ConnexInstrInfo.td - Target Description for Connex Target ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file describes the Connex instructions in TableGen format. +// +//===----------------------------------------------------------------------===// + +include "ConnexInstrFormats.td" + +include "ConnexInstrInfoVec.td" + + + + + +include "ConnexInstrInfoScalar.td" + Index: lib/Target/Connex/ConnexInstrInfoScalar.td =================================================================== --- lib/Target/Connex/ConnexInstrInfoScalar.td +++ lib/Target/Connex/ConnexInstrInfoScalar.td @@ -0,0 +1,598 @@ +//===-- ConnexInstrInfoScalar.td - Scalar Target Description for Connex Target --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file describes the Connex scalar instructions in TableGen format. +// It basically implements the BPF ISA. +// +//===----------------------------------------------------------------------===// + +// Instruction Operands and Patterns (64 bits operands BPF) + +// These are target-independent nodes, but have target-specific formats. +def SDT_ConnexCallSeqStart : SDCallSeqStart<[SDTCisVT<0, iPTR>, + SDTCisVT<1, iPTR>]>; +def SDT_ConnexCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, iPTR>, SDTCisVT<1, iPTR>]>; +def SDT_ConnexCall : SDTypeProfile<0, -1, [SDTCisVT<0, iPTR>]>; +def SDT_ConnexSetFlag : SDTypeProfile<0, 3, [SDTCisSameAs<0, 1>]>; +def SDT_ConnexSelectCC : SDTypeProfile<1, 5, [SDTCisSameAs<1, 2>, + SDTCisSameAs<0, 4>, + SDTCisSameAs<4, 5>]>; +def SDT_ConnexBrCC : SDTypeProfile<0, 4, [SDTCisSameAs<0, 1>, + SDTCisVT<3, OtherVT>]>; +def SDT_ConnexWrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, + SDTCisPtrTy<0>]>; + +def Connexcall : SDNode<"ConnexISD::CALL", SDT_ConnexCall, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, + SDNPVariadic]>; +def Connexretflag : SDNode<"ConnexISD::RET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; +def Connexcallseq_start: SDNode<"ISD::CALLSEQ_START", SDT_ConnexCallSeqStart, + [SDNPHasChain, SDNPOutGlue]>; +def Connexcallseq_end : SDNode<"ISD::CALLSEQ_END", SDT_ConnexCallSeqEnd, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; +def Connexbrcc : SDNode<"ConnexISD::BR_CC", SDT_ConnexBrCC, + [SDNPHasChain, SDNPOutGlue, SDNPInGlue]>; + +def Connexselectcc : SDNode<"ConnexISD::SELECT_CC", SDT_ConnexSelectCC, [SDNPInGlue]>; +def ConnexWrapper : SDNode<"ConnexISD::Wrapper", SDT_ConnexWrapper>; + +def brtarget : Operand; +def calltarget : Operand; + +def u64imm : Operand { + let PrintMethod = "printImm64Operand"; +} + +/* Alex: added type qualifier i64 to avoid error + "Could not infer all types in pattern!" - type ambiguity since the + variable name ("in dag operator") does not have a type and this poses + issues to the Type inference algorithm, since I added in + ConnexRegisterInfo.td a second RegisterClass with type v128i16... (or v8i64) +*/ +//def i64immSExt32 : PatLeaf<(imm), +def i64immSExt32 : PatLeaf<(i64 imm), + [{return isInt<32>(N->getSExtValue()); }]>; + +// Addressing modes. +def ADDRri : ComplexPattern; +def FIri : ComplexPattern; + +// Address operands +def MEMri : Operand { + let PrintMethod = "printMemOperand"; + let EncoderMethod = "getMemoryOpValue"; + let MIOperandInfo = (ops GPR, i16imm); +} + + +// Alex: added type qualifier i64 to avoid error "Could not infer all types in pattern!" - type ambiguity since the variable name ("in dag operator") does not have a type and this poses issues to the Type inference algorithm, since I added in ConnexRegisterInfo.td a second RegisterClass with type v2i64) +// Conditional code predicates - used for pattern matching for jump instructions +def Connex_CC_EQ : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETEQ);}]>; +def Connex_CC_NE : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETNE);}]>; +def Connex_CC_GE : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETGE);}]>; +def Connex_CC_GT : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETGT);}]>; +def Connex_CC_GTU : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETUGT);}]>; +def Connex_CC_GEU : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETUGE);}]>; + +// jump instructions +class JMP_RR Opc, string OpcodeStr, PatLeaf Cond> + : InstConnex<(outs), (ins GPR:$dst, GPR:$src, brtarget:$BrDst), + !strconcat(OpcodeStr, "\t$dst, $src goto $BrDst"), + [(Connexbrcc i64:$dst, i64:$src, Cond, bb:$BrDst)]> { + bits<4> op; + bits<1> ConnexSrc; + bits<4> dst; + bits<4> src; + bits<16> BrDst; + + let Inst{63-60} = op; + let Inst{59} = ConnexSrc; + let Inst{55-52} = src; + let Inst{51-48} = dst; + let Inst{47-32} = BrDst; + + let op = Opc; + let ConnexSrc = 1; + let ConnexClass = 5; // Connex_JMP +} + +class JMP_RI Opc, string OpcodeStr, PatLeaf Cond> + : InstConnex<(outs), (ins GPR:$dst, i64imm:$imm, brtarget:$BrDst), + !strconcat(OpcodeStr, "i\t$dst, $imm goto $BrDst"), + [(Connexbrcc i64:$dst, i64immSExt32:$imm, Cond, bb:$BrDst)]> { + bits<4> op; + bits<1> ConnexSrc; + bits<4> dst; + bits<16> BrDst; + bits<32> imm; + + let Inst{63-60} = op; + let Inst{59} = ConnexSrc; + let Inst{51-48} = dst; + let Inst{47-32} = BrDst; + let Inst{31-0} = imm; + + let op = Opc; + let ConnexSrc = 0; + let ConnexClass = 5; // Connex_JMP +} + +// Alex: commented out original code: multiclass J Opc, string OpcodeStr, PatLeaf Cond> { +// Alex: gives error multiclass J Opc, string OpcodeStr, PatFrag Cond> { // error: Value 'JMP_RR:Cond' of type 'PatLeaf' is incompatible with initializer 'J::Cond' +multiclass J Opc, string OpcodeStr, PatLeaf Cond> { + def _rr : JMP_RR; + def _ri : JMP_RI; +} + +let isBranch = 1, isTerminator = 1, hasDelaySlot=0 in { +// cmp+goto instructions +defm JEQ : J<0x1, "jeq", Connex_CC_EQ>; +defm JUGT : J<0x2, "jgt", Connex_CC_GTU>; +defm JUGE : J<0x3, "jge", Connex_CC_GEU>; +defm JNE : J<0x5, "jne", Connex_CC_NE>; +defm JSGT : J<0x6, "jsgt", Connex_CC_GT>; +defm JSGE : J<0x7, "jsge", Connex_CC_GE>; +} + +// Inspired from def : Pat<(f32 (load addr:$src)), (LDRAM addr:$src)>; +//Pat<(f32 (load addr:$src)), (JEQ_ri addr:$src)>; + +// ALU instructions +class ALU_RI Opc, string OpcodeStr, SDNode OpNode> + : InstConnex<(outs GPR:$dst), (ins GPR:$src2, i64imm:$imm), + !strconcat(OpcodeStr, "i\t$dst, $imm"), + [(set GPR:$dst, (OpNode GPR:$src2, i64immSExt32:$imm))]> { + //[(set GPR:$dst, (OpNode GPR:$src2, (i64 i64immSExt32:$imm)))]> { + bits<4> op; + bits<1> ConnexSrc; + bits<4> dst; + bits<32> imm; + + let Inst{63-60} = op; + let Inst{59} = ConnexSrc; + let Inst{51-48} = dst; + let Inst{31-0} = imm; + + let op = Opc; + let ConnexSrc = 0; + let ConnexClass = 7; // Connex_ALU64 +} +/* +// Alex: gives TableGen error: <> +def : Pat<(v8i64 i64immSExt32:$imm), (ALU_RI i64imm:$imm)>; +*/ + +class ALU_RR Opc, string OpcodeStr, SDNode OpNode> + : InstConnex<(outs GPR:$dst), (ins GPR:$src2, GPR:$src), + !strconcat(OpcodeStr, "\t$dst, $src"), + [(set GPR:$dst, (OpNode i64:$src2, i64:$src))]> { + bits<4> op; + bits<1> ConnexSrc; + bits<4> dst; + bits<4> src; + + let Inst{63-60} = op; + let Inst{59} = ConnexSrc; + let Inst{55-52} = src; + let Inst{51-48} = dst; + + let op = Opc; + let ConnexSrc = 1; + let ConnexClass = 7; // Connex_ALU64 +} + +multiclass ALU Opc, string OpcodeStr, SDNode OpNode> { + def _rr : ALU_RR; + def _ri : ALU_RI; +} + +let Constraints = "$dst = $src2" in { +let isAsCheapAsAMove = 1 in { + defm ADD : ALU<0x0, "add", add>; + defm SUB : ALU<0x1, "sub", sub>; + defm OR : ALU<0x4, "or", or>; + defm AND : ALU<0x5, "and", and>; + defm SLL : ALU<0x6, "sll", shl>; + defm SRL : ALU<0x7, "srl", srl>; + defm XOR : ALU<0xa, "xor", xor>; + defm SRA : ALU<0xc, "sra", sra>; +} + defm MUL : ALU<0x2, "mul", mul>; + defm DIV : ALU<0x3, "div", udiv>; +} + +class MOV_RR + : InstConnex<(outs GPR:$dst), (ins GPR:$src), + !strconcat(OpcodeStr, "\t$dst, $src"), + []> { + bits<4> op; + bits<1> ConnexSrc; + bits<4> dst; + bits<4> src; + + let Inst{63-60} = op; + let Inst{59} = ConnexSrc; + let Inst{55-52} = src; + let Inst{51-48} = dst; + + let op = 0xb; // Connex_MOV + let ConnexSrc = 1; // Connex_X + let ConnexClass = 7; // Connex_ALU64 +} + +class MOV_RI + : InstConnex<(outs GPR:$dst), (ins i64imm:$imm), + !strconcat(OpcodeStr, "\t$dst, $imm"), + [(set GPR:$dst, (i64 i64immSExt32:$imm))]> { + bits<4> op; + bits<1> ConnexSrc; + bits<4> dst; + bits<32> imm; + + let Inst{63-60} = op; + let Inst{59} = ConnexSrc; + let Inst{51-48} = dst; + let Inst{31-0} = imm; + + let op = 0xb; // Connex_MOV + let ConnexSrc = 0; // Connex_K + let ConnexClass = 7; // Connex_ALU64 +} + +class LD_IMM64 Pseudo, string OpcodeStr> + : InstConnex<(outs GPR:$dst), (ins u64imm:$imm), + !strconcat(OpcodeStr, "\t$dst, $imm"), + [(set GPR:$dst, (i64 imm:$imm))]> { + + bits<3> mode; + bits<2> size; + bits<4> dst; + bits<64> imm; + + let Inst{63-61} = mode; + let Inst{60-59} = size; + let Inst{51-48} = dst; + let Inst{55-52} = Pseudo; + let Inst{47-32} = 0; + let Inst{31-0} = imm{31-0}; + + let mode = 0; // Connex_IMM + let size = 3; // Connex_DW + let ConnexClass = 0; // Connex_LD +} + +let isReMaterializable = 1, isAsCheapAsAMove = 1 in { +def LD_imm64 : LD_IMM64<0, "ld_64">; +def MOV_rr : MOV_RR<"mov">; +def MOV_ri : MOV_RI<"mov">; +} + +def FI_ri + : InstConnex<(outs GPR:$dst), (ins MEMri:$addr), + "lea\t$dst, $addr", + [(set i64:$dst, FIri:$addr)]> { + // This is a tentative instruction, and will be replaced + // with MOV_rr and ADD_ri in PEI phase +} + + +def LD_pseudo + : InstConnex<(outs GPR:$dst), (ins i64imm:$pseudo, u64imm:$imm), + "ld_pseudo\t$dst, $pseudo, $imm", + [(set GPR:$dst, (int_connex_pseudo imm:$pseudo, imm:$imm))]> { + + bits<3> mode; + bits<2> size; + bits<4> dst; + bits<64> imm; + bits<4> pseudo; + + let Inst{63-61} = mode; + let Inst{60-59} = size; + let Inst{51-48} = dst; + let Inst{55-52} = pseudo; + let Inst{47-32} = 0; + let Inst{31-0} = imm{31-0}; + + let mode = 0; // Connex_IMM + let size = 3; // Connex_DW + let ConnexClass = 0; // Connex_LD +} + +// STORE instructions +class STORE SizeOp, string OpcodeStr, list Pattern> + : InstConnex<(outs), (ins GPR:$src, MEMri:$addr), + !strconcat(OpcodeStr, "\t$addr, $src"), Pattern> { + bits<3> mode; + bits<2> size; + bits<4> src; + bits<20> addr; + + let Inst{63-61} = mode; + let Inst{60-59} = size; + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = src; + let Inst{47-32} = addr{15-0}; // offset + + let mode = 3; // Connex_MEM + let size = SizeOp; + let ConnexClass = 3; // Connex_STX +} + +class STOREi64 Opc, string OpcodeStr, PatFrag OpNode> + // Alex: commented out (original) + : STORE; + // Alex: does NOT help to use GPR instead of i64 : STORE; + +def STW : STOREi64<0x0, "stw", truncstorei32>; +def STH : STOREi64<0x1, "sth", truncstorei16>; +def STB : STOREi64<0x2, "stb", truncstorei8>; +def STD : STOREi64<0x3, "std", store>; + +// LOAD instructions +class LOAD SizeOp, string OpcodeStr, list Pattern> + : InstConnex<(outs GPR:$dst), (ins MEMri:$addr), + !strconcat(OpcodeStr, "\t$dst, $addr"), Pattern> { + bits<3> mode; + bits<2> size; + bits<4> dst; + bits<20> addr; + + let Inst{63-61} = mode; + let Inst{60-59} = size; + let Inst{51-48} = dst; + let Inst{55-52} = addr{19-16}; + let Inst{47-32} = addr{15-0}; + + let mode = 3; // Connex_MEM + let size = SizeOp; + let ConnexClass = 1; // Connex_LDX +} + +class LOADi64 SizeOp, string OpcodeStr, PatFrag OpNode> + : LOAD; + +def LDW : LOADi64<0x0, "ldw", zextloadi32>; +def LDH : LOADi64<0x1, "ldh", zextloadi16>; +def LDB : LOADi64<0x2, "ldb", zextloadi8>; +def LDD : LOADi64<0x3, "ldd", load>; + +class BRANCH Opc, string OpcodeStr, list Pattern> + : InstConnex<(outs), (ins brtarget:$BrDst), + !strconcat(OpcodeStr, "\t$BrDst"), Pattern> { + bits<4> op; + bits<16> BrDst; + bits<1> ConnexSrc; + + let Inst{63-60} = op; + let Inst{59} = ConnexSrc; + let Inst{47-32} = BrDst; + + let op = Opc; + let ConnexSrc = 0; + let ConnexClass = 5; // Connex_JMP +} + +class CALL + : InstConnex<(outs), (ins calltarget:$BrDst), + !strconcat(OpcodeStr, "\t$BrDst"), []> { + bits<4> op; + bits<32> BrDst; + bits<1> ConnexSrc; + + let Inst{63-60} = op; + let Inst{59} = ConnexSrc; + let Inst{31-0} = BrDst; + + let op = 8; // Connex_CALL + let ConnexSrc = 0; + let ConnexClass = 5; // Connex_JMP +} + +// Jump always +let isBranch = 1, isTerminator = 1, hasDelaySlot=0, isBarrier = 1 in { + def JMP : BRANCH<0x0, "jmp", [(br bb:$BrDst)]>; +} + +// Jump and link +let isCall=1, hasDelaySlot=0, Uses = [R11], + // Potentially clobbered registers + Defs = [R0, R1, R2, R3, R4, R5] in { + def JAL : CALL<"call">; +} + +class NOP_I + : InstConnex<(outs), (ins i32imm:$imm), + //!strconcat(OpcodeStr, "\t$imm ; // scalar or vector NOP"), []> { + !strconcat(OpcodeStr, " ; // (immOperand = $imm ) scalar or vector NOP"), []> { + // mov r0, r0 == nop + bits<4> op; + bits<1> ConnexSrc; + bits<4> dst; + bits<4> src; + + let Inst{63-60} = op; + let Inst{59} = ConnexSrc; + let Inst{55-52} = src; + let Inst{51-48} = dst; + + let op = 0xb; // Connex_MOV + let ConnexSrc = 1; // Connex_X + let ConnexClass = 7; // Connex_ALU64 + let src = 0; // R0 + let dst = 0; // R0 +} + +//let hasSideEffects = 0 in +let hasSideEffects = 1 in // Alex: If we manually generate NOP (for delay slots) it means we want to keep it, otherwise we should NOT have it generated (hasSideEffects - The instruction has side effects that are not captured by any operands of the instruction or other flags.) + def NOP_BPF : NOP_I<"NOP">; + + +class RET + : InstConnex<(outs), (ins), + !strconcat(OpcodeStr, ""), [(Connexretflag)]> { + bits<4> op; + + let Inst{63-60} = op; + let Inst{59} = 0; + let Inst{31-0} = 0; + + let op = 9; // Connex_EXIT + let ConnexClass = 5; // Connex_JMP +} + +let isReturn = 1, isTerminator = 1, hasDelaySlot=0, isBarrier = 1, + isNotDuplicable = 1 in { + def RET : RET<"ret">; +} + +// ADJCALLSTACKDOWN/UP pseudo insns +let Defs = [R11], Uses = [R11], isCodeGenOnly = 1 in { +def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i64imm:$amt1, i64imm:$amt2), + "#ADJCALLSTACKDOWN $amt1 $amt2", + [(Connexcallseq_start timm:$amt1, timm:$amt2)]>; +def ADJCALLSTACKUP : Pseudo<(outs), (ins i64imm:$amt1, i64imm:$amt2), + "#ADJCALLSTACKUP $amt1 $amt2", + [(Connexcallseq_end timm:$amt1, timm:$amt2)]>; +} + +let usesCustomInserter = 1 in { + def Select : Pseudo<(outs GPR:$dst), + (ins GPR:$lhs, GPR:$rhs, i64imm:$imm, GPR:$src, GPR:$src2), + "# Select PSEUDO $dst = $lhs $imm $rhs ? $src : $src2", + [(set i64:$dst, + (Connexselectcc i64:$lhs, i64:$rhs, (i64 imm:$imm), i64:$src, i64:$src2))]>; +} + +// load 64-bit global addr into register +def : Pat<(ConnexWrapper tglobaladdr:$in), (LD_imm64 tglobaladdr:$in)>; + +// 0xffffFFFF doesn't fit into simm32, optimize common case +def : Pat<(i64 (and (i64 GPR:$src), 0xffffFFFF)), + (SRL_ri (SLL_ri (i64 GPR:$src), 32), 32)>; + +// Calls +def : Pat<(Connexcall tglobaladdr:$dst), (JAL tglobaladdr:$dst)>; +def : Pat<(Connexcall imm:$dst), (JAL imm:$dst)>; + +// Loads +def : Pat<(extloadi8 ADDRri:$src), (i64 (LDB ADDRri:$src))>; +def : Pat<(extloadi16 ADDRri:$src), (i64 (LDH ADDRri:$src))>; +def : Pat<(extloadi32 ADDRri:$src), (i64 (LDW ADDRri:$src))>; + +// Atomics +class XADD SizeOp, string OpcodeStr, PatFrag OpNode> + : InstConnex<(outs GPR:$dst), (ins MEMri:$addr, GPR:$val), + !strconcat(OpcodeStr, "\t$dst, $addr, $val"), + [(set GPR:$dst, (OpNode ADDRri:$addr, GPR:$val))]> { + bits<3> mode; + bits<2> size; + bits<4> src; + bits<20> addr; + + let Inst{63-61} = mode; + let Inst{60-59} = size; + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = src; + let Inst{47-32} = addr{15-0}; // offset + + let mode = 6; // Connex_XADD + let size = SizeOp; + let ConnexClass = 3; // Connex_STX +} + +let Constraints = "$dst = $val" in { +def XADD32 : XADD<0, "xadd32", atomic_load_add_32>; +def XADD64 : XADD<3, "xadd64", atomic_load_add_64>; +// undefined def XADD16 : XADD<1, "xadd16", atomic_load_add_16>; +// undefined def XADD8 : XADD<2, "xadd8", atomic_load_add_8>; +} + +// bswap16, bswap32, bswap64 +class BSWAP SizeOp, string OpcodeStr, list Pattern> + : InstConnex<(outs GPR:$dst), (ins GPR:$src), + !strconcat(OpcodeStr, "\t$dst"), + Pattern> { + bits<4> op; + bits<1> ConnexSrc; + bits<4> dst; + bits<32> imm; + + let Inst{63-60} = op; + let Inst{59} = ConnexSrc; + let Inst{51-48} = dst; + let Inst{31-0} = imm; + + let op = 0xd; // Connex_END + let ConnexSrc = 1; // Connex_TO_BE (TODO: use Connex_TO_LE for big-endian target) + let ConnexClass = 4; // Connex_ALU + let imm = SizeOp; +} + +let Constraints = "$dst = $src" in { +def BSWAP16 : BSWAP<16, "bswap16", [(set GPR:$dst, (srl (bswap GPR:$src), (i64 48)))]>; +def BSWAP32 : BSWAP<32, "bswap32", [(set GPR:$dst, (srl (bswap GPR:$src), (i64 32)))]>; +def BSWAP64 : BSWAP<64, "bswap64", [(set GPR:$dst, (bswap GPR:$src))]>; +} + +let Defs = [R0, R1, R2, R3, R4, R5], Uses = [R6], hasSideEffects = 1, + hasExtraDefRegAllocReq = 1, hasExtraSrcRegAllocReq = 1, mayLoad = 1 in { +class LOAD_ABS SizeOp, string OpcodeStr, Intrinsic OpNode> + : InstConnex<(outs), (ins GPR:$skb, i64imm:$imm), + !strconcat(OpcodeStr, "\tr0, $skb.data + $imm"), + [(set R0, (OpNode GPR:$skb, i64immSExt32:$imm))]> { + //[(set R0, (OpNode GPR:$skb, (i64immSExt32:$imm)))]> { + bits<3> mode; + bits<2> size; + bits<32> imm; + + let Inst{63-61} = mode; + let Inst{60-59} = size; + let Inst{31-0} = imm; + + let mode = 1; // Connex_ABS + let size = SizeOp; + let ConnexClass = 0; // Connex_LD +} + +class LOAD_IND SizeOp, string OpcodeStr, Intrinsic OpNode> + : InstConnex<(outs), (ins GPR:$skb, GPR:$val), + !strconcat(OpcodeStr, "\tr0, $skb.data + $val"), + [(set R0, (OpNode GPR:$skb, GPR:$val))]> { + bits<3> mode; + bits<2> size; + bits<4> val; + + let Inst{63-61} = mode; + let Inst{60-59} = size; + let Inst{55-52} = val; + + let mode = 2; // Connex_IND + let size = SizeOp; + let ConnexClass = 0; // Connex_LD +} +} + +def LD_ABS_B : LOAD_ABS<2, "ldabs_b", int_connex_load_byte>; +def LD_ABS_H : LOAD_ABS<1, "ldabs_h", int_connex_load_half>; +def LD_ABS_W : LOAD_ABS<0, "ldabs_w", int_connex_load_word>; + +def LD_IND_B : LOAD_IND<2, "ldind_b", int_connex_load_byte>; +def LD_IND_H : LOAD_IND<1, "ldind_h", int_connex_load_half>; +def LD_IND_W : LOAD_IND<0, "ldind_w", int_connex_load_word>; + + + + Index: lib/Target/Connex/ConnexInstrInfoVec.td =================================================================== --- lib/Target/Connex/ConnexInstrInfoVec.td +++ lib/Target/Connex/ConnexInstrInfoVec.td @@ -0,0 +1,875 @@ +//===-- ConnexInstrInfoVec.td - Scalar Target Description for Connex Target --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file describes the Connex-S vector instructions in TableGen format. +// The ISA is described in ConnexISA.pdf. +// +//===----------------------------------------------------------------------===// + + + + +class MSA_1R_FMT opcode>: MSAInst { + bits<5> ws; + + let Inst{31-23} = opcode; + + let Namespace = "Connex"; + let DecoderNamespace = "Connex"; + + let Inst{9-5} = ws; +} + +// From include/llvm/IR/IntrinsicsConnex.td: +// def int_connex_reduce : Intrinsic<[], [llvm_anyvector_ty], []>; +class RED_1R_DESC_BASE { + dag OutOperandList = (outs); + dag InOperandList = (ins ROWS:$ws); + string AsmString = !strconcat(instr_asm, + " $ws ; // MSA_1R generic instruction"); + list Pattern = [(int_connex_reduce ROWS:$ws)]; + bit hasSideEffects = 1; + InstrItinClass Itinerary = itin; +} +class RED_H_DESC : RED_1R_DESC_BASE<"RED", MSA128HOpnd>; +class RED_H_ENC : MSA_1R_FMT<0b101010110>; +def RED_H: RED_H_ENC, RED_H_DESC; + + +// IMPORTANT NOTE: RED_U, unsigned reduction, is only used for manual/custom ISel +class RED_U_1R_DESC_BASE { + dag OutOperandList = (outs); + dag InOperandList = (ins ROWS:$ws); + string AsmString = !strconcat(instr_asm, + " $ws ; // MSA_1R generic instruction"); + list Pattern = []; + bit hasSideEffects = 1; + InstrItinClass Itinerary = itin; +} +class RED_U_H_DESC : RED_U_1R_DESC_BASE<"RED_U", MSA128HOpnd>; +class RED_U_H_ENC : MSA_1R_FMT<0b101010111>; +def RED_U_H: RED_U_H_ENC, RED_U_H_DESC; + + + + + + +let hasSideEffects = 1 in // Inspired from MSP430InstrInfo.td +def NOP : NonImmediateInstruction<0b000000000, (outs), (ins), + "NOP; // NOP : NonImmediateInstruction", []>; + +// NEW32 +class NOP_BITCONVERT_DESC_BASE { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws); + // NOT working because of strange concatenation done by TableGen: string AsmString = !strconcat("// 'NOP' used for vector bitconvert $ws -> $wd", AsmStrInfo); + string AsmString = !strconcat("// 'NOP' used for vector bitconvert $ws -> $wd . ", AsmStrInfo); + list Pattern = []; + + // Inspired from include/llvm/Target/Target.td: + // <> + string Constraints = "$ws = $wd"; + + //bit hasSideEffects = 1; // We need to put this since we don't specify a DAG pattern in Pattern + InstrItinClass Itinerary = itin; +} +class NOP_BITCONVERT_ENC : MSA_2R_FMT<0b101010110>; // MSAInst; // TODO: add encoding; //MSA_1R_FMT<0b101010110>; +class NOP_BITCONVERT_HW_DESC : NOP_BITCONVERT_DESC_BASE<"v8i16 to v4i32", MSA128HOpnd, MSA128HOpnd>; +def NOP_BITCONVERT_HW: NOP_BITCONVERT_ENC, NOP_BITCONVERT_HW_DESC; +// +class NOP_BITCONVERT_WH_DESC : NOP_BITCONVERT_DESC_BASE<"v4i32 to v8i16", MSA128HOpnd, MSA128HOpnd>; +def NOP_BITCONVERT_WH: NOP_BITCONVERT_ENC, NOP_BITCONVERT_WH_DESC; +// +class NOP_BITCONVERT_HH_DESC : NOP_BITCONVERT_DESC_BASE<"v8i16 to v8i16", MSA128HOpnd, MSA128HOpnd>; +def NOP_BITCONVERT_HH: NOP_BITCONVERT_ENC, NOP_BITCONVERT_HH_DESC; + + +class NOP_BOGUS_DESC_BASE { + dag OutOperandList = (outs); + dag InOperandList = (ins); + string AsmString = "// 'NOP' used for ConnexInstrInfo::copyPhysReg()"; + list Pattern = []; + + // We need to put this normally since we don't specify a DAG pattern in Pattern + //bit hasSideEffects = 1; + InstrItinClass Itinerary = itin; +} +class NOP_BOGUS_ENC : MSAInst; // TODO: add encoding; +def NOP_BOGUS: NOP_BOGUS_ENC, NOP_BOGUS_DESC_BASE; + + +/* +// IMPORTANT: NOT good because it seems ISel is CSEing nodes of this type. + +// This is to avoid initializing registers in Select*_OpincaaCodeGen.cpp +class NOP_BOGUS_INIT_DESC_BASE< + RegisterOperand ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins); + string AsmString = "// NOP_BOGUS_INIT_DESC_BASE (wd = $wd )"; + list Pattern = []; + + // We need to put this since we don't specify a DAG pattern in Pattern + bit hasSideEffects = 1; + + InstrItinClass Itinerary = itin; +} +class NOP_BOGUS_INIT_DESC : NOP_BOGUS_INIT_DESC_BASE; +class NOP_BOGUS_INIT_ENC : MSAInst; // TODO: add encoding; +def NOP_BOGUS_INIT: NOP_BOGUS_INIT_ENC, NOP_BOGUS_INIT_DESC; +*/ + +class NOP_SPECIAL_DESC_BASE { + dag OutOperandList = (outs ROWD_TIED:$wdTied); + dag InOperandList = (ins ROWS:$ws); + string AsmString = "NOP ; // NOP_SPECIAL_DESC_BASE (ws = $ws, wdTied = $wdTied )"; + list Pattern = []; + + string Constraints = "$ws = $wdTied"; + + bit hasSideEffects = 1; // We need to put this since we don't specify a DAG pattern in Pattern + + InstrItinClass Itinerary = itin; +} +class NOP_SPECIAL_DESC : NOP_SPECIAL_DESC_BASE; +class NOP_SPECIAL_ENC : MSAInst; // TODO: add encoding; //MSA_1R_FMT<0b101010110>; +def NOP_SPECIAL: NOP_SPECIAL_ENC, NOP_SPECIAL_DESC; + + + + + + + + +// From MipsMSAInstrInfo.td +class IsCommutable { + bit isCommutable = 1; +} + + + +class MSA_2R_DESC_BASE { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws); + //string AsmString = !strconcat(instr_asm, "\t$wd, $ws"); + // ALEX_INFIX_NOTATION: + string AsmString = !strconcat("$wd = ", !strconcat(instr_asm, " $ws ; // MSA_2R generic instruction")); + list Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws))]; + InstrItinClass Itinerary = itin; +} + + +class MSA_3R_DESC_BASE { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, ROWT:$wt); + //string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $wt"); + // ALEX_INFIX_NOTATION: + string AsmString = !strconcat("$wd = $ws ", !strconcat(instr_asm, " $wt ; // MSA_3R generic instruction")); + list Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, ROWT:$wt))]; + InstrItinClass Itinerary = itin; +} + +class MSA_3R_PREFIX_DESC_BASE { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, ROWT:$wt); + string AsmString = !strconcat(!strconcat("$wd = ", instr_asm), "( $ws , $wt ) ; // MSA_3R_PREFIX generic instruction"); + list Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, ROWT:$wt))]; + //bit hasSideEffects = 1; + InstrItinClass Itinerary = itin; +} + +class MUL_3R_DESC_BASE { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, ROWT:$wt); + // IMPORTANT NOTE: we write in string "( $wt )" to be parsed properly + string AsmString = !strconcat("$ws * ( $wt ); ", "$wd = MULTLO(); // MUL_3R"); + // TODO: MAYBE return also the high 32 bits + list Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, ROWT:$wt))]; + InstrItinClass Itinerary = itin; +} + + + + + + + + + + + +include "ConnexInstrInfoVec_READ_WRITE.td" +include "ConnexInstrInfoVec_REPEAT.td" + + + + +// These are taken from Mips MipsMSAInstrInfo.td. +// See also http://llvm.org/docs/LangRef.html#shl-instruction +class SHLV_H_DESC : MSA_3R_DESC_BASE<"<<", shl, MSA128HOpnd>; +class SHLV_H_ENC : MSA_3R_FMT<0b111100101>; //; +def SHLV_H : SHLV_H_ENC, SHLV_H_DESC; + +// srl is defined in [LLVM]/llvm/include/llvm/Target/TargetSelectionDAG.td +class SHRV_H_DESC : MSA_3R_DESC_BASE<">>", srl, MSA128HOpnd>; +class SHRV_H_ENC : MSA_3R_FMT<0b111110101>; //; +def SHRV_H : SHRV_H_ENC, SHRV_H_DESC; + + + + +// sra is defined in [LLVM]/llvm/include/llvm/Target/TargetSelectionDAG.td +class SHRAV_H_DESC : MSA_3R_PREFIX_DESC_BASE<"SHRA", sra, MSA128HOpnd>; +class SHRAV_H_ENC : MSA_3R_FMT<0b111111101>; //; +def SHRAV_H : SHRAV_H_ENC, SHRAV_H_DESC; + + + +/* +!!!! !!!! !!!! !!!!TODO: To optimize xor var, -1 to not + [REPO]/llvm/build30/bin/TestNot.ll + %neg = xor i32 %0, -1 + From http://llvm.org/docs/LangRef.html#xor-instruction: + <> + << = xor i32 %V, -1 ; yields i32:result = ~%V >> + + Myabe we should start from: + https://github.com/llvm-mirror/llvm/blob/master/lib/CodeGen/SelectionDAG/DAGCombiner.cpp + // Canonicalize (sub -1, x) -> ~x, i.e. (xor x, -1) + + See also http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20100215/096325.html + (not relevant I guess http://lists.llvm.org/pipermail/llvm-dev/2011-July/041884.html) + + From https://groups.google.com/forum/#!msg/llvm-dev/C3fd9OxBFrg/SA8BYziWwbkJ : + > + > I also would like to see why the "XOR A, -1" is not turned into a NOT, any + > + Probably because NOT (like NEG) doesn't exist :) + + + + I assume the decision was made that it wasn't worth adding the extra + unary instructions when they can easily be handled in codegen by + matching "XOR X, -1" or "SUB 0, X". + + ~ Scott +*/ +// Inspired from [LLVM]/llvm/lib/Target/Mips/MipsMSAInstrInfo.td, from: class NLZC_D_DESC : MSA_2R_DESC_BASE<"nlzc.d", ctlz, MSA128DOpnd>; +class NOT_H_DESC : MSA_2R_DESC_BASE<"~", not, MSA128HOpnd>; +class NOT_H_ENC : MSA_2R_FMT<0b110000111>; // 0b11000011, 0b11, 0b011110>; +def NOT_H : NOT_H_ENC, NOT_H_DESC; + +class ORV_H_DESC : MSA_3R_DESC_BASE<"|", or, MSA128HOpnd>, IsCommutable; +class ORV_H_ENC : MSA_3R_FMT<0b111111101>; //; +def ORV_H : ORV_H_ENC, ORV_H_DESC; + +class ANDV_H_DESC : MSA_3R_DESC_BASE<"&", and, MSA128HOpnd>, IsCommutable; +class ANDV_H_ENC : MSA_3R_FMT<0b111111101>; //; +def ANDV_H : ANDV_H_ENC, ANDV_H_DESC; + +class XORV_H_DESC : MSA_3R_DESC_BASE<"^", xor, MSA128HOpnd>, IsCommutable; +class XORV_H_ENC : MSA_3R_FMT<0b111111101>; //; +def XORV_H : XORV_H_ENC, XORV_H_DESC; + +// Using ctpop intrinsic - just like llvm/lib/Target/AArch64/AArch64InstrInfo.td +class POPCNT_H_DESC : MSA_2R_DESC_BASE<"POPCNT", ctpop, MSA128HOpnd>; +class POPCNT_H_ENC : MSA_2R_FMT<0b110010111>; // 0b11000011, 0b11, 0b011110>; +def POPCNT_H : POPCNT_H_ENC, POPCNT_H_DESC; + + + + +class MSA_2R_SPECIAL_DESC_BASE { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, ROWS_TIED:$wsTied); + // ALEX_INFIX_NOTATION: + string AsmString = !strconcat("$wd = ", !strconcat(instr_asm, " $ws ; // MSA_2R_SPECIAL generic instruction (wsTied = $wsTied )") ); + //list Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, ROWT:$wt))]; + list Pattern = []; + + // Inspired from include/llvm/Target/Target.td: + // <> + string Constraints = "$wd = $wsTied"; + + // We need to put this since we don't specify a DAG pattern in Pattern + bit hasSideEffects = 1; + + InstrItinClass Itinerary = itin; +} + +class MSA_3R_SPECIAL_PREFIX_DESC_BASE { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, ROWT:$wt, ROWS_TIED:$wsTied); + string AsmString = !strconcat("$wd = ", + !strconcat(instr_asm, + "($ws, $wt ) ; // MSA_3R_SPECIAL generic instruction (wsTied = $wsTied )") ); + list Pattern = []; + + // Inspired from include/llvm/Target/Target.td: + // <> + string Constraints = "$wd = $wsTied"; + + // We need to put this since we don't specify a DAG pattern in Pattern + bit hasSideEffects = 1; + + InstrItinClass Itinerary = itin; +} + +class MSA_3R_SPECIAL_DESC_BASE { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, ROWT:$wt, ROWS_TIED:$wsTied); + // ALEX_INFIX_NOTATION: + string AsmString = !strconcat("$wd = $ws ", + !strconcat(instr_asm, + " $wt ; // MSA_3R_SPECIAL generic instruction (wsTied = $wsTied )") ); + list Pattern = []; + + // Inspired from llvm/include/llvm/Target/Target.td: + // <> + string Constraints = "$wd = $wsTied"; + + // We need to put this since we don't specify a DAG pattern in Pattern + bit hasSideEffects = 1; + + InstrItinClass Itinerary = itin; +} + +class MSA_3R_PREFIX_SPECIAL_DESC_BASE { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, ROWT:$wt, ROWS_TIED:$wsTied); + string AsmString = !strconcat( + !strconcat("$wd = ", instr_asm), + "( $ws , $wt ) ; // MSA_3R_PREFIX_SPECIAL generic instruction (wsTied = $wsTied )" ); + list Pattern = []; + + string Constraints = "$wd = $wsTied"; + + // We need to put this to prevent llc (SelectionDAG, DAGCombiner, MachineCSE) + // to apply CSE and other optimizations on the predicated instructions + bit hasSideEffects = 1; + + InstrItinClass Itinerary = itin; +} + +class SHLV_SPECIAL_H_DESC : MSA_3R_SPECIAL_DESC_BASE<"<<", shl, MSA128HOpnd>; +class SHLV_SPECIAL_H_ENC : MSA_3R_FMT<0b110111101>; +def SHLV_SPECIAL_H : SHLV_SPECIAL_H_ENC, SHLV_SPECIAL_H_DESC; + +class SHRV_SPECIAL_H_DESC : MSA_3R_SPECIAL_DESC_BASE<">>", srl, MSA128HOpnd>; +class SHRV_SPECIAL_H_ENC : MSA_3R_FMT<0b110111101>; +def SHRV_SPECIAL_H : SHRV_SPECIAL_H_ENC, SHRV_SPECIAL_H_DESC; + +class SHRAV_SPECIAL_H_DESC : MSA_3R_PREFIX_SPECIAL_DESC_BASE<"SHRA", sra, MSA128HOpnd>; +class SHRAV_SPECIAL_H_ENC : MSA_3R_FMT<0b110101101>; //; +def SHRAV_SPECIAL_H : SHRAV_SPECIAL_H_ENC, SHRAV_SPECIAL_H_DESC; + + +// We use ORV_SPECIAL_H for codegen of VSELECT +class ORV_SPECIAL_H_DESC : MSA_3R_SPECIAL_DESC_BASE<"|", or, MSA128HOpnd>, IsCommutable; +class ORV_SPECIAL_H_ENC : MSA_3R_FMT<0b111111101>; +def ORV_SPECIAL_H : ORV_SPECIAL_H_ENC, ORV_SPECIAL_H_DESC; + +class ANDV_SPECIAL_H_DESC : MSA_3R_SPECIAL_DESC_BASE<"&", and, MSA128HOpnd>, IsCommutable; +class ANDV_SPECIAL_H_ENC : MSA_3R_FMT<0b111111101>; +def ANDV_SPECIAL_H : ANDV_SPECIAL_H_ENC, ANDV_SPECIAL_H_DESC; + +class XORV_SPECIAL_H_DESC : MSA_3R_SPECIAL_DESC_BASE<"^", xor, MSA128HOpnd>, IsCommutable; +class XORV_SPECIAL_H_ENC : MSA_3R_FMT<0b111111101>; +def XORV_SPECIAL_H : XORV_SPECIAL_H_ENC, XORV_SPECIAL_H_DESC; + +class NOT_SPECIAL_H_DESC : MSA_2R_SPECIAL_DESC_BASE<"~", not, MSA128HOpnd>; +class NOT_SPECIAL_H_ENC : MSA_2R_FMT<0b111111101>; +def NOT_SPECIAL_H : NOT_SPECIAL_H_ENC, NOT_SPECIAL_H_DESC; + + +// Using ctpop intrinsic - just like llvm/lib/Target/AArch64/AArch64InstrInfo.td +class POPCNT_SPECIAL_H_DESC : MSA_2R_SPECIAL_DESC_BASE<"POPCNT", ctpop, MSA128HOpnd>; +class POPCNT_SPECIAL_H_ENC : MSA_2R_FMT<0b110010111>; +def POPCNT_SPECIAL_H : POPCNT_SPECIAL_H_ENC, POPCNT_SPECIAL_H_DESC; + + + +class POWER_CELL_H_DESC_BASE { + dag OutOperandList = (outs); + dag InOperandList = (ins); + string AsmString = !strconcat(instr_asm, "; // POWER_CELL_H_DESC "); + list Pattern = []; + + bit hasSideEffects = 1; + InstrItinClass Itinerary = itin; +} +class DISABLE_CELL_H_DESC : POWER_CELL_H_DESC_BASE<"DISABLE_CELL">; +class DISABLE_CELL_H_ENC : MSAInst; // TODO: add encoding +def DISABLE_CELL_H: DISABLE_CELL_H_ENC, DISABLE_CELL_H_DESC; +// +class ENABLE_ALL_CELLS_H_DESC : POWER_CELL_H_DESC_BASE<"ENABLE_ALL_CELLS">; +class ENABLE_ALL_CELLS_H_ENC : MSAInst; // TODO: add encoding +def ENABLE_ALL_CELLS_H: ENABLE_ALL_CELLS_H_ENC, ENABLE_ALL_CELLS_H_DESC; + + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + + + + + + + + +include "ConnexInstrInfoVec_vsetcc_vselect.td" +include "ConnexInstrInfoVec_Operands.td" +include "ConnexInstrInfoVec_vsplat.td" +include "ConnexInstrInfoVec_vinsert.td" + + + + + + + + + + + + +// From MipsDSPInstrInfo.td +def immZExt1 : ImmLeaf(Imm);}]>; + + + + +class EQ_H_DESC : MSA_3R_DESC_BASE<"==", vseteq_v128i16, MSA128HOpnd>, IsCommutable; +class EQ_H_ENC : MSA_3R_FMT<0b111111101>; +let isCompare = 1 in // (Is this instruction a comparison instruction?) +// We model the fact it changes the flags of Connex +// (hasSideEffects - The instruction has side effects that are not captured +// by any operands of the instruction or other flags.) +let hasSideEffects = 1 in +def EQ_H : EQ_H_ENC, EQ_H_DESC; + +class LT_H_DESC : MSA_3R_DESC_BASE<"<", setlt, MSA128HOpnd>; +class LT_H_ENC : MSA_3R_FMT<0b111111101>; +let isCompare = 1 in // (Is this instruction a comparison instruction?) +let hasSideEffects = 1 in +def LT_H : LT_H_ENC, LT_H_DESC; + +class ULT_H_DESC : MSA_3R_PREFIX_DESC_BASE<"ULT", setult, MSA128HOpnd>; +class ULT_H_ENC : MSA_3R_FMT<0b111111101>; +let isCompare = 1 in +let hasSideEffects = 1 in +def ULT_H : ULT_H_ENC, ULT_H_DESC; + +class EQ_SPECIAL_H_DESC : MSA_3R_SPECIAL_DESC_BASE<"==", vseteq_v128i16, MSA128HOpnd>, IsCommutable; +class EQ_SPECIAL_H_ENC : MSA_3R_FMT<0b111111101>; +let isCompare = 1 in +let hasSideEffects = 1 in +def EQ_SPECIAL_H : EQ_SPECIAL_H_ENC, EQ_SPECIAL_H_DESC; + +class LT_SPECIAL_H_DESC : MSA_3R_SPECIAL_DESC_BASE<"<", vsetlt_v128i16, MSA128HOpnd>; +class LT_SPECIAL_H_ENC : MSA_3R_FMT<0b111111101>; +let isCompare = 1 in +let hasSideEffects = 1 in +def LT_SPECIAL_H : LT_SPECIAL_H_ENC, LT_SPECIAL_H_DESC; + +class ULT_SPECIAL_H_DESC : MSA_3R_SPECIAL_PREFIX_DESC_BASE<"ULT", vsetult_v128i16, MSA128HOpnd>; +class ULT_SPECIAL_H_ENC : MSA_3R_FMT<0b111111101>; +let isCompare = 1 in +let hasSideEffects = 1 in +def ULT_SPECIAL_H : ULT_SPECIAL_H_ENC, ULT_SPECIAL_H_DESC; + + + + + + +include "ConnexInstrInfoVec_VLOAD_LDIX_LDSH.td" +/* +// Putting VLOAD before LOAD (LD_DESC...) does not help for selecting +// BUILD_VECTOR inlib/Target/Connex/ConnexInstrInfo_vec_VLOAD.td +include "ConnexInstrInfo_vec_VLOAD.td" +*/ + + + + +// Note: add is defined in [LLVM]/llvm/include/llvm/Target/TargetSelectionDAG.td +class ADDV_H_DESC : MSA_3R_DESC_BASE<"+", add, MSA128HOpnd>, IsCommutable; +class ADDV_H_ENC : MSA_3R_FMT<0b101000101>; +def ADDV_H : ADDV_H_ENC, ADDV_H_DESC; + +class ADDV_SPECIAL_H_DESC : MSA_3R_SPECIAL_DESC_BASE<"+", add, MSA128HOpnd>, IsCommutable; +class ADDV_SPECIAL_H_ENC : MSA_3R_FMT<0b101000101>; +def ADDV_SPECIAL_H : ADDV_SPECIAL_H_ENC, ADDV_SPECIAL_H_DESC; + + +/* +The ADDC, SUBC can experience NOT coming immediately after ADD and SUB, respectively, + even if we make ADDC take a MVT::Glue result from ADD (this is not guaranteeing + us to have ADDC coming immediately after ADD). + In fact ADD can be scheduled after ADDC by the post-RA scheduler + ("********** List Scheduling **********") - see + DawnCC/35_MatMul_i32/2/STDerr_llc_01; + (a solution would be to disable running the post-RA scheduler pass, + but this is not desirable). +Therefore, we add for ADDC and SUBC one more input, coming from ADD and SUB, + respectively - in order to make (at least) ADDC come after ADD. However, not + even this should not guarantee that ADDC comes immediately after ADD as it + should to preserve the Carry flags. +*/ +class MSA_3R_PREFIX_CARRY_DESC_BASE { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, ROWT:$wt, ROWS_CARRY:$wsCarry); + string AsmString = !strconcat( + !strconcat("$wd = ", instr_asm), + "( $ws , $wt ) ; // MSA_3R prefix Carry instruction (wsCarry = $wsCarry ) "); + list Pattern = []; + + bit hasSideEffects = 1; // We need to put this since we don't specify a DAG pattern in Pattern + InstrItinClass Itinerary = itin; +} +class ADDCV_H_DESC : MSA_3R_PREFIX_CARRY_DESC_BASE<"ADDC", MSA128HOpnd>, IsCommutable; +class ADDCV_H_ENC : MSA_3R_FMT<0b101110101>; +def ADDCV_H : ADDCV_H_ENC, ADDCV_H_DESC; + +class SUBCV_H_DESC : MSA_3R_PREFIX_CARRY_DESC_BASE<"SUBC", MSA128HOpnd>; +class SUBCV_H_ENC : MSA_3R_FMT<0b101110101>; +def SUBCV_H : SUBCV_H_ENC, SUBCV_H_DESC; + + + + + + + +// Similarly as for MSA_3R_PREFIX_CARRY_DESC_BASE we also +// take the result of the instruction before that sets the Carry flags. +class MSA_3R_PREFIX_CARRY_SPECIAL_DESC_BASE { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, ROWT:$wt, ROWS_CARRY:$wsCarry, ROWD_TIED:$wdTied); + string AsmString = !strconcat( + !strconcat("$wd = ", instr_asm), + "( $ws , $wt ) ; // MSA_3R prefix Carry special instruction (wsCarry = $wsCarry and wdTied = $wdTied ) "); + list Pattern = []; + + string Constraints = "$wd = $wdTied"; // Inspired from llvm/include/llvm/Target/Target.td: <> + + // We need to put this since we don't specify a DAG pattern in Pattern + bit hasSideEffects = 1; + InstrItinClass Itinerary = itin; +} +class SUBCV_SPECIAL_H_DESC : MSA_3R_PREFIX_CARRY_SPECIAL_DESC_BASE<"SUBC", MSA128HOpnd>; +class SUBCV_SPECIAL_H_ENC : MSA_3R_FMT<0b101110101>; +def SUBCV_SPECIAL_H : SUBCV_SPECIAL_H_ENC, SUBCV_SPECIAL_H_DESC; +// +class ADDCV_SPECIAL_H_DESC : MSA_3R_PREFIX_CARRY_SPECIAL_DESC_BASE<"ADDC", MSA128HOpnd>, IsCommutable; +class ADDCV_SPECIAL_H_ENC : MSA_3R_FMT<0b101110101>; +def ADDCV_SPECIAL_H : ADDCV_SPECIAL_H_ENC, ADDCV_SPECIAL_H_DESC; + + + + + + +class SUBV_H_DESC : MSA_3R_DESC_BASE<"-", sub, MSA128HOpnd>; +class SUBV_H_ENC : MSA_3R_FMT<0b101000101>; +def SUBV_H : SUBV_H_ENC, SUBV_H_DESC; + +class SUBV_SPECIAL_H_DESC : MSA_3R_SPECIAL_DESC_BASE<"-", sub, MSA128HOpnd>; +def SUBV_SPECIAL_H : SUBV_H_ENC, SUBV_SPECIAL_H_DESC; + + + + + +/* IMPORTANT: + This generic i16 multiplication with destination is actually NOT a Connex + instruction, but we use it to match the ISD::MUL automatically with + TableGen, since it is simpler like this. + MULV is multiplication with src1, src2 and dst + (actually it has 2 Connex instructions) + + Note that we specify below also the Connex assembly instructions for multiplication. +*/ +class MUL3RV_H_DESC : MUL_3R_DESC_BASE<"*", mul, MSA128HOpnd>, IsCommutable; +class MUL3RV_H_ENC : MSA_3R_FMT<0b101000101>; + +def MUL3RV_H : MUL3RV_H_ENC, MUL3RV_H_DESC; + + + + + + +// Now we specify all actual Connex instructions for multiplication +class MULT_H_DESC : MSA_RR_INFIX_DESC_BASE<"*", MSA128HOpnd>, IsCommutable; +class MULT_H_ENC : MSA_2R_FMT<0b010110101>; +def MULT_H : MULT_H_ENC, MULT_H_DESC; + +// IMPORTANT NOTE: MULT_U_H, unsigned multiplication, is only used for manual ISel +// TODO: maybe do also MULT_SPECIAL_H_DESC, MULT_U_SPECIAL_H_DESC +class MULT_U_H_DESC : MSA_RR_PREFIX_DESC_BASE<"MULT_U", MSA128HOpnd>, IsCommutable; +class MULT_U_H_ENC : MSA_2R_FMT<0b010110111>; +def MULT_U_H : MULT_U_H_ENC, MULT_U_H_DESC; + +class MULTLO_H_DESC : MSA_LDIX_LDSH_MULT_H_DESC_BASE<"MULTLO()", MSA128HOpnd>; +class MULTLO_H_ENC : MSA_1R_FMT<0b010110101>; +def MULTLO_H : MULTLO_H_ENC, MULTLO_H_DESC; + +class MULTHI_H_DESC : MSA_LDIX_LDSH_MULT_H_DESC_BASE<"MULTHI()", MSA128HOpnd>; +class MULTHI_H_ENC : MSA_1R_FMT<0b010110101>; +def MULTHI_H : MULTHI_H_ENC, MULTHI_H_DESC; + + + +class MULTLO_SPECIAL_H_DESC : MSA_LDIX_LDSH_MULT_SPECIAL_H_DESC_BASE<"MULTLO()", MSA128HOpnd>; +def MULTLO_SPECIAL_H : MULTLO_H_ENC, MULTLO_SPECIAL_H_DESC; + +class MULTHI_SPECIAL_H_DESC : MSA_LDIX_LDSH_MULT_SPECIAL_H_DESC_BASE<"MULTHI()", MSA128HOpnd>; +def MULTHI_SPECIAL_H : MULTHI_H_ENC, MULTHI_SPECIAL_H_DESC; + + + + + + + + + + + + + + + + + + + + + + + + +let Constraints = "$specialOperandOut = $specialOperandIn" in +let isCodeGenOnly = 1 in +//let hasSideEffects = 1 in +//let isBarrier = 1 in // Can control flow fall through this instruction? +//bit isSelect = 1; // Is this instruction a select instruction? +def END_WHERE_2OPNDS : NonImmediateInstruction<0b100011111, + (outs MSA128HOpnd:$specialOperandOut), + (ins MSA128HOpnd:$specialOperandIn), + "\n); // END_WHERE (NII) \n EXECUTE_IN_ALL( // (specialOperandIn = $specialOperandIn, specialOperandOut = $specialOperandOut) ;", + []>; +// +let isCodeGenOnly = 1 in +let hasSideEffects = 1 in +//let isBarrier = 1 in // Can control flow fall through this instruction? +//bit isSelect = 1; // Is this instruction a select instruction? +def END_WHERE : NonImmediateInstruction<0b100011111, + (outs), + (ins), + "\n); // END_WHERE (NII) \n EXECUTE_IN_ALL( // ;", + []>; + + +let isCodeGenOnly = 1 in // to avoid: <> +let hasSideEffects = 1 in +let isBarrier = 1 in +def WHERECRY : NonImmediateInstruction<0b100011100, + (outs), + (ins), + "\n); // END_EXECUTE_IN_ALL\n EXECUTE_WHERE_CRY( // NII;", + []>; + +let Constraints = "$specialOperandOut = $specialOperandIn" in +// To avoid: <> +let isCodeGenOnly = 1 in +//let hasSideEffects = 1 in +//let isBarrier = 1 in +def WHEREEQ : NonImmediateInstruction<0b100011101, + (outs MSA128HOpnd:$specialOperandOut), + (ins MSA128HOpnd:$specialOperandIn), + "); // END_EXECUTE_IN_ALL\n EXECUTE_WHERE_EQ( // NII (specialOperandIn = $specialOperandIn, specialOperandOut = $specialOperandOut) ;", + []>; + + + + + +let Constraints = "$specialOperandOut = $specialOperandIn" in // Inspired from llvm/include/llvm/Target/Target.td: <> +let isCodeGenOnly = 1 in // to avoid: <> +//let hasSideEffects = 1 in +//let isBarrier = 1 in +def WHERELT : NonImmediateInstruction<0b100011101, + (outs MSA128HOpnd:$specialOperandOut), + (ins MSA128HOpnd:$specialOperandIn), + "); // END_EXECUTE_IN_ALL\n EXECUTE_WHERE_LT( // NII (specialOperandIn = $specialOperandIn, specialOperandOut = $specialOperandOut) ;", + []>; + + + +let Constraints = "$specialOperandOut = $specialOperandIn" in // Inspired from llvm/include/llvm/Target/Target.td: <> +let isCodeGenOnly = 1 in // to avoid: <> +//let hasSideEffects = 1 in +//let isBarrier = 1 in +def WHEREULT : NonImmediateInstruction<0b100011101, + (outs MSA128HOpnd:$specialOperandOut), + (ins MSA128HOpnd:$specialOperandIn), + "); // END_EXECUTE_IN_ALL\n EXECUTE_WHERE_ULT( // NII (specialOperandIn = $specialOperandIn, specialOperandOut = $specialOperandOut) ;", + []>; + + +// Inspired from lib/Target/WebAssembly/WebAssemblyInstrInfo.td +def bb_op : Operand; + + + + + + + + + +// Inspired from [LLVM]/llvm/lib/Target/Mips/MipsMSAInstrInfo.td + +class MSA_3R_DESC_BASE_2STR { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, ROWT:$wt, ROWP:$pred); + // ALEX_INFIX_NOTATION: + string AsmString = instr_asm2; + list Pattern = []; + InstrItinClass Itinerary = itin; +} + +/* OLD: IMPORTANT: WHERE_EQ/LT/CRY has 2 inputs and 1 output because I + lower VSELECT to WHEREEQ_H, which I later use to create a bundle with real + machine instructions to "resist" the post-RA scheduler without changing the + order of the nodes (in ConnexTargetMachine.cpp, passes PassCreateWhereBlocks + and PassFinalizeBundles). */ +class WHEREEQ_BUNDLE_H_ENC : MSA_3R_FMT<0b000110010>; +class WHEREEQ_BUNDLE_H_DESC : MSA_3R_DESC_BASE_2STR<");\n EXECUTE_WHERE_EQ( //;", vseteq_v128i16, MSA128HOpnd>; //, IsCommutable; +// +let isCodeGenOnly = 1 in +let hasSideEffects = 1 in +//let isBarrier = 1 in +//let isPseudo = 1 in +def WHEREEQ_BUNDLE_H : WHEREEQ_BUNDLE_H_ENC, WHEREEQ_BUNDLE_H_DESC; + + + +class WHERELT_BUNDLE_H_ENC : MSA_3R_FMT<0b000110010>; +class WHERELT_BUNDLE_H_DESC : MSA_3R_DESC_BASE_2STR<");\n EXECUTE_WHERE_LT( //;", vsetlt_v128i16, MSA128HOpnd>; //, IsCommutable; +// +let isCodeGenOnly = 1 in +let hasSideEffects = 1 in +//let isBarrier = 1 in +//let isPseudo = 1 in +def WHERELT_BUNDLE_H : WHERELT_BUNDLE_H_ENC, WHERELT_BUNDLE_H_DESC; + + +class WHEREULT_BUNDLE_H_ENC : MSA_3R_FMT<0b000110010>; +class WHEREULT_BUNDLE_H_DESC : MSA_3R_DESC_BASE_2STR<");\n EXECUTE_WHERE_ULT( //;", vsetult_v128i16, MSA128HOpnd>; //, IsCommutable; +// +let isCodeGenOnly = 1 in +let hasSideEffects = 1 in +//let isBarrier = 1 in +//let isPseudo = 1 in +def WHEREULT_BUNDLE_H : WHEREULT_BUNDLE_H_ENC, WHEREULT_BUNDLE_H_DESC; + + + + + + + + + +// NOTE: It modifies Carry (Sub), Lt, Eq +//def CELLSHL : NonImmediateInstruction<0b100010001, + +class CELLSHR_H_DESC : MSA_RR_PREFIX_DESC_BASE<"CELLSHR", MSA128HOpnd>; +class CELLSHR_H_ENC : MSA_RR_FMT<0b110101011>; +def CELLSHR_H : CELLSHR_H_ENC, CELLSHR_H_DESC; + +class CELLSHL_H_DESC : MSA_RR_PREFIX_DESC_BASE<"CELLSHL", MSA128HOpnd>; +class CELLSHL_H_ENC : MSA_RR_FMT<0b110101011>; +def CELLSHL_H : CELLSHL_H_ENC, CELLSHL_H_DESC; Index: lib/Target/LLVMBuild.txt =================================================================== --- lib/Target/LLVMBuild.txt +++ lib/Target/LLVMBuild.txt @@ -24,6 +24,7 @@ AArch64 AVR BPF + Connex Lanai Hexagon MSP430