Index: include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h =================================================================== --- include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -17,6 +17,7 @@ #include "llvm/CodeGen/GlobalISel/Types.h" #include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/LowLevelType.h" #include "llvm/IR/DebugLoc.h" namespace llvm { @@ -96,7 +97,7 @@ /// \pre Ty == nullptr or isPreISelGenericOpcode(Opcode) /// /// \return The newly created instruction. - MachineInstr *buildInstr(unsigned Opcode, Type *Ty); + MachineInstr *buildInstr(unsigned Opcode, LLT Ty); /// Build and insert = \p Opcode [\p Ty] \p BB. /// @@ -104,7 +105,7 @@ /// \pre Ty == nullptr or isPreISelGenericOpcode(Opcode) /// /// \return The newly created instruction. - MachineInstr *buildInstr(unsigned Opcode, Type *Ty, MachineBasicBlock &BB); + MachineInstr *buildInstr(unsigned Opcode, LLT Ty, MachineBasicBlock &BB); /// Build and insert \p Res = \p Opcode [\p Ty] \p Op0, \p Op1. /// @@ -112,7 +113,7 @@ /// \pre Ty == nullptr or isPreISelGenericOpcode(Opcode) /// /// \return The newly created instruction. - MachineInstr *buildInstr(unsigned Opcode, Type *Ty, unsigned Res, + MachineInstr *buildInstr(unsigned Opcode, LLT Ty, unsigned Res, unsigned Op0, unsigned Op1); /// Build and insert \p Res = \p Opcode \p Op0, \p Op1. Index: include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h =================================================================== --- include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h +++ include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h @@ -291,9 +291,6 @@ /// Total number of register banks. unsigned NumRegBanks; - /// Mapping from MVT::SimpleValueType to register banks. - std::unique_ptr VTToRegBank; - /// Create a RegisterBankInfo that can accomodate up to \p NumRegBanks /// RegisterBank instances. /// @@ -325,14 +322,6 @@ /// It also adjusts the size of the register bank to reflect the maximal /// size of a value that can be hold into that register bank. /// - /// If \p AddTypeMapping is true, this method also records what types can - /// be mapped to \p ID. Although this done by default, targets may want to - /// disable it, espicially if a given type may be mapped on different - /// register bank. Indeed, in such case, this method only records the - /// first register bank where the type matches. - /// This information is only used to provide default mapping - /// (see getInstrMappingImpl). - /// /// \note This method does *not* add the super classes of \p RCId. /// The rationale is if \p ID covers the registers of \p RCId, that /// does not necessarily mean that \p ID covers the set of registers @@ -343,8 +332,7 @@ /// /// \todo TableGen should just generate the BitSet vector for us. void addRegBankCoverage(unsigned ID, unsigned RCId, - const TargetRegisterInfo &TRI, - bool AddTypeMapping = true); + const TargetRegisterInfo &TRI); /// Get the register bank identified by \p ID. RegisterBank &getRegBank(unsigned ID) { @@ -352,36 +340,6 @@ return RegBanks[ID]; } - /// Get the register bank that has been recorded to cover \p SVT. - const RegisterBank *getRegBankForType(MVT::SimpleValueType SVT) const { - if (!VTToRegBank) - return nullptr; - assert(SVT < MVT::SimpleValueType::LAST_VALUETYPE && "Out-of-bound access"); - return VTToRegBank.get()[SVT]; - } - - /// Record \p RegBank as the register bank that covers \p SVT. - /// If a record was already set for \p SVT, the mapping is not - /// updated, unless \p Force == true - /// - /// \post if getRegBankForType(SVT)\@pre == nullptr then - /// getRegBankForType(SVT) == &RegBank - /// \post if Force == true then getRegBankForType(SVT) == &RegBank - void recordRegBankForType(const RegisterBank &RegBank, - MVT::SimpleValueType SVT, bool Force = false) { - if (!VTToRegBank) { - VTToRegBank.reset( - new const RegisterBank *[MVT::SimpleValueType::LAST_VALUETYPE]); - std::fill(&VTToRegBank[0], - &VTToRegBank[MVT::SimpleValueType::LAST_VALUETYPE], nullptr); - } - assert(SVT < MVT::SimpleValueType::LAST_VALUETYPE && "Out-of-bound access"); - // If we want to override the mapping or the mapping does not exits yet, - // set the register bank for SVT. - if (Force || !getRegBankForType(SVT)) - VTToRegBank.get()[SVT] = &RegBank; - } - /// Try to get the mapping of \p MI. /// See getInstrMapping for more details on what a mapping represents. /// Index: include/llvm/CodeGen/LowLevelType.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/LowLevelType.h @@ -0,0 +1,185 @@ +//== llvm/CodeGen/GlobalISel/LowLevelType.h -------------------- -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// Implement a low-level type suitable for MachineInstr level instruction +/// selection. +/// +/// For a type attached to a MachineInstr, we only care about 2 details: total +/// size and the number of vector lanes (if any). Accordingly, there are 3 +/// possible valid type-kinds: +/// +/// * `unsized` for labels etc +/// * `sN` for scalars and aggregates +/// * `` for vectors, which must have at least 2 elements. +/// +/// Other information required for correct selection is expected to be carried +/// by the opcode, or non-type flags. For example the distinction between G_ADD +/// and G_FADD for int/float or fast-math flags. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_LOWLEVELTYPE_H +#define LLVM_CODEGEN_GLOBALISEL_LOWLEVELTYPE_H + +#include +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/CodeGen/ValueTypes.h" + +namespace llvm { + +class LLVMContext; +class Type; +class raw_ostream; + +class LLT { +public: + enum TypeKind : uint16_t { + Invalid, + Scalar, + Vector, + Unsized, + }; + + /// \brief get a low-level scalar or aggregate "bag of bits". + static LLT scalar(unsigned SizeInBits) { + return LLT{Scalar, 1, SizeInBits}; + } + + /// \brief get a low-level vector of some number of elements and element + /// width. \p NumElements must be at least 2. + static LLT vector(uint16_t NumElements, unsigned ScalarSizeInBits) { + assert(NumElements > 1 && "invalid number of vector elements"); + return LLT{Vector, NumElements, ScalarSizeInBits}; + } + + /// \brief get a low-level vector of some number of elements and element + /// type + static LLT vector(uint16_t NumElements, LLT ScalarTy) { + assert(NumElements > 1 && "invalid number of vector elements"); + assert(ScalarTy.isScalar() && "invalid vector element type"); + return LLT{Vector, NumElements, ScalarTy.getSizeInBits()}; + } + + /// \brief get an unsized but valid low-level type (e.g. for a label). + static LLT unsized() { + return LLT{Unsized, 1, 0}; + } + + explicit LLT(TypeKind Kind, uint16_t NumElements, unsigned ScalarSizeInBits) + : ScalarSize(ScalarSizeInBits), NumElements(NumElements), Kind(Kind) { + assert((Kind != Vector || NumElements > 1) && + "invalid number of vector elements"); + } + + explicit LLT() : ScalarSize(0), NumElements(0), Kind(Invalid) {} + + /// \brief construct a low-level type based on an LLVM type. + explicit LLT(const Type &Ty); + + bool isValid() const { return Kind != Invalid; } + + bool isVector() const { return Kind == Vector; } + + bool isSized() const { return Kind == Scalar || Kind == Vector; } + + /// \brief Returns the number of elements in a vector LLT. Must only be called + /// on vector types. + uint16_t getNumElements() const { + assert(isVector() && "cannot get number of elements on scalar/aggregate"); + return NumElements; + } + + /// \brief Returns the total size of the type. Must only be called on sized + /// types. + unsigned getSizeInBits() const { + assert(isSized() && "attempt to get size of unsized type"); + return ScalarSize * NumElements; + } + + unsigned getScalarSizeInBits() const { + assert(isSized() && "cannot get size of this type"); + return ScalarSize; + } + + /// \brief Returns the vector's element type. Only valid for vector types. + LLT getElementType() const { + assert(isVector() && "cannot get element type of scalar/aggregate"); + return scalar(ScalarSize); + } + + /// \brief get a low-level type with half the size of the original, by halving + /// the size of the scalar type involved. For example `s32` will become + /// `s16`, `<2 x s32>` will become `<2 x s16>`. + LLT halfScalarSize() const { + assert(isSized() && "cannot change size of this type"); + return LLT{Kind, NumElements, ScalarSize / 2}; + } + + /// \brief get a low-level type with twice the size of the original, by + /// doubling the size of the scalar type involved. For example `s32` will + /// become `s64`, `<2 x s32>` will become `<2 x s64>`. + LLT doubleScalarSize() const { + assert(isSized() && "cannot change size of this type"); + return LLT{Kind, NumElements, ScalarSize * 2}; + } + + /// \brief get a low-level type with half the size of the original, by halving + /// the number of vector elements of the scalar type involved. The source must + /// be a vector type with an even number of elements. For example `<4 x + /// s32>` will become `<2 x s32>`, `<2 x s32>` will become `s32`. + LLT halfElements() const { + assert(isVector() && NumElements % 2 == 0 && "cannot half odd vector"); + if (NumElements == 2) + return scalar(ScalarSize); + + return LLT{Vector, static_cast(NumElements / 2), ScalarSize}; + } + + /// \brief get a low-level type with twice the size of the original, by + /// doubling the number of vector elements of the scalar type involved. The + /// source must be a vector type. For example `<2 x s32>` will become `<4 x + /// s32>`. Doubling the number of elements in sN produces <2 x sN>. + LLT doubleElements() const { + return LLT{Vector, static_cast(NumElements * 2), ScalarSize}; + } + + void print(raw_ostream &OS) const; + + bool operator ==(const LLT &RHS) const { + return Kind == RHS.Kind && ScalarSize == RHS.ScalarSize && + NumElements == RHS.NumElements; + } + + friend struct DenseMapInfo; +private: + unsigned ScalarSize; + uint16_t NumElements; + TypeKind Kind; +}; + +template<> struct DenseMapInfo { + static inline LLT getEmptyKey() { + return LLT{LLT::Invalid, 0, -1u}; + } + static inline LLT getTombstoneKey() { + return LLT{LLT::Invalid, 0, -2u}; + } + static inline unsigned getHashValue(const LLT &Ty) { + uint64_t Val = ((uint64_t)Ty.ScalarSize << 32) | + ((uint64_t)Ty.NumElements << 16) | (uint64_t)Ty.Kind; + return DenseMapInfo::getHashValue(Val); + } + static bool isEqual(const LLT &LHS, const LLT &RHS) { + return LHS == RHS; + } +}; + +} + +#endif Index: include/llvm/CodeGen/MachineInstr.h =================================================================== --- include/llvm/CodeGen/MachineInstr.h +++ include/llvm/CodeGen/MachineInstr.h @@ -23,6 +23,9 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/CodeGen/MachineOperand.h" +#ifdef LLVM_BUILD_GLOBAL_ISEL +#include "llvm/CodeGen/LowLevelType.h" +#endif #include "llvm/IR/DebugLoc.h" #include "llvm/IR/InlineAsm.h" #include "llvm/MC/MCInstrDesc.h" @@ -39,9 +42,6 @@ class TargetInstrInfo; class TargetRegisterClass; class TargetRegisterInfo; -#ifdef LLVM_BUILD_GLOBAL_ISEL -class Type; -#endif class MachineFunction; class MachineMemOperand; @@ -108,9 +108,9 @@ #ifdef LLVM_BUILD_GLOBAL_ISEL /// Type of the instruction in case of a generic opcode. - /// \invariant This must be nullptr is getOpcode() is not + /// \invariant This must be LLT{} if getOpcode() is not /// in the range of generic opcodes. - Type *Ty; + LLT Ty; #endif MachineInstr(const MachineInstr&) = delete; @@ -189,8 +189,8 @@ /// Set the type of the instruction. /// \pre getOpcode() is in the range of the generic opcodes. - void setType(Type *Ty); - Type *getType() const; + void setType(LLT Ty); + LLT getType() const; /// Return true if MI is in a bundle (but not the first MI in a bundle). /// Index: lib/CodeGen/CMakeLists.txt =================================================================== --- lib/CodeGen/CMakeLists.txt +++ lib/CodeGen/CMakeLists.txt @@ -48,6 +48,7 @@ LiveVariables.cpp LLVMTargetMachine.cpp LocalStackSlotAllocation.cpp + LowLevelType.cpp LowerEmuTLS.cpp MachineBasicBlock.cpp MachineBlockFrequencyInfo.cpp Index: lib/CodeGen/GlobalISel/IRTranslator.cpp =================================================================== --- lib/CodeGen/GlobalISel/IRTranslator.cpp +++ lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -69,7 +69,7 @@ unsigned Op0 = getOrCreateVReg(*Inst.getOperand(0)); unsigned Op1 = getOrCreateVReg(*Inst.getOperand(1)); unsigned Res = getOrCreateVReg(Inst); - MIRBuilder.buildInstr(Opcode, Inst.getType(), Res, Op0, Op1); + MIRBuilder.buildInstr(Opcode, LLT{*Inst.getType()}, Res, Op0, Op1); return true; } @@ -88,7 +88,7 @@ if (BrInst.isUnconditional()) { const BasicBlock &BrTgt = *cast(BrInst.getOperand(0)); MachineBasicBlock &TgtBB = getOrCreateBB(BrTgt); - MIRBuilder.buildInstr(TargetOpcode::G_BR, BrTgt.getType(), TgtBB); + MIRBuilder.buildInstr(TargetOpcode::G_BR, LLT{*BrTgt.getType()}, TgtBB); } else { assert(0 && "Not yet implemented"); } Index: lib/CodeGen/GlobalISel/MachineIRBuilder.cpp =================================================================== --- lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -56,9 +56,9 @@ //------------------------------------------------------------------------------ // Build instruction variants. //------------------------------------------------------------------------------ -MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode, Type *Ty) { +MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode, LLT Ty) { MachineInstr *NewMI = BuildMI(getMF(), DL, getTII().get(Opcode)); - if (Ty) { + if (Ty.isValid()) { assert(isPreISelGenericOpcode(Opcode) && "Only generic instruction can have a type"); NewMI->setType(Ty); @@ -71,10 +71,10 @@ MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode, unsigned Res, unsigned Op0, unsigned Op1) { - return buildInstr(Opcode, nullptr, Res, Op0, Op1); + return buildInstr(Opcode, LLT{}, Res, Op0, Op1); } -MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode, Type *Ty, +MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode, LLT Ty, unsigned Res, unsigned Op0, unsigned Op1) { MachineInstr *NewMI = buildInstr(Opcode, Ty); @@ -87,16 +87,16 @@ MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode, unsigned Res, unsigned Op0) { - MachineInstr *NewMI = buildInstr(Opcode, nullptr); + MachineInstr *NewMI = buildInstr(Opcode, LLT{}); MachineInstrBuilder(getMF(), NewMI).addReg(Res, RegState::Define).addReg(Op0); return NewMI; } MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode) { - return buildInstr(Opcode, nullptr); + return buildInstr(Opcode, LLT{}); } -MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode, Type *Ty, +MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode, LLT Ty, MachineBasicBlock &BB) { MachineInstr *NewMI = buildInstr(Opcode, Ty); MachineInstrBuilder(getMF(), NewMI).addMBB(&BB); Index: lib/CodeGen/GlobalISel/RegisterBankInfo.cpp =================================================================== --- lib/CodeGen/GlobalISel/RegisterBankInfo.cpp +++ lib/CodeGen/GlobalISel/RegisterBankInfo.cpp @@ -65,8 +65,7 @@ } void RegisterBankInfo::addRegBankCoverage(unsigned ID, unsigned RCId, - const TargetRegisterInfo &TRI, - bool AddTypeMapping) { + const TargetRegisterInfo &TRI) { RegisterBank &RB = getRegBank(ID); unsigned NbOfRegClasses = TRI.getNumRegClasses(); @@ -98,13 +97,6 @@ // Remember the biggest size in bits. MaxSize = std::max(MaxSize, CurRC.getSize() * 8); - // If we have been asked to record the type supported by this - // register bank, do it now. - if (AddTypeMapping) - for (MVT::SimpleValueType SVT : - make_range(CurRC.vt_begin(), CurRC.vt_end())) - recordRegBankForType(getRegBank(ID), SVT); - // Walk through all sub register classes and push them into the worklist. bool First = true; for (BitMaskClassIterator It(CurRC.getSubClassMask(), TRI); It.isValid(); @@ -242,30 +234,18 @@ // the register bank from the encoding constraints. CurRegBank = getRegBankFromConstraints(MI, OpIdx, TII, TRI); if (!CurRegBank) { - // Check if we can deduce the register bank from the type of - // the instruction. - Type *MITy = MI.getType(); - if (MITy) - CurRegBank = getRegBankForType( - MVT::getVT(MITy, /*HandleUnknown*/ true).SimpleTy); - if (!CurRegBank) - // Use the current assigned register bank. - // That may not make much sense though. - CurRegBank = AltRegBank; - if (!CurRegBank) { - // All our attempts failed, give up. - CompleteMapping = false; - - if (!isCopyLike) - // MI does not carry enough information to guess the mapping. - return InstructionMapping(); - - // For copies, we want to keep interating to find a register - // bank for the other operands if we did not find one yet. - if (RegBank) - break; - continue; - } + // All our attempts failed, give up. + CompleteMapping = false; + + if (!isCopyLike) + // MI does not carry enough information to guess the mapping. + return InstructionMapping(); + + // For copies, we want to keep interating to find a register + // bank for the other operands if we did not find one yet. + if (RegBank) + break; + continue; } } RegBank = CurRegBank; Index: lib/CodeGen/LowLevelType.cpp =================================================================== --- /dev/null +++ lib/CodeGen/LowLevelType.cpp @@ -0,0 +1,46 @@ +//===-- llvm/CodeGen/GlobalISel/LowLevelType.cpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file implements the more header-heavy bits of the LLT class to +/// avoid polluting users' namespaces. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/LowLevelType.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +LLT::LLT(const Type &Ty) { + if (auto VTy = dyn_cast(&Ty)) { + ScalarSize = VTy->getElementType()->getPrimitiveSizeInBits(); + NumElements = VTy->getNumElements(); + Kind = NumElements == 1 ? Scalar : Vector; + } else if (Ty.isSized()) { + // Aggregates are no different from real scalars as far as GlobalISel is + // concerned. + Kind = Scalar; + ScalarSize = Ty.getPrimitiveSizeInBits(); + NumElements = 1; + } else { + Kind = Unsized; + ScalarSize = NumElements = 0; + } +} + +void LLT::print(raw_ostream &OS) const { + if (isVector()) + OS << "<" << NumElements << " x s" << ScalarSize << ">"; + else if (isSized()) + OS << "s" << ScalarSize; + else if (isValid()) + OS << "unsized"; + else + llvm_unreachable("trying to print an invalid type"); +} Index: lib/CodeGen/MIRParser/MILexer.h =================================================================== --- lib/CodeGen/MIRParser/MILexer.h +++ lib/CodeGen/MIRParser/MILexer.h @@ -102,6 +102,7 @@ NamedRegister, MachineBasicBlockLabel, MachineBasicBlock, + ScalarType, StackObject, FixedStackObject, NamedGlobalValue, Index: lib/CodeGen/MIRParser/MILexer.cpp =================================================================== --- lib/CodeGen/MIRParser/MILexer.cpp +++ lib/CodeGen/MIRParser/MILexer.cpp @@ -173,14 +173,16 @@ return C; } -static Cursor maybeLexIntegerType(Cursor C, MIToken &Token) { - if (C.peek() != 'i' || !isdigit(C.peek(1))) +static Cursor maybeLexIntegerOrScalarType(Cursor C, MIToken &Token) { + if ((C.peek() != 'i' && C.peek() != 's') || !isdigit(C.peek(1))) return None; + char Kind = C.peek(); auto Range = C; C.advance(); // Skip 'i' while (isdigit(C.peek())) C.advance(); - Token.reset(MIToken::IntegerType, Range.upto(C)); + Token.reset(Kind == 'i' ? MIToken::IntegerType : MIToken::ScalarType, + Range.upto(C)); return C; } @@ -566,7 +568,7 @@ return C.remaining(); } - if (Cursor R = maybeLexIntegerType(C, Token)) + if (Cursor R = maybeLexIntegerOrScalarType(C, Token)) return R.remaining(); if (Cursor R = maybeLexMachineBasicBlock(C, Token, ErrorCallback)) return R.remaining(); Index: lib/CodeGen/MIRParser/MIParser.cpp =================================================================== --- lib/CodeGen/MIRParser/MIParser.cpp +++ lib/CodeGen/MIRParser/MIParser.cpp @@ -129,10 +129,7 @@ bool parseIRConstant(StringRef::iterator Loc, StringRef Source, const Constant *&C); bool parseIRConstant(StringRef::iterator Loc, const Constant *&C); - bool parseIRType(StringRef::iterator Loc, StringRef Source, unsigned &Read, - Type *&Ty); - // \p MustBeSized defines whether or not \p Ty must be sized. - bool parseIRType(StringRef::iterator Loc, Type *&Ty, bool MustBeSized = true); + bool parseLowLevelType(StringRef::iterator Loc, LLT &Ty, bool MustBeSized); bool parseTypedImmediateOperand(MachineOperand &Dest); bool parseFPImmediateOperand(MachineOperand &Dest); bool parseMBBReference(MachineBasicBlock *&MBB); @@ -596,11 +593,11 @@ if (Token.isError() || parseInstruction(OpCode, Flags)) return true; - Type *Ty = nullptr; + LLT Ty{}; if (isPreISelGenericOpcode(OpCode)) { // For generic opcode, a type is mandatory. auto Loc = Token.location(); - if (parseIRType(Loc, Ty)) + if (parseLowLevelType(Loc, Ty, true)) return true; } @@ -659,7 +656,7 @@ // TODO: Check for extraneous machine operands. MI = MF.CreateMachineInstr(MCID, DebugLocation, /*NoImplicit=*/true); MI->setFlags(Flags); - if (Ty) + if (Ty.isValid()) MI->setType(Ty); for (const auto &Operand : Operands) MI->addOperand(MF, Operand.Operand); @@ -1021,35 +1018,44 @@ return false; } -bool MIParser::parseIRType(StringRef::iterator Loc, StringRef StringValue, - unsigned &Read, Type *&Ty) { - auto Source = StringValue.str(); // The source has to be null terminated. - SMDiagnostic Err; - Ty = parseTypeAtBeginning(Source.c_str(), Read, Err, - *MF.getFunction()->getParent(), &IRSlots); - if (!Ty) - return error(Loc + Err.getColumnNo(), Err.getMessage()); - return false; -} +bool MIParser::parseLowLevelType(StringRef::iterator Loc, LLT &Ty, + bool MustBeSized) { + if (Token.is(MIToken::Identifier) && Token.stringValue() == "unsized") { + if (MustBeSized) + return error("expected sN or for sized GlobalISel type"); + lex(); + Ty = LLT::unsized(); + return false; + } else if (Token.is(MIToken::ScalarType)) { + Ty = LLT::scalar(APSInt(Token.range().drop_front()).getZExtValue()); + lex(); + return false; + } -bool MIParser::parseIRType(StringRef::iterator Loc, Type *&Ty, - bool MustBeSized) { - // At this point we enter in the IR world, i.e., to get the correct type, - // we need to hand off the whole string, not just the current token. - // E.g., <4 x i64> would give '<' as a token and there is not much - // the IR parser can do with that. - unsigned Read = 0; - if (parseIRType(Loc, StringRef(Loc), Read, Ty)) - return true; - // The type must be sized, otherwise there is not much the backend - // can do with it. - if (MustBeSized && !Ty->isSized()) - return error("expected a sized type"); - // The next token is Read characters from the Loc. - // However, the current location is not Loc, but Loc + the length of Token. - // Therefore, subtract the length of Token (range().end() - Loc) to the - // number of characters to skip before the next token. - lex(Read - (Token.range().end() - Loc)); + // Now we're looking for a vector. + if (Token.isNot(MIToken::less)) + return error(Loc, "expected unsized, sN or for GlobalISel type"); + lex(); + + if (Token.isNot(MIToken::IntegerLiteral)) + return error(Loc, "expected for vctor type"); + uint64_t NumElements = Token.integerValue().getZExtValue(); + lex(); + + if (Token.isNot(MIToken::Identifier) || Token.stringValue() != "x") + return error(Loc, "expected '' for vector type"); + lex(); + + if (Token.isNot(MIToken::ScalarType)) + return error(Loc, "expected '' for vector type"); + uint64_t ScalarSize = APSInt(Token.range().drop_front()).getZExtValue(); + lex(); + + if (Token.isNot(MIToken::greater)) + return error(Loc, "expected '' for vector type"); + lex(); + + Ty = LLT::vector(NumElements, ScalarSize); return false; } Index: lib/CodeGen/MIRPrinter.cpp =================================================================== --- lib/CodeGen/MIRPrinter.cpp +++ lib/CodeGen/MIRPrinter.cpp @@ -565,9 +565,9 @@ OS << "frame-setup "; OS << TII->getName(MI.getOpcode()); if (isPreISelGenericOpcode(MI.getOpcode())) { - assert(MI.getType() && "Generic instructions must have a type"); + assert(MI.getType().isValid() && "Generic instructions must have a type"); OS << ' '; - MI.getType()->print(OS, /*IsForDebug*/ false, /*NoDetails*/ true); + MI.getType().print(OS); } if (I < E) OS << ' '; Index: lib/CodeGen/MachineInstr.cpp =================================================================== --- lib/CodeGen/MachineInstr.cpp +++ lib/CodeGen/MachineInstr.cpp @@ -657,7 +657,7 @@ debugLoc(std::move(dl)) #ifdef LLVM_BUILD_GLOBAL_ISEL , - Ty(nullptr) + Ty(LLT{}) #endif { assert(debugLoc.hasTrivialDestructor() && "Expected trivial destructor"); @@ -681,7 +681,7 @@ MemRefs(MI.MemRefs), debugLoc(MI.getDebugLoc()) #ifdef LLVM_BUILD_GLOBAL_ISEL , - Ty(nullptr) + Ty(LLT{}) #endif { assert(debugLoc.hasTrivialDestructor() && "Expected trivial destructor"); @@ -711,18 +711,18 @@ // The proper implementation is WIP and is tracked here: // PR26576. #ifndef LLVM_BUILD_GLOBAL_ISEL -void MachineInstr::setType(Type *Ty) {} +void MachineInstr::setType(LLT Ty) {} -Type *MachineInstr::getType() const { return nullptr; } +LLT MachineInstr::getType() const { return LLT{}; } #else -void MachineInstr::setType(Type *Ty) { - assert((!Ty || isPreISelGenericOpcode(getOpcode())) && +void MachineInstr::setType(LLT Ty) { + assert((!Ty.isValid() || isPreISelGenericOpcode(getOpcode())) && "Non generic instructions are not supposed to be typed"); this->Ty = Ty; } -Type *MachineInstr::getType() const { return Ty; } +LLT MachineInstr::getType() const { return Ty; } #endif // LLVM_BUILD_GLOBAL_ISEL /// RemoveRegOperandsFromUseLists - Unlink all of the register operands in @@ -1726,9 +1726,9 @@ else OS << "UNKNOWN"; - if (getType()) { + if (getType().isValid()) { OS << ' '; - getType()->print(OS, /*IsForDebug*/ false, /*NoDetails*/ true); + getType().print(OS); OS << ' '; } Index: lib/Target/AArch64/AArch64RegisterBankInfo.h =================================================================== --- lib/Target/AArch64/AArch64RegisterBankInfo.h +++ lib/Target/AArch64/AArch64RegisterBankInfo.h @@ -64,6 +64,8 @@ /// Alternative in the sense different from getInstrMapping. InstructionMappings getInstrAlternativeMappings(const MachineInstr &MI) const override; + + InstructionMapping getInstrMapping(const MachineInstr &MI) const override; }; } // End llvm namespace. #endif Index: lib/Target/AArch64/AArch64RegisterBankInfo.cpp =================================================================== --- lib/Target/AArch64/AArch64RegisterBankInfo.cpp +++ lib/Target/AArch64/AArch64RegisterBankInfo.cpp @@ -155,6 +155,7 @@ void AArch64RegisterBankInfo::applyMappingImpl( const OperandsMapper &OpdMapper) const { switch (OpdMapper.getMI().getOpcode()) { + case TargetOpcode::G_ADD: case TargetOpcode::G_OR: { // Those ID must match getInstrAlternativeMappings. assert((OpdMapper.getInstrMapping().getID() == 1 || @@ -166,3 +167,27 @@ llvm_unreachable("Don't know how to handle that operation"); } } + +RegisterBankInfo::InstructionMapping +AArch64RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { + RegisterBankInfo::InstructionMapping Mapping = getInstrMappingImpl(MI); + if (Mapping.isValid()) + return Mapping; + + // As a top-level guess, vectors go in FPRs, scalars in GPRs. Obviously this + // won't work for normal floating-point types (or NZCV). When such + // instructions exist we'll need to look at the MI's opcode. + LLT Ty = MI.getType(); + unsigned BankID; + if (Ty.isVector()) + BankID = AArch64::FPRRegBankID; + else + BankID = AArch64::GPRRegBankID; + + Mapping = InstructionMapping{1, 1, MI.getNumOperands()}; + int Size = Ty.isSized() ? Ty.getSizeInBits() : 0; + for (unsigned Idx = 0; Idx < MI.getNumOperands(); ++Idx) + Mapping.setOperandMapping(Idx, Size, getRegBank(BankID)); + + return Mapping; +} Index: test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll =================================================================== --- test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll +++ test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll @@ -9,7 +9,7 @@ ; CHECK: name: addi64 ; CHECK: [[ARG1:%[0-9]+]](64) = COPY %x0 ; CHECK-NEXT: [[ARG2:%[0-9]+]](64) = COPY %x1 -; CHECK-NEXT: [[RES:%[0-9]+]](64) = G_ADD i64 [[ARG1]], [[ARG2]] +; CHECK-NEXT: [[RES:%[0-9]+]](64) = G_ADD s64 [[ARG1]], [[ARG2]] ; CHECK-NEXT: %x0 = COPY [[RES]] ; CHECK-NEXT: RET_ReallyLR implicit %x0 define i64 @addi64(i64 %arg1, i64 %arg2) { @@ -28,7 +28,7 @@ ; CHECK-NEXT: successors: %[[END:[0-9a-zA-Z._-]+]]({{0x[a-f0-9]+ / 0x[a-f0-9]+}} = 100.00%) ; ; Check that we emit the correct branch. -; CHECK: G_BR label %[[END]] +; CHECK: G_BR unsized %[[END]] ; ; Check that end contains the return instruction. ; CHECK: [[END]]: @@ -43,7 +43,7 @@ ; CHECK: name: ori64 ; CHECK: [[ARG1:%[0-9]+]](64) = COPY %x0 ; CHECK-NEXT: [[ARG2:%[0-9]+]](64) = COPY %x1 -; CHECK-NEXT: [[RES:%[0-9]+]](64) = G_OR i64 [[ARG1]], [[ARG2]] +; CHECK-NEXT: [[RES:%[0-9]+]](64) = G_OR s64 [[ARG1]], [[ARG2]] ; CHECK-NEXT: %x0 = COPY [[RES]] ; CHECK-NEXT: RET_ReallyLR implicit %x0 define i64 @ori64(i64 %arg1, i64 %arg2) { @@ -54,7 +54,7 @@ ; CHECK: name: ori32 ; CHECK: [[ARG1:%[0-9]+]](32) = COPY %w0 ; CHECK-NEXT: [[ARG2:%[0-9]+]](32) = COPY %w1 -; CHECK-NEXT: [[RES:%[0-9]+]](32) = G_OR i32 [[ARG1]], [[ARG2]] +; CHECK-NEXT: [[RES:%[0-9]+]](32) = G_OR s32 [[ARG1]], [[ARG2]] ; CHECK-NEXT: %w0 = COPY [[RES]] ; CHECK-NEXT: RET_ReallyLR implicit %w0 define i32 @ori32(i32 %arg1, i32 %arg2) { Index: test/CodeGen/AArch64/GlobalISel/arm64-regbankselect.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/arm64-regbankselect.mir +++ test/CodeGen/AArch64/GlobalISel/arm64-regbankselect.mir @@ -68,8 +68,8 @@ body: | bb.0.entry: liveins: %x0 - ; CHECK: %0(32) = G_ADD i32 %x0 - %0(32) = G_ADD i32 %x0, %x0 + ; CHECK: %0(32) = G_ADD s32 %w0 + %0(32) = G_ADD s32 %w0, %w0 ... --- @@ -85,8 +85,8 @@ body: | bb.0.entry: liveins: %d0 - ; CHECK: %0(32) = G_ADD <2 x i32> %d0 - %0(32) = G_ADD <2 x i32> %d0, %d0 + ; CHECK: %0(64) = G_ADD <2 x s32> %d0 + %0(64) = G_ADD <2 x s32> %d0, %d0 ... --- @@ -107,9 +107,9 @@ liveins: %s0, %x0 ; CHECK: %0(32) = COPY %s0 ; CHECK-NEXT: %2(32) = COPY %0 - ; CHECK-NEXT: %1(32) = G_ADD i32 %2, %x0 + ; CHECK-NEXT: %1(32) = G_ADD s32 %2, %w0 %0(32) = COPY %s0 - %1(32) = G_ADD i32 %0, %x0 + %1(32) = G_ADD s32 %0, %w0 ... # Check that we repair the assignment for %0 differently for both uses. @@ -129,9 +129,9 @@ ; CHECK: %0(32) = COPY %s0 ; CHECK-NEXT: %2(32) = COPY %0 ; CHECK-NEXT: %3(32) = COPY %0 - ; CHECK-NEXT: %1(32) = G_ADD i32 %2, %3 + ; CHECK-NEXT: %1(32) = G_ADD s32 %2, %3 %0(32) = COPY %s0 - %1(32) = G_ADD i32 %0, %0 + %1(32) = G_ADD s32 %0, %0 ... --- @@ -152,10 +152,10 @@ bb.0.entry: liveins: %w0 ; CHECK: %0(32) = COPY %w0 - ; CHECK-NEXT: %2(32) = G_ADD i32 %0, %w0 + ; CHECK-NEXT: %2(32) = G_ADD s32 %0, %w0 ; CHECK-NEXT: %1(32) = COPY %2 %0(32) = COPY %w0 - %1(32) = G_ADD i32 %0, %w0 + %1(32) = G_ADD s32 %0, %w0 ... --- @@ -187,7 +187,7 @@ bb.1.then: successors: %bb.2.end - %3(32) = G_ADD i32 %0, %0 + %3(32) = G_ADD s32 %0, %0 bb.2.end: %4(32) = PHI %0, %bb.0.entry, %3, %bb.1.then @@ -211,9 +211,9 @@ liveins: %w0, %s0 ; CHECK: %0(32) = COPY %w0 ; CHECK-NEXT: %2(32) = COPY %s0 - ; CHECK-NEXT: %1(32) = G_ADD i32 %0, %2 + ; CHECK-NEXT: %1(32) = G_ADD s32 %0, %2 %0(32) = COPY %w0 - %1(32) = G_ADD i32 %0, %s0 + %1(32) = G_ADD s32 %0, %s0 ... --- @@ -229,10 +229,10 @@ bb.0.entry: liveins: %w0 ; CHECK: %0(32) = COPY %w0 - ; CHECK-NEXT: %1(32) = G_ADD i32 %0, %0 + ; CHECK-NEXT: %1(32) = G_ADD s32 %0, %0 ; CHECK-NEXT: %s0 = COPY %1 %0(32) = COPY %w0 - %s0 = G_ADD i32 %0, %0 + %s0 = G_ADD s32 %0, %0 ... --- @@ -271,13 +271,13 @@ ; FAST-NEXT: %3(64) = COPY %0 ; FAST-NEXT: %4(64) = COPY %1 ; The mapping of G_OR is on FPR. - ; FAST-NEXT: %2(64) = G_OR <2 x i32> %3, %4 + ; FAST-NEXT: %2(64) = G_OR <2 x s32> %3, %4 ; Greedy mode remapped the instruction on the GPR bank. - ; GREEDY-NEXT: %2(64) = G_OR <2 x i32> %0, %1 + ; GREEDY-NEXT: %2(64) = G_OR <2 x s32> %0, %1 %0(64) = COPY %x0 %1(64) = COPY %x1 - %2(64) = G_OR <2 x i32> %0, %1 + %2(64) = G_OR <2 x s32> %0, %1 ... --- @@ -317,13 +317,13 @@ ; FAST-NEXT: %3(64) = COPY %0 ; FAST-NEXT: %4(64) = COPY %1 ; The mapping of G_OR is on FPR. - ; FAST-NEXT: %2(64) = G_OR <2 x i32> %3, %4 + ; FAST-NEXT: %2(64) = G_OR <2 x s32> %3, %4 ; Greedy mode remapped the instruction on the GPR bank. - ; GREEDY-NEXT: %3(64) = G_OR <2 x i32> %0, %1 + ; GREEDY-NEXT: %3(64) = G_OR <2 x s32> %0, %1 ; We need to keep %2 into FPR because we do not know anything about it. ; GREEDY-NEXT: %2(64) = COPY %3 %0(64) = COPY %x0 %1(64) = COPY %x1 - %2(64) = G_OR <2 x i32> %0, %1 + %2(64) = G_OR <2 x s32> %0, %1 ... Index: test/CodeGen/AMDGPU/GlobalISel/amdgpu-irtranslator.ll =================================================================== --- test/CodeGen/AMDGPU/GlobalISel/amdgpu-irtranslator.ll +++ test/CodeGen/AMDGPU/GlobalISel/amdgpu-irtranslator.ll @@ -5,7 +5,7 @@ ; Tests for add. ; CHECK: name: addi32 -; CHECK: G_ADD i32 +; CHECK: G_ADD s32 define i32 @addi32(i32 %arg1, i32 %arg2) { %res = add i32 %arg1, %arg2 ret i32 %res Index: test/CodeGen/MIR/X86/generic-instr-type-error.mir =================================================================== --- test/CodeGen/MIR/X86/generic-instr-type-error.mir +++ test/CodeGen/MIR/X86/generic-instr-type-error.mir @@ -10,6 +10,6 @@ body: | bb.0.entry: liveins: %edi - ; CHECK: [[@LINE+1]]:20: expected a sized type - %0(32) = G_ADD %opaque %edi, %edi + ; CHECK: [[@LINE+1]]:20: expected sN or for sized GlobalISel type + %0(32) = G_ADD unsized %edi, %edi ... Index: test/CodeGen/MIR/X86/generic-virtual-registers.mir =================================================================== --- test/CodeGen/MIR/X86/generic-virtual-registers.mir +++ test/CodeGen/MIR/X86/generic-virtual-registers.mir @@ -33,16 +33,16 @@ body: | bb.0.entry: liveins: %edi - ; CHECK: %0(32) = G_ADD i32 %edi - %0(32) = G_ADD i32 %edi, %edi - ; CHECK: %1(64) = G_ADD <2 x i32> %edi - %1(64) = G_ADD <2 x i32> %edi, %edi - ; CHECK: %2(64) = G_ADD <2 x i32> %edi - %2(64) = G_ADD %type_alias %edi, %edi + ; CHECK: %0(32) = G_ADD s32 %edi + %0(32) = G_ADD s32 %edi, %edi + ; CHECK: %1(64) = G_ADD <2 x s32> %edi + %1(64) = G_ADD <2 x s32> %edi, %edi + ; CHECK: %2(64) = G_ADD s64 %edi + %2(64) = G_ADD s64 %edi, %edi ; G_ADD is actually not a valid operand for structure type, ; but that is the only one we have for now for testing. - ; CHECK: %3(64) = G_ADD { i32, i32 } %edi - %3(64) = G_ADD {i32, i32} %edi, %edi - ; CHECK: %4(48) = G_ADD %structure_alias %edi - %4(48) = G_ADD %structure_alias %edi, %edi + ; CHECK: %3(64) = G_ADD s64 %edi + %3(64) = G_ADD s64 %edi, %edi + ; CHECK: %4(48) = G_ADD s48 %edi + %4(48) = G_ADD s48 %edi, %edi ...