1*0b57cec5SDimitry Andric //===- NeonEmitter.cpp - Generate arm_neon.h for use with clang -*- C++ -*-===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This tablegen backend is responsible for emitting arm_neon.h, which includes 10*0b57cec5SDimitry Andric // a declaration and definition of each function specified by the ARM NEON 11*0b57cec5SDimitry Andric // compiler interface. See ARM document DUI0348B. 12*0b57cec5SDimitry Andric // 13*0b57cec5SDimitry Andric // Each NEON instruction is implemented in terms of 1 or more functions which 14*0b57cec5SDimitry Andric // are suffixed with the element type of the input vectors. Functions may be 15*0b57cec5SDimitry Andric // implemented in terms of generic vector operations such as +, *, -, etc. or 16*0b57cec5SDimitry Andric // by calling a __builtin_-prefixed function which will be handled by clang's 17*0b57cec5SDimitry Andric // CodeGen library. 18*0b57cec5SDimitry Andric // 19*0b57cec5SDimitry Andric // Additional validation code can be generated by this file when runHeader() is 20*0b57cec5SDimitry Andric // called, rather than the normal run() entry point. 21*0b57cec5SDimitry Andric // 22*0b57cec5SDimitry Andric // See also the documentation in include/clang/Basic/arm_neon.td. 23*0b57cec5SDimitry Andric // 24*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 25*0b57cec5SDimitry Andric 26*0b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 27*0b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 28*0b57cec5SDimitry Andric #include "llvm/ADT/None.h" 29*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 30*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 31*0b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 32*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 33*0b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 34*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 35*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 36*0b57cec5SDimitry Andric #include "llvm/TableGen/Error.h" 37*0b57cec5SDimitry Andric #include "llvm/TableGen/Record.h" 38*0b57cec5SDimitry Andric #include "llvm/TableGen/SetTheory.h" 39*0b57cec5SDimitry Andric #include <algorithm> 40*0b57cec5SDimitry Andric #include <cassert> 41*0b57cec5SDimitry Andric #include <cctype> 42*0b57cec5SDimitry Andric #include <cstddef> 43*0b57cec5SDimitry Andric #include <cstdint> 44*0b57cec5SDimitry Andric #include <deque> 45*0b57cec5SDimitry Andric #include <map> 46*0b57cec5SDimitry Andric #include <set> 47*0b57cec5SDimitry Andric #include <sstream> 48*0b57cec5SDimitry Andric #include <string> 49*0b57cec5SDimitry Andric #include <utility> 50*0b57cec5SDimitry Andric #include <vector> 51*0b57cec5SDimitry Andric 52*0b57cec5SDimitry Andric using namespace llvm; 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric namespace { 55*0b57cec5SDimitry Andric 56*0b57cec5SDimitry Andric // While globals are generally bad, this one allows us to perform assertions 57*0b57cec5SDimitry Andric // liberally and somehow still trace them back to the def they indirectly 58*0b57cec5SDimitry Andric // came from. 59*0b57cec5SDimitry Andric static Record *CurrentRecord = nullptr; 60*0b57cec5SDimitry Andric static void assert_with_loc(bool Assertion, const std::string &Str) { 61*0b57cec5SDimitry Andric if (!Assertion) { 62*0b57cec5SDimitry Andric if (CurrentRecord) 63*0b57cec5SDimitry Andric PrintFatalError(CurrentRecord->getLoc(), Str); 64*0b57cec5SDimitry Andric else 65*0b57cec5SDimitry Andric PrintFatalError(Str); 66*0b57cec5SDimitry Andric } 67*0b57cec5SDimitry Andric } 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric enum ClassKind { 70*0b57cec5SDimitry Andric ClassNone, 71*0b57cec5SDimitry Andric ClassI, // generic integer instruction, e.g., "i8" suffix 72*0b57cec5SDimitry Andric ClassS, // signed/unsigned/poly, e.g., "s8", "u8" or "p8" suffix 73*0b57cec5SDimitry Andric ClassW, // width-specific instruction, e.g., "8" suffix 74*0b57cec5SDimitry Andric ClassB, // bitcast arguments with enum argument to specify type 75*0b57cec5SDimitry Andric ClassL, // Logical instructions which are op instructions 76*0b57cec5SDimitry Andric // but we need to not emit any suffix for in our 77*0b57cec5SDimitry Andric // tests. 78*0b57cec5SDimitry Andric ClassNoTest // Instructions which we do not test since they are 79*0b57cec5SDimitry Andric // not TRUE instructions. 80*0b57cec5SDimitry Andric }; 81*0b57cec5SDimitry Andric 82*0b57cec5SDimitry Andric /// NeonTypeFlags - Flags to identify the types for overloaded Neon 83*0b57cec5SDimitry Andric /// builtins. These must be kept in sync with the flags in 84*0b57cec5SDimitry Andric /// include/clang/Basic/TargetBuiltins.h. 85*0b57cec5SDimitry Andric namespace NeonTypeFlags { 86*0b57cec5SDimitry Andric 87*0b57cec5SDimitry Andric enum { EltTypeMask = 0xf, UnsignedFlag = 0x10, QuadFlag = 0x20 }; 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric enum EltType { 90*0b57cec5SDimitry Andric Int8, 91*0b57cec5SDimitry Andric Int16, 92*0b57cec5SDimitry Andric Int32, 93*0b57cec5SDimitry Andric Int64, 94*0b57cec5SDimitry Andric Poly8, 95*0b57cec5SDimitry Andric Poly16, 96*0b57cec5SDimitry Andric Poly64, 97*0b57cec5SDimitry Andric Poly128, 98*0b57cec5SDimitry Andric Float16, 99*0b57cec5SDimitry Andric Float32, 100*0b57cec5SDimitry Andric Float64 101*0b57cec5SDimitry Andric }; 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric } // end namespace NeonTypeFlags 104*0b57cec5SDimitry Andric 105*0b57cec5SDimitry Andric class NeonEmitter; 106*0b57cec5SDimitry Andric 107*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 108*0b57cec5SDimitry Andric // TypeSpec 109*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 110*0b57cec5SDimitry Andric 111*0b57cec5SDimitry Andric /// A TypeSpec is just a simple wrapper around a string, but gets its own type 112*0b57cec5SDimitry Andric /// for strong typing purposes. 113*0b57cec5SDimitry Andric /// 114*0b57cec5SDimitry Andric /// A TypeSpec can be used to create a type. 115*0b57cec5SDimitry Andric class TypeSpec : public std::string { 116*0b57cec5SDimitry Andric public: 117*0b57cec5SDimitry Andric static std::vector<TypeSpec> fromTypeSpecs(StringRef Str) { 118*0b57cec5SDimitry Andric std::vector<TypeSpec> Ret; 119*0b57cec5SDimitry Andric TypeSpec Acc; 120*0b57cec5SDimitry Andric for (char I : Str.str()) { 121*0b57cec5SDimitry Andric if (islower(I)) { 122*0b57cec5SDimitry Andric Acc.push_back(I); 123*0b57cec5SDimitry Andric Ret.push_back(TypeSpec(Acc)); 124*0b57cec5SDimitry Andric Acc.clear(); 125*0b57cec5SDimitry Andric } else { 126*0b57cec5SDimitry Andric Acc.push_back(I); 127*0b57cec5SDimitry Andric } 128*0b57cec5SDimitry Andric } 129*0b57cec5SDimitry Andric return Ret; 130*0b57cec5SDimitry Andric } 131*0b57cec5SDimitry Andric }; 132*0b57cec5SDimitry Andric 133*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 134*0b57cec5SDimitry Andric // Type 135*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 136*0b57cec5SDimitry Andric 137*0b57cec5SDimitry Andric /// A Type. Not much more to say here. 138*0b57cec5SDimitry Andric class Type { 139*0b57cec5SDimitry Andric private: 140*0b57cec5SDimitry Andric TypeSpec TS; 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric bool Float, Signed, Immediate, Void, Poly, Constant, Pointer; 143*0b57cec5SDimitry Andric // ScalarForMangling and NoManglingQ are really not suited to live here as 144*0b57cec5SDimitry Andric // they are not related to the type. But they live in the TypeSpec (not the 145*0b57cec5SDimitry Andric // prototype), so this is really the only place to store them. 146*0b57cec5SDimitry Andric bool ScalarForMangling, NoManglingQ; 147*0b57cec5SDimitry Andric unsigned Bitwidth, ElementBitwidth, NumVectors; 148*0b57cec5SDimitry Andric 149*0b57cec5SDimitry Andric public: 150*0b57cec5SDimitry Andric Type() 151*0b57cec5SDimitry Andric : Float(false), Signed(false), Immediate(false), Void(true), Poly(false), 152*0b57cec5SDimitry Andric Constant(false), Pointer(false), ScalarForMangling(false), 153*0b57cec5SDimitry Andric NoManglingQ(false), Bitwidth(0), ElementBitwidth(0), NumVectors(0) {} 154*0b57cec5SDimitry Andric 155*0b57cec5SDimitry Andric Type(TypeSpec TS, char CharMod) 156*0b57cec5SDimitry Andric : TS(std::move(TS)), Float(false), Signed(false), Immediate(false), 157*0b57cec5SDimitry Andric Void(false), Poly(false), Constant(false), Pointer(false), 158*0b57cec5SDimitry Andric ScalarForMangling(false), NoManglingQ(false), Bitwidth(0), 159*0b57cec5SDimitry Andric ElementBitwidth(0), NumVectors(0) { 160*0b57cec5SDimitry Andric applyModifier(CharMod); 161*0b57cec5SDimitry Andric } 162*0b57cec5SDimitry Andric 163*0b57cec5SDimitry Andric /// Returns a type representing "void". 164*0b57cec5SDimitry Andric static Type getVoid() { return Type(); } 165*0b57cec5SDimitry Andric 166*0b57cec5SDimitry Andric bool operator==(const Type &Other) const { return str() == Other.str(); } 167*0b57cec5SDimitry Andric bool operator!=(const Type &Other) const { return !operator==(Other); } 168*0b57cec5SDimitry Andric 169*0b57cec5SDimitry Andric // 170*0b57cec5SDimitry Andric // Query functions 171*0b57cec5SDimitry Andric // 172*0b57cec5SDimitry Andric bool isScalarForMangling() const { return ScalarForMangling; } 173*0b57cec5SDimitry Andric bool noManglingQ() const { return NoManglingQ; } 174*0b57cec5SDimitry Andric 175*0b57cec5SDimitry Andric bool isPointer() const { return Pointer; } 176*0b57cec5SDimitry Andric bool isFloating() const { return Float; } 177*0b57cec5SDimitry Andric bool isInteger() const { return !Float && !Poly; } 178*0b57cec5SDimitry Andric bool isSigned() const { return Signed; } 179*0b57cec5SDimitry Andric bool isImmediate() const { return Immediate; } 180*0b57cec5SDimitry Andric bool isScalar() const { return NumVectors == 0; } 181*0b57cec5SDimitry Andric bool isVector() const { return NumVectors > 0; } 182*0b57cec5SDimitry Andric bool isFloat() const { return Float && ElementBitwidth == 32; } 183*0b57cec5SDimitry Andric bool isDouble() const { return Float && ElementBitwidth == 64; } 184*0b57cec5SDimitry Andric bool isHalf() const { return Float && ElementBitwidth == 16; } 185*0b57cec5SDimitry Andric bool isPoly() const { return Poly; } 186*0b57cec5SDimitry Andric bool isChar() const { return ElementBitwidth == 8; } 187*0b57cec5SDimitry Andric bool isShort() const { return !Float && ElementBitwidth == 16; } 188*0b57cec5SDimitry Andric bool isInt() const { return !Float && ElementBitwidth == 32; } 189*0b57cec5SDimitry Andric bool isLong() const { return !Float && ElementBitwidth == 64; } 190*0b57cec5SDimitry Andric bool isVoid() const { return Void; } 191*0b57cec5SDimitry Andric unsigned getNumElements() const { return Bitwidth / ElementBitwidth; } 192*0b57cec5SDimitry Andric unsigned getSizeInBits() const { return Bitwidth; } 193*0b57cec5SDimitry Andric unsigned getElementSizeInBits() const { return ElementBitwidth; } 194*0b57cec5SDimitry Andric unsigned getNumVectors() const { return NumVectors; } 195*0b57cec5SDimitry Andric 196*0b57cec5SDimitry Andric // 197*0b57cec5SDimitry Andric // Mutator functions 198*0b57cec5SDimitry Andric // 199*0b57cec5SDimitry Andric void makeUnsigned() { Signed = false; } 200*0b57cec5SDimitry Andric void makeSigned() { Signed = true; } 201*0b57cec5SDimitry Andric 202*0b57cec5SDimitry Andric void makeInteger(unsigned ElemWidth, bool Sign) { 203*0b57cec5SDimitry Andric Float = false; 204*0b57cec5SDimitry Andric Poly = false; 205*0b57cec5SDimitry Andric Signed = Sign; 206*0b57cec5SDimitry Andric Immediate = false; 207*0b57cec5SDimitry Andric ElementBitwidth = ElemWidth; 208*0b57cec5SDimitry Andric } 209*0b57cec5SDimitry Andric 210*0b57cec5SDimitry Andric void makeImmediate(unsigned ElemWidth) { 211*0b57cec5SDimitry Andric Float = false; 212*0b57cec5SDimitry Andric Poly = false; 213*0b57cec5SDimitry Andric Signed = true; 214*0b57cec5SDimitry Andric Immediate = true; 215*0b57cec5SDimitry Andric ElementBitwidth = ElemWidth; 216*0b57cec5SDimitry Andric } 217*0b57cec5SDimitry Andric 218*0b57cec5SDimitry Andric void makeScalar() { 219*0b57cec5SDimitry Andric Bitwidth = ElementBitwidth; 220*0b57cec5SDimitry Andric NumVectors = 0; 221*0b57cec5SDimitry Andric } 222*0b57cec5SDimitry Andric 223*0b57cec5SDimitry Andric void makeOneVector() { 224*0b57cec5SDimitry Andric assert(isVector()); 225*0b57cec5SDimitry Andric NumVectors = 1; 226*0b57cec5SDimitry Andric } 227*0b57cec5SDimitry Andric 228*0b57cec5SDimitry Andric void doubleLanes() { 229*0b57cec5SDimitry Andric assert_with_loc(Bitwidth != 128, "Can't get bigger than 128!"); 230*0b57cec5SDimitry Andric Bitwidth = 128; 231*0b57cec5SDimitry Andric } 232*0b57cec5SDimitry Andric 233*0b57cec5SDimitry Andric void halveLanes() { 234*0b57cec5SDimitry Andric assert_with_loc(Bitwidth != 64, "Can't get smaller than 64!"); 235*0b57cec5SDimitry Andric Bitwidth = 64; 236*0b57cec5SDimitry Andric } 237*0b57cec5SDimitry Andric 238*0b57cec5SDimitry Andric /// Return the C string representation of a type, which is the typename 239*0b57cec5SDimitry Andric /// defined in stdint.h or arm_neon.h. 240*0b57cec5SDimitry Andric std::string str() const; 241*0b57cec5SDimitry Andric 242*0b57cec5SDimitry Andric /// Return the string representation of a type, which is an encoded 243*0b57cec5SDimitry Andric /// string for passing to the BUILTIN() macro in Builtins.def. 244*0b57cec5SDimitry Andric std::string builtin_str() const; 245*0b57cec5SDimitry Andric 246*0b57cec5SDimitry Andric /// Return the value in NeonTypeFlags for this type. 247*0b57cec5SDimitry Andric unsigned getNeonEnum() const; 248*0b57cec5SDimitry Andric 249*0b57cec5SDimitry Andric /// Parse a type from a stdint.h or arm_neon.h typedef name, 250*0b57cec5SDimitry Andric /// for example uint32x2_t or int64_t. 251*0b57cec5SDimitry Andric static Type fromTypedefName(StringRef Name); 252*0b57cec5SDimitry Andric 253*0b57cec5SDimitry Andric private: 254*0b57cec5SDimitry Andric /// Creates the type based on the typespec string in TS. 255*0b57cec5SDimitry Andric /// Sets "Quad" to true if the "Q" or "H" modifiers were 256*0b57cec5SDimitry Andric /// seen. This is needed by applyModifier as some modifiers 257*0b57cec5SDimitry Andric /// only take effect if the type size was changed by "Q" or "H". 258*0b57cec5SDimitry Andric void applyTypespec(bool &Quad); 259*0b57cec5SDimitry Andric /// Applies a prototype modifier to the type. 260*0b57cec5SDimitry Andric void applyModifier(char Mod); 261*0b57cec5SDimitry Andric }; 262*0b57cec5SDimitry Andric 263*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 264*0b57cec5SDimitry Andric // Variable 265*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 266*0b57cec5SDimitry Andric 267*0b57cec5SDimitry Andric /// A variable is a simple class that just has a type and a name. 268*0b57cec5SDimitry Andric class Variable { 269*0b57cec5SDimitry Andric Type T; 270*0b57cec5SDimitry Andric std::string N; 271*0b57cec5SDimitry Andric 272*0b57cec5SDimitry Andric public: 273*0b57cec5SDimitry Andric Variable() : T(Type::getVoid()), N("") {} 274*0b57cec5SDimitry Andric Variable(Type T, std::string N) : T(std::move(T)), N(std::move(N)) {} 275*0b57cec5SDimitry Andric 276*0b57cec5SDimitry Andric Type getType() const { return T; } 277*0b57cec5SDimitry Andric std::string getName() const { return "__" + N; } 278*0b57cec5SDimitry Andric }; 279*0b57cec5SDimitry Andric 280*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 281*0b57cec5SDimitry Andric // Intrinsic 282*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 283*0b57cec5SDimitry Andric 284*0b57cec5SDimitry Andric /// The main grunt class. This represents an instantiation of an intrinsic with 285*0b57cec5SDimitry Andric /// a particular typespec and prototype. 286*0b57cec5SDimitry Andric class Intrinsic { 287*0b57cec5SDimitry Andric friend class DagEmitter; 288*0b57cec5SDimitry Andric 289*0b57cec5SDimitry Andric /// The Record this intrinsic was created from. 290*0b57cec5SDimitry Andric Record *R; 291*0b57cec5SDimitry Andric /// The unmangled name and prototype. 292*0b57cec5SDimitry Andric std::string Name, Proto; 293*0b57cec5SDimitry Andric /// The input and output typespecs. InTS == OutTS except when 294*0b57cec5SDimitry Andric /// CartesianProductOfTypes is 1 - this is the case for vreinterpret. 295*0b57cec5SDimitry Andric TypeSpec OutTS, InTS; 296*0b57cec5SDimitry Andric /// The base class kind. Most intrinsics use ClassS, which has full type 297*0b57cec5SDimitry Andric /// info for integers (s32/u32). Some use ClassI, which doesn't care about 298*0b57cec5SDimitry Andric /// signedness (i32), while some (ClassB) have no type at all, only a width 299*0b57cec5SDimitry Andric /// (32). 300*0b57cec5SDimitry Andric ClassKind CK; 301*0b57cec5SDimitry Andric /// The list of DAGs for the body. May be empty, in which case we should 302*0b57cec5SDimitry Andric /// emit a builtin call. 303*0b57cec5SDimitry Andric ListInit *Body; 304*0b57cec5SDimitry Andric /// The architectural #ifdef guard. 305*0b57cec5SDimitry Andric std::string Guard; 306*0b57cec5SDimitry Andric /// Set if the Unavailable bit is 1. This means we don't generate a body, 307*0b57cec5SDimitry Andric /// just an "unavailable" attribute on a declaration. 308*0b57cec5SDimitry Andric bool IsUnavailable; 309*0b57cec5SDimitry Andric /// Is this intrinsic safe for big-endian? or does it need its arguments 310*0b57cec5SDimitry Andric /// reversing? 311*0b57cec5SDimitry Andric bool BigEndianSafe; 312*0b57cec5SDimitry Andric 313*0b57cec5SDimitry Andric /// The types of return value [0] and parameters [1..]. 314*0b57cec5SDimitry Andric std::vector<Type> Types; 315*0b57cec5SDimitry Andric /// The local variables defined. 316*0b57cec5SDimitry Andric std::map<std::string, Variable> Variables; 317*0b57cec5SDimitry Andric /// NeededEarly - set if any other intrinsic depends on this intrinsic. 318*0b57cec5SDimitry Andric bool NeededEarly; 319*0b57cec5SDimitry Andric /// UseMacro - set if we should implement using a macro or unset for a 320*0b57cec5SDimitry Andric /// function. 321*0b57cec5SDimitry Andric bool UseMacro; 322*0b57cec5SDimitry Andric /// The set of intrinsics that this intrinsic uses/requires. 323*0b57cec5SDimitry Andric std::set<Intrinsic *> Dependencies; 324*0b57cec5SDimitry Andric /// The "base type", which is Type('d', OutTS). InBaseType is only 325*0b57cec5SDimitry Andric /// different if CartesianProductOfTypes = 1 (for vreinterpret). 326*0b57cec5SDimitry Andric Type BaseType, InBaseType; 327*0b57cec5SDimitry Andric /// The return variable. 328*0b57cec5SDimitry Andric Variable RetVar; 329*0b57cec5SDimitry Andric /// A postfix to apply to every variable. Defaults to "". 330*0b57cec5SDimitry Andric std::string VariablePostfix; 331*0b57cec5SDimitry Andric 332*0b57cec5SDimitry Andric NeonEmitter &Emitter; 333*0b57cec5SDimitry Andric std::stringstream OS; 334*0b57cec5SDimitry Andric 335*0b57cec5SDimitry Andric public: 336*0b57cec5SDimitry Andric Intrinsic(Record *R, StringRef Name, StringRef Proto, TypeSpec OutTS, 337*0b57cec5SDimitry Andric TypeSpec InTS, ClassKind CK, ListInit *Body, NeonEmitter &Emitter, 338*0b57cec5SDimitry Andric StringRef Guard, bool IsUnavailable, bool BigEndianSafe) 339*0b57cec5SDimitry Andric : R(R), Name(Name.str()), Proto(Proto.str()), OutTS(OutTS), InTS(InTS), 340*0b57cec5SDimitry Andric CK(CK), Body(Body), Guard(Guard.str()), IsUnavailable(IsUnavailable), 341*0b57cec5SDimitry Andric BigEndianSafe(BigEndianSafe), NeededEarly(false), UseMacro(false), 342*0b57cec5SDimitry Andric BaseType(OutTS, 'd'), InBaseType(InTS, 'd'), Emitter(Emitter) { 343*0b57cec5SDimitry Andric // If this builtin takes an immediate argument, we need to #define it rather 344*0b57cec5SDimitry Andric // than use a standard declaration, so that SemaChecking can range check 345*0b57cec5SDimitry Andric // the immediate passed by the user. 346*0b57cec5SDimitry Andric if (Proto.find('i') != std::string::npos) 347*0b57cec5SDimitry Andric UseMacro = true; 348*0b57cec5SDimitry Andric 349*0b57cec5SDimitry Andric // Pointer arguments need to use macros to avoid hiding aligned attributes 350*0b57cec5SDimitry Andric // from the pointer type. 351*0b57cec5SDimitry Andric if (Proto.find('p') != std::string::npos || 352*0b57cec5SDimitry Andric Proto.find('c') != std::string::npos) 353*0b57cec5SDimitry Andric UseMacro = true; 354*0b57cec5SDimitry Andric 355*0b57cec5SDimitry Andric // It is not permitted to pass or return an __fp16 by value, so intrinsics 356*0b57cec5SDimitry Andric // taking a scalar float16_t must be implemented as macros. 357*0b57cec5SDimitry Andric if (OutTS.find('h') != std::string::npos && 358*0b57cec5SDimitry Andric Proto.find('s') != std::string::npos) 359*0b57cec5SDimitry Andric UseMacro = true; 360*0b57cec5SDimitry Andric 361*0b57cec5SDimitry Andric // Modify the TypeSpec per-argument to get a concrete Type, and create 362*0b57cec5SDimitry Andric // known variables for each. 363*0b57cec5SDimitry Andric // Types[0] is the return value. 364*0b57cec5SDimitry Andric Types.emplace_back(OutTS, Proto[0]); 365*0b57cec5SDimitry Andric for (unsigned I = 1; I < Proto.size(); ++I) 366*0b57cec5SDimitry Andric Types.emplace_back(InTS, Proto[I]); 367*0b57cec5SDimitry Andric } 368*0b57cec5SDimitry Andric 369*0b57cec5SDimitry Andric /// Get the Record that this intrinsic is based off. 370*0b57cec5SDimitry Andric Record *getRecord() const { return R; } 371*0b57cec5SDimitry Andric /// Get the set of Intrinsics that this intrinsic calls. 372*0b57cec5SDimitry Andric /// this is the set of immediate dependencies, NOT the 373*0b57cec5SDimitry Andric /// transitive closure. 374*0b57cec5SDimitry Andric const std::set<Intrinsic *> &getDependencies() const { return Dependencies; } 375*0b57cec5SDimitry Andric /// Get the architectural guard string (#ifdef). 376*0b57cec5SDimitry Andric std::string getGuard() const { return Guard; } 377*0b57cec5SDimitry Andric /// Get the non-mangled name. 378*0b57cec5SDimitry Andric std::string getName() const { return Name; } 379*0b57cec5SDimitry Andric 380*0b57cec5SDimitry Andric /// Return true if the intrinsic takes an immediate operand. 381*0b57cec5SDimitry Andric bool hasImmediate() const { 382*0b57cec5SDimitry Andric return Proto.find('i') != std::string::npos; 383*0b57cec5SDimitry Andric } 384*0b57cec5SDimitry Andric 385*0b57cec5SDimitry Andric /// Return the parameter index of the immediate operand. 386*0b57cec5SDimitry Andric unsigned getImmediateIdx() const { 387*0b57cec5SDimitry Andric assert(hasImmediate()); 388*0b57cec5SDimitry Andric unsigned Idx = Proto.find('i'); 389*0b57cec5SDimitry Andric assert(Idx > 0 && "Can't return an immediate!"); 390*0b57cec5SDimitry Andric return Idx - 1; 391*0b57cec5SDimitry Andric } 392*0b57cec5SDimitry Andric 393*0b57cec5SDimitry Andric /// Return true if the intrinsic takes an splat operand. 394*0b57cec5SDimitry Andric bool hasSplat() const { return Proto.find('a') != std::string::npos; } 395*0b57cec5SDimitry Andric 396*0b57cec5SDimitry Andric /// Return the parameter index of the splat operand. 397*0b57cec5SDimitry Andric unsigned getSplatIdx() const { 398*0b57cec5SDimitry Andric assert(hasSplat()); 399*0b57cec5SDimitry Andric unsigned Idx = Proto.find('a'); 400*0b57cec5SDimitry Andric assert(Idx > 0 && "Can't return a splat!"); 401*0b57cec5SDimitry Andric return Idx - 1; 402*0b57cec5SDimitry Andric } 403*0b57cec5SDimitry Andric 404*0b57cec5SDimitry Andric unsigned getNumParams() const { return Proto.size() - 1; } 405*0b57cec5SDimitry Andric Type getReturnType() const { return Types[0]; } 406*0b57cec5SDimitry Andric Type getParamType(unsigned I) const { return Types[I + 1]; } 407*0b57cec5SDimitry Andric Type getBaseType() const { return BaseType; } 408*0b57cec5SDimitry Andric /// Return the raw prototype string. 409*0b57cec5SDimitry Andric std::string getProto() const { return Proto; } 410*0b57cec5SDimitry Andric 411*0b57cec5SDimitry Andric /// Return true if the prototype has a scalar argument. 412*0b57cec5SDimitry Andric /// This does not return true for the "splat" code ('a'). 413*0b57cec5SDimitry Andric bool protoHasScalar() const; 414*0b57cec5SDimitry Andric 415*0b57cec5SDimitry Andric /// Return the index that parameter PIndex will sit at 416*0b57cec5SDimitry Andric /// in a generated function call. This is often just PIndex, 417*0b57cec5SDimitry Andric /// but may not be as things such as multiple-vector operands 418*0b57cec5SDimitry Andric /// and sret parameters need to be taken into accont. 419*0b57cec5SDimitry Andric unsigned getGeneratedParamIdx(unsigned PIndex) { 420*0b57cec5SDimitry Andric unsigned Idx = 0; 421*0b57cec5SDimitry Andric if (getReturnType().getNumVectors() > 1) 422*0b57cec5SDimitry Andric // Multiple vectors are passed as sret. 423*0b57cec5SDimitry Andric ++Idx; 424*0b57cec5SDimitry Andric 425*0b57cec5SDimitry Andric for (unsigned I = 0; I < PIndex; ++I) 426*0b57cec5SDimitry Andric Idx += std::max(1U, getParamType(I).getNumVectors()); 427*0b57cec5SDimitry Andric 428*0b57cec5SDimitry Andric return Idx; 429*0b57cec5SDimitry Andric } 430*0b57cec5SDimitry Andric 431*0b57cec5SDimitry Andric bool hasBody() const { return Body && !Body->getValues().empty(); } 432*0b57cec5SDimitry Andric 433*0b57cec5SDimitry Andric void setNeededEarly() { NeededEarly = true; } 434*0b57cec5SDimitry Andric 435*0b57cec5SDimitry Andric bool operator<(const Intrinsic &Other) const { 436*0b57cec5SDimitry Andric // Sort lexicographically on a two-tuple (Guard, Name) 437*0b57cec5SDimitry Andric if (Guard != Other.Guard) 438*0b57cec5SDimitry Andric return Guard < Other.Guard; 439*0b57cec5SDimitry Andric return Name < Other.Name; 440*0b57cec5SDimitry Andric } 441*0b57cec5SDimitry Andric 442*0b57cec5SDimitry Andric ClassKind getClassKind(bool UseClassBIfScalar = false) { 443*0b57cec5SDimitry Andric if (UseClassBIfScalar && !protoHasScalar()) 444*0b57cec5SDimitry Andric return ClassB; 445*0b57cec5SDimitry Andric return CK; 446*0b57cec5SDimitry Andric } 447*0b57cec5SDimitry Andric 448*0b57cec5SDimitry Andric /// Return the name, mangled with type information. 449*0b57cec5SDimitry Andric /// If ForceClassS is true, use ClassS (u32/s32) instead 450*0b57cec5SDimitry Andric /// of the intrinsic's own type class. 451*0b57cec5SDimitry Andric std::string getMangledName(bool ForceClassS = false) const; 452*0b57cec5SDimitry Andric /// Return the type code for a builtin function call. 453*0b57cec5SDimitry Andric std::string getInstTypeCode(Type T, ClassKind CK) const; 454*0b57cec5SDimitry Andric /// Return the type string for a BUILTIN() macro in Builtins.def. 455*0b57cec5SDimitry Andric std::string getBuiltinTypeStr(); 456*0b57cec5SDimitry Andric 457*0b57cec5SDimitry Andric /// Generate the intrinsic, returning code. 458*0b57cec5SDimitry Andric std::string generate(); 459*0b57cec5SDimitry Andric /// Perform type checking and populate the dependency graph, but 460*0b57cec5SDimitry Andric /// don't generate code yet. 461*0b57cec5SDimitry Andric void indexBody(); 462*0b57cec5SDimitry Andric 463*0b57cec5SDimitry Andric private: 464*0b57cec5SDimitry Andric std::string mangleName(std::string Name, ClassKind CK) const; 465*0b57cec5SDimitry Andric 466*0b57cec5SDimitry Andric void initVariables(); 467*0b57cec5SDimitry Andric std::string replaceParamsIn(std::string S); 468*0b57cec5SDimitry Andric 469*0b57cec5SDimitry Andric void emitBodyAsBuiltinCall(); 470*0b57cec5SDimitry Andric 471*0b57cec5SDimitry Andric void generateImpl(bool ReverseArguments, 472*0b57cec5SDimitry Andric StringRef NamePrefix, StringRef CallPrefix); 473*0b57cec5SDimitry Andric void emitReturn(); 474*0b57cec5SDimitry Andric void emitBody(StringRef CallPrefix); 475*0b57cec5SDimitry Andric void emitShadowedArgs(); 476*0b57cec5SDimitry Andric void emitArgumentReversal(); 477*0b57cec5SDimitry Andric void emitReturnReversal(); 478*0b57cec5SDimitry Andric void emitReverseVariable(Variable &Dest, Variable &Src); 479*0b57cec5SDimitry Andric void emitNewLine(); 480*0b57cec5SDimitry Andric void emitClosingBrace(); 481*0b57cec5SDimitry Andric void emitOpeningBrace(); 482*0b57cec5SDimitry Andric void emitPrototype(StringRef NamePrefix); 483*0b57cec5SDimitry Andric 484*0b57cec5SDimitry Andric class DagEmitter { 485*0b57cec5SDimitry Andric Intrinsic &Intr; 486*0b57cec5SDimitry Andric StringRef CallPrefix; 487*0b57cec5SDimitry Andric 488*0b57cec5SDimitry Andric public: 489*0b57cec5SDimitry Andric DagEmitter(Intrinsic &Intr, StringRef CallPrefix) : 490*0b57cec5SDimitry Andric Intr(Intr), CallPrefix(CallPrefix) { 491*0b57cec5SDimitry Andric } 492*0b57cec5SDimitry Andric std::pair<Type, std::string> emitDagArg(Init *Arg, std::string ArgName); 493*0b57cec5SDimitry Andric std::pair<Type, std::string> emitDagSaveTemp(DagInit *DI); 494*0b57cec5SDimitry Andric std::pair<Type, std::string> emitDagSplat(DagInit *DI); 495*0b57cec5SDimitry Andric std::pair<Type, std::string> emitDagDup(DagInit *DI); 496*0b57cec5SDimitry Andric std::pair<Type, std::string> emitDagDupTyped(DagInit *DI); 497*0b57cec5SDimitry Andric std::pair<Type, std::string> emitDagShuffle(DagInit *DI); 498*0b57cec5SDimitry Andric std::pair<Type, std::string> emitDagCast(DagInit *DI, bool IsBitCast); 499*0b57cec5SDimitry Andric std::pair<Type, std::string> emitDagCall(DagInit *DI); 500*0b57cec5SDimitry Andric std::pair<Type, std::string> emitDagNameReplace(DagInit *DI); 501*0b57cec5SDimitry Andric std::pair<Type, std::string> emitDagLiteral(DagInit *DI); 502*0b57cec5SDimitry Andric std::pair<Type, std::string> emitDagOp(DagInit *DI); 503*0b57cec5SDimitry Andric std::pair<Type, std::string> emitDag(DagInit *DI); 504*0b57cec5SDimitry Andric }; 505*0b57cec5SDimitry Andric }; 506*0b57cec5SDimitry Andric 507*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 508*0b57cec5SDimitry Andric // NeonEmitter 509*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 510*0b57cec5SDimitry Andric 511*0b57cec5SDimitry Andric class NeonEmitter { 512*0b57cec5SDimitry Andric RecordKeeper &Records; 513*0b57cec5SDimitry Andric DenseMap<Record *, ClassKind> ClassMap; 514*0b57cec5SDimitry Andric std::map<std::string, std::deque<Intrinsic>> IntrinsicMap; 515*0b57cec5SDimitry Andric unsigned UniqueNumber; 516*0b57cec5SDimitry Andric 517*0b57cec5SDimitry Andric void createIntrinsic(Record *R, SmallVectorImpl<Intrinsic *> &Out); 518*0b57cec5SDimitry Andric void genBuiltinsDef(raw_ostream &OS, SmallVectorImpl<Intrinsic *> &Defs); 519*0b57cec5SDimitry Andric void genOverloadTypeCheckCode(raw_ostream &OS, 520*0b57cec5SDimitry Andric SmallVectorImpl<Intrinsic *> &Defs); 521*0b57cec5SDimitry Andric void genIntrinsicRangeCheckCode(raw_ostream &OS, 522*0b57cec5SDimitry Andric SmallVectorImpl<Intrinsic *> &Defs); 523*0b57cec5SDimitry Andric 524*0b57cec5SDimitry Andric public: 525*0b57cec5SDimitry Andric /// Called by Intrinsic - this attempts to get an intrinsic that takes 526*0b57cec5SDimitry Andric /// the given types as arguments. 527*0b57cec5SDimitry Andric Intrinsic &getIntrinsic(StringRef Name, ArrayRef<Type> Types); 528*0b57cec5SDimitry Andric 529*0b57cec5SDimitry Andric /// Called by Intrinsic - returns a globally-unique number. 530*0b57cec5SDimitry Andric unsigned getUniqueNumber() { return UniqueNumber++; } 531*0b57cec5SDimitry Andric 532*0b57cec5SDimitry Andric NeonEmitter(RecordKeeper &R) : Records(R), UniqueNumber(0) { 533*0b57cec5SDimitry Andric Record *SI = R.getClass("SInst"); 534*0b57cec5SDimitry Andric Record *II = R.getClass("IInst"); 535*0b57cec5SDimitry Andric Record *WI = R.getClass("WInst"); 536*0b57cec5SDimitry Andric Record *SOpI = R.getClass("SOpInst"); 537*0b57cec5SDimitry Andric Record *IOpI = R.getClass("IOpInst"); 538*0b57cec5SDimitry Andric Record *WOpI = R.getClass("WOpInst"); 539*0b57cec5SDimitry Andric Record *LOpI = R.getClass("LOpInst"); 540*0b57cec5SDimitry Andric Record *NoTestOpI = R.getClass("NoTestOpInst"); 541*0b57cec5SDimitry Andric 542*0b57cec5SDimitry Andric ClassMap[SI] = ClassS; 543*0b57cec5SDimitry Andric ClassMap[II] = ClassI; 544*0b57cec5SDimitry Andric ClassMap[WI] = ClassW; 545*0b57cec5SDimitry Andric ClassMap[SOpI] = ClassS; 546*0b57cec5SDimitry Andric ClassMap[IOpI] = ClassI; 547*0b57cec5SDimitry Andric ClassMap[WOpI] = ClassW; 548*0b57cec5SDimitry Andric ClassMap[LOpI] = ClassL; 549*0b57cec5SDimitry Andric ClassMap[NoTestOpI] = ClassNoTest; 550*0b57cec5SDimitry Andric } 551*0b57cec5SDimitry Andric 552*0b57cec5SDimitry Andric // run - Emit arm_neon.h.inc 553*0b57cec5SDimitry Andric void run(raw_ostream &o); 554*0b57cec5SDimitry Andric 555*0b57cec5SDimitry Andric // runFP16 - Emit arm_fp16.h.inc 556*0b57cec5SDimitry Andric void runFP16(raw_ostream &o); 557*0b57cec5SDimitry Andric 558*0b57cec5SDimitry Andric // runHeader - Emit all the __builtin prototypes used in arm_neon.h 559*0b57cec5SDimitry Andric // and arm_fp16.h 560*0b57cec5SDimitry Andric void runHeader(raw_ostream &o); 561*0b57cec5SDimitry Andric 562*0b57cec5SDimitry Andric // runTests - Emit tests for all the Neon intrinsics. 563*0b57cec5SDimitry Andric void runTests(raw_ostream &o); 564*0b57cec5SDimitry Andric }; 565*0b57cec5SDimitry Andric 566*0b57cec5SDimitry Andric } // end anonymous namespace 567*0b57cec5SDimitry Andric 568*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 569*0b57cec5SDimitry Andric // Type implementation 570*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 571*0b57cec5SDimitry Andric 572*0b57cec5SDimitry Andric std::string Type::str() const { 573*0b57cec5SDimitry Andric if (Void) 574*0b57cec5SDimitry Andric return "void"; 575*0b57cec5SDimitry Andric std::string S; 576*0b57cec5SDimitry Andric 577*0b57cec5SDimitry Andric if (!Signed && isInteger()) 578*0b57cec5SDimitry Andric S += "u"; 579*0b57cec5SDimitry Andric 580*0b57cec5SDimitry Andric if (Poly) 581*0b57cec5SDimitry Andric S += "poly"; 582*0b57cec5SDimitry Andric else if (Float) 583*0b57cec5SDimitry Andric S += "float"; 584*0b57cec5SDimitry Andric else 585*0b57cec5SDimitry Andric S += "int"; 586*0b57cec5SDimitry Andric 587*0b57cec5SDimitry Andric S += utostr(ElementBitwidth); 588*0b57cec5SDimitry Andric if (isVector()) 589*0b57cec5SDimitry Andric S += "x" + utostr(getNumElements()); 590*0b57cec5SDimitry Andric if (NumVectors > 1) 591*0b57cec5SDimitry Andric S += "x" + utostr(NumVectors); 592*0b57cec5SDimitry Andric S += "_t"; 593*0b57cec5SDimitry Andric 594*0b57cec5SDimitry Andric if (Constant) 595*0b57cec5SDimitry Andric S += " const"; 596*0b57cec5SDimitry Andric if (Pointer) 597*0b57cec5SDimitry Andric S += " *"; 598*0b57cec5SDimitry Andric 599*0b57cec5SDimitry Andric return S; 600*0b57cec5SDimitry Andric } 601*0b57cec5SDimitry Andric 602*0b57cec5SDimitry Andric std::string Type::builtin_str() const { 603*0b57cec5SDimitry Andric std::string S; 604*0b57cec5SDimitry Andric if (isVoid()) 605*0b57cec5SDimitry Andric return "v"; 606*0b57cec5SDimitry Andric 607*0b57cec5SDimitry Andric if (Pointer) 608*0b57cec5SDimitry Andric // All pointers are void pointers. 609*0b57cec5SDimitry Andric S += "v"; 610*0b57cec5SDimitry Andric else if (isInteger()) 611*0b57cec5SDimitry Andric switch (ElementBitwidth) { 612*0b57cec5SDimitry Andric case 8: S += "c"; break; 613*0b57cec5SDimitry Andric case 16: S += "s"; break; 614*0b57cec5SDimitry Andric case 32: S += "i"; break; 615*0b57cec5SDimitry Andric case 64: S += "Wi"; break; 616*0b57cec5SDimitry Andric case 128: S += "LLLi"; break; 617*0b57cec5SDimitry Andric default: llvm_unreachable("Unhandled case!"); 618*0b57cec5SDimitry Andric } 619*0b57cec5SDimitry Andric else 620*0b57cec5SDimitry Andric switch (ElementBitwidth) { 621*0b57cec5SDimitry Andric case 16: S += "h"; break; 622*0b57cec5SDimitry Andric case 32: S += "f"; break; 623*0b57cec5SDimitry Andric case 64: S += "d"; break; 624*0b57cec5SDimitry Andric default: llvm_unreachable("Unhandled case!"); 625*0b57cec5SDimitry Andric } 626*0b57cec5SDimitry Andric 627*0b57cec5SDimitry Andric if (isChar() && !Pointer) 628*0b57cec5SDimitry Andric // Make chars explicitly signed. 629*0b57cec5SDimitry Andric S = "S" + S; 630*0b57cec5SDimitry Andric else if (isInteger() && !Pointer && !Signed) 631*0b57cec5SDimitry Andric S = "U" + S; 632*0b57cec5SDimitry Andric 633*0b57cec5SDimitry Andric // Constant indices are "int", but have the "constant expression" modifier. 634*0b57cec5SDimitry Andric if (isImmediate()) { 635*0b57cec5SDimitry Andric assert(isInteger() && isSigned()); 636*0b57cec5SDimitry Andric S = "I" + S; 637*0b57cec5SDimitry Andric } 638*0b57cec5SDimitry Andric 639*0b57cec5SDimitry Andric if (isScalar()) { 640*0b57cec5SDimitry Andric if (Constant) S += "C"; 641*0b57cec5SDimitry Andric if (Pointer) S += "*"; 642*0b57cec5SDimitry Andric return S; 643*0b57cec5SDimitry Andric } 644*0b57cec5SDimitry Andric 645*0b57cec5SDimitry Andric std::string Ret; 646*0b57cec5SDimitry Andric for (unsigned I = 0; I < NumVectors; ++I) 647*0b57cec5SDimitry Andric Ret += "V" + utostr(getNumElements()) + S; 648*0b57cec5SDimitry Andric 649*0b57cec5SDimitry Andric return Ret; 650*0b57cec5SDimitry Andric } 651*0b57cec5SDimitry Andric 652*0b57cec5SDimitry Andric unsigned Type::getNeonEnum() const { 653*0b57cec5SDimitry Andric unsigned Addend; 654*0b57cec5SDimitry Andric switch (ElementBitwidth) { 655*0b57cec5SDimitry Andric case 8: Addend = 0; break; 656*0b57cec5SDimitry Andric case 16: Addend = 1; break; 657*0b57cec5SDimitry Andric case 32: Addend = 2; break; 658*0b57cec5SDimitry Andric case 64: Addend = 3; break; 659*0b57cec5SDimitry Andric case 128: Addend = 4; break; 660*0b57cec5SDimitry Andric default: llvm_unreachable("Unhandled element bitwidth!"); 661*0b57cec5SDimitry Andric } 662*0b57cec5SDimitry Andric 663*0b57cec5SDimitry Andric unsigned Base = (unsigned)NeonTypeFlags::Int8 + Addend; 664*0b57cec5SDimitry Andric if (Poly) { 665*0b57cec5SDimitry Andric // Adjustment needed because Poly32 doesn't exist. 666*0b57cec5SDimitry Andric if (Addend >= 2) 667*0b57cec5SDimitry Andric --Addend; 668*0b57cec5SDimitry Andric Base = (unsigned)NeonTypeFlags::Poly8 + Addend; 669*0b57cec5SDimitry Andric } 670*0b57cec5SDimitry Andric if (Float) { 671*0b57cec5SDimitry Andric assert(Addend != 0 && "Float8 doesn't exist!"); 672*0b57cec5SDimitry Andric Base = (unsigned)NeonTypeFlags::Float16 + (Addend - 1); 673*0b57cec5SDimitry Andric } 674*0b57cec5SDimitry Andric 675*0b57cec5SDimitry Andric if (Bitwidth == 128) 676*0b57cec5SDimitry Andric Base |= (unsigned)NeonTypeFlags::QuadFlag; 677*0b57cec5SDimitry Andric if (isInteger() && !Signed) 678*0b57cec5SDimitry Andric Base |= (unsigned)NeonTypeFlags::UnsignedFlag; 679*0b57cec5SDimitry Andric 680*0b57cec5SDimitry Andric return Base; 681*0b57cec5SDimitry Andric } 682*0b57cec5SDimitry Andric 683*0b57cec5SDimitry Andric Type Type::fromTypedefName(StringRef Name) { 684*0b57cec5SDimitry Andric Type T; 685*0b57cec5SDimitry Andric T.Void = false; 686*0b57cec5SDimitry Andric T.Float = false; 687*0b57cec5SDimitry Andric T.Poly = false; 688*0b57cec5SDimitry Andric 689*0b57cec5SDimitry Andric if (Name.front() == 'u') { 690*0b57cec5SDimitry Andric T.Signed = false; 691*0b57cec5SDimitry Andric Name = Name.drop_front(); 692*0b57cec5SDimitry Andric } else { 693*0b57cec5SDimitry Andric T.Signed = true; 694*0b57cec5SDimitry Andric } 695*0b57cec5SDimitry Andric 696*0b57cec5SDimitry Andric if (Name.startswith("float")) { 697*0b57cec5SDimitry Andric T.Float = true; 698*0b57cec5SDimitry Andric Name = Name.drop_front(5); 699*0b57cec5SDimitry Andric } else if (Name.startswith("poly")) { 700*0b57cec5SDimitry Andric T.Poly = true; 701*0b57cec5SDimitry Andric Name = Name.drop_front(4); 702*0b57cec5SDimitry Andric } else { 703*0b57cec5SDimitry Andric assert(Name.startswith("int")); 704*0b57cec5SDimitry Andric Name = Name.drop_front(3); 705*0b57cec5SDimitry Andric } 706*0b57cec5SDimitry Andric 707*0b57cec5SDimitry Andric unsigned I = 0; 708*0b57cec5SDimitry Andric for (I = 0; I < Name.size(); ++I) { 709*0b57cec5SDimitry Andric if (!isdigit(Name[I])) 710*0b57cec5SDimitry Andric break; 711*0b57cec5SDimitry Andric } 712*0b57cec5SDimitry Andric Name.substr(0, I).getAsInteger(10, T.ElementBitwidth); 713*0b57cec5SDimitry Andric Name = Name.drop_front(I); 714*0b57cec5SDimitry Andric 715*0b57cec5SDimitry Andric T.Bitwidth = T.ElementBitwidth; 716*0b57cec5SDimitry Andric T.NumVectors = 1; 717*0b57cec5SDimitry Andric 718*0b57cec5SDimitry Andric if (Name.front() == 'x') { 719*0b57cec5SDimitry Andric Name = Name.drop_front(); 720*0b57cec5SDimitry Andric unsigned I = 0; 721*0b57cec5SDimitry Andric for (I = 0; I < Name.size(); ++I) { 722*0b57cec5SDimitry Andric if (!isdigit(Name[I])) 723*0b57cec5SDimitry Andric break; 724*0b57cec5SDimitry Andric } 725*0b57cec5SDimitry Andric unsigned NumLanes; 726*0b57cec5SDimitry Andric Name.substr(0, I).getAsInteger(10, NumLanes); 727*0b57cec5SDimitry Andric Name = Name.drop_front(I); 728*0b57cec5SDimitry Andric T.Bitwidth = T.ElementBitwidth * NumLanes; 729*0b57cec5SDimitry Andric } else { 730*0b57cec5SDimitry Andric // Was scalar. 731*0b57cec5SDimitry Andric T.NumVectors = 0; 732*0b57cec5SDimitry Andric } 733*0b57cec5SDimitry Andric if (Name.front() == 'x') { 734*0b57cec5SDimitry Andric Name = Name.drop_front(); 735*0b57cec5SDimitry Andric unsigned I = 0; 736*0b57cec5SDimitry Andric for (I = 0; I < Name.size(); ++I) { 737*0b57cec5SDimitry Andric if (!isdigit(Name[I])) 738*0b57cec5SDimitry Andric break; 739*0b57cec5SDimitry Andric } 740*0b57cec5SDimitry Andric Name.substr(0, I).getAsInteger(10, T.NumVectors); 741*0b57cec5SDimitry Andric Name = Name.drop_front(I); 742*0b57cec5SDimitry Andric } 743*0b57cec5SDimitry Andric 744*0b57cec5SDimitry Andric assert(Name.startswith("_t") && "Malformed typedef!"); 745*0b57cec5SDimitry Andric return T; 746*0b57cec5SDimitry Andric } 747*0b57cec5SDimitry Andric 748*0b57cec5SDimitry Andric void Type::applyTypespec(bool &Quad) { 749*0b57cec5SDimitry Andric std::string S = TS; 750*0b57cec5SDimitry Andric ScalarForMangling = false; 751*0b57cec5SDimitry Andric Void = false; 752*0b57cec5SDimitry Andric Poly = Float = false; 753*0b57cec5SDimitry Andric ElementBitwidth = ~0U; 754*0b57cec5SDimitry Andric Signed = true; 755*0b57cec5SDimitry Andric NumVectors = 1; 756*0b57cec5SDimitry Andric 757*0b57cec5SDimitry Andric for (char I : S) { 758*0b57cec5SDimitry Andric switch (I) { 759*0b57cec5SDimitry Andric case 'S': 760*0b57cec5SDimitry Andric ScalarForMangling = true; 761*0b57cec5SDimitry Andric break; 762*0b57cec5SDimitry Andric case 'H': 763*0b57cec5SDimitry Andric NoManglingQ = true; 764*0b57cec5SDimitry Andric Quad = true; 765*0b57cec5SDimitry Andric break; 766*0b57cec5SDimitry Andric case 'Q': 767*0b57cec5SDimitry Andric Quad = true; 768*0b57cec5SDimitry Andric break; 769*0b57cec5SDimitry Andric case 'P': 770*0b57cec5SDimitry Andric Poly = true; 771*0b57cec5SDimitry Andric break; 772*0b57cec5SDimitry Andric case 'U': 773*0b57cec5SDimitry Andric Signed = false; 774*0b57cec5SDimitry Andric break; 775*0b57cec5SDimitry Andric case 'c': 776*0b57cec5SDimitry Andric ElementBitwidth = 8; 777*0b57cec5SDimitry Andric break; 778*0b57cec5SDimitry Andric case 'h': 779*0b57cec5SDimitry Andric Float = true; 780*0b57cec5SDimitry Andric LLVM_FALLTHROUGH; 781*0b57cec5SDimitry Andric case 's': 782*0b57cec5SDimitry Andric ElementBitwidth = 16; 783*0b57cec5SDimitry Andric break; 784*0b57cec5SDimitry Andric case 'f': 785*0b57cec5SDimitry Andric Float = true; 786*0b57cec5SDimitry Andric LLVM_FALLTHROUGH; 787*0b57cec5SDimitry Andric case 'i': 788*0b57cec5SDimitry Andric ElementBitwidth = 32; 789*0b57cec5SDimitry Andric break; 790*0b57cec5SDimitry Andric case 'd': 791*0b57cec5SDimitry Andric Float = true; 792*0b57cec5SDimitry Andric LLVM_FALLTHROUGH; 793*0b57cec5SDimitry Andric case 'l': 794*0b57cec5SDimitry Andric ElementBitwidth = 64; 795*0b57cec5SDimitry Andric break; 796*0b57cec5SDimitry Andric case 'k': 797*0b57cec5SDimitry Andric ElementBitwidth = 128; 798*0b57cec5SDimitry Andric // Poly doesn't have a 128x1 type. 799*0b57cec5SDimitry Andric if (Poly) 800*0b57cec5SDimitry Andric NumVectors = 0; 801*0b57cec5SDimitry Andric break; 802*0b57cec5SDimitry Andric default: 803*0b57cec5SDimitry Andric llvm_unreachable("Unhandled type code!"); 804*0b57cec5SDimitry Andric } 805*0b57cec5SDimitry Andric } 806*0b57cec5SDimitry Andric assert(ElementBitwidth != ~0U && "Bad element bitwidth!"); 807*0b57cec5SDimitry Andric 808*0b57cec5SDimitry Andric Bitwidth = Quad ? 128 : 64; 809*0b57cec5SDimitry Andric } 810*0b57cec5SDimitry Andric 811*0b57cec5SDimitry Andric void Type::applyModifier(char Mod) { 812*0b57cec5SDimitry Andric bool AppliedQuad = false; 813*0b57cec5SDimitry Andric applyTypespec(AppliedQuad); 814*0b57cec5SDimitry Andric 815*0b57cec5SDimitry Andric switch (Mod) { 816*0b57cec5SDimitry Andric case 'v': 817*0b57cec5SDimitry Andric Void = true; 818*0b57cec5SDimitry Andric break; 819*0b57cec5SDimitry Andric case 't': 820*0b57cec5SDimitry Andric if (Poly) { 821*0b57cec5SDimitry Andric Poly = false; 822*0b57cec5SDimitry Andric Signed = false; 823*0b57cec5SDimitry Andric } 824*0b57cec5SDimitry Andric break; 825*0b57cec5SDimitry Andric case 'b': 826*0b57cec5SDimitry Andric Signed = false; 827*0b57cec5SDimitry Andric Float = false; 828*0b57cec5SDimitry Andric Poly = false; 829*0b57cec5SDimitry Andric NumVectors = 0; 830*0b57cec5SDimitry Andric Bitwidth = ElementBitwidth; 831*0b57cec5SDimitry Andric break; 832*0b57cec5SDimitry Andric case '$': 833*0b57cec5SDimitry Andric Signed = true; 834*0b57cec5SDimitry Andric Float = false; 835*0b57cec5SDimitry Andric Poly = false; 836*0b57cec5SDimitry Andric NumVectors = 0; 837*0b57cec5SDimitry Andric Bitwidth = ElementBitwidth; 838*0b57cec5SDimitry Andric break; 839*0b57cec5SDimitry Andric case 'u': 840*0b57cec5SDimitry Andric Signed = false; 841*0b57cec5SDimitry Andric Poly = false; 842*0b57cec5SDimitry Andric Float = false; 843*0b57cec5SDimitry Andric break; 844*0b57cec5SDimitry Andric case 'x': 845*0b57cec5SDimitry Andric Signed = true; 846*0b57cec5SDimitry Andric assert(!Poly && "'u' can't be used with poly types!"); 847*0b57cec5SDimitry Andric Float = false; 848*0b57cec5SDimitry Andric break; 849*0b57cec5SDimitry Andric case 'o': 850*0b57cec5SDimitry Andric Bitwidth = ElementBitwidth = 64; 851*0b57cec5SDimitry Andric NumVectors = 0; 852*0b57cec5SDimitry Andric Float = true; 853*0b57cec5SDimitry Andric break; 854*0b57cec5SDimitry Andric case 'y': 855*0b57cec5SDimitry Andric Bitwidth = ElementBitwidth = 32; 856*0b57cec5SDimitry Andric NumVectors = 0; 857*0b57cec5SDimitry Andric Float = true; 858*0b57cec5SDimitry Andric break; 859*0b57cec5SDimitry Andric case 'Y': 860*0b57cec5SDimitry Andric Bitwidth = ElementBitwidth = 16; 861*0b57cec5SDimitry Andric NumVectors = 0; 862*0b57cec5SDimitry Andric Float = true; 863*0b57cec5SDimitry Andric break; 864*0b57cec5SDimitry Andric case 'I': 865*0b57cec5SDimitry Andric Bitwidth = ElementBitwidth = 32; 866*0b57cec5SDimitry Andric NumVectors = 0; 867*0b57cec5SDimitry Andric Float = false; 868*0b57cec5SDimitry Andric Signed = true; 869*0b57cec5SDimitry Andric break; 870*0b57cec5SDimitry Andric case 'L': 871*0b57cec5SDimitry Andric Bitwidth = ElementBitwidth = 64; 872*0b57cec5SDimitry Andric NumVectors = 0; 873*0b57cec5SDimitry Andric Float = false; 874*0b57cec5SDimitry Andric Signed = true; 875*0b57cec5SDimitry Andric break; 876*0b57cec5SDimitry Andric case 'U': 877*0b57cec5SDimitry Andric Bitwidth = ElementBitwidth = 32; 878*0b57cec5SDimitry Andric NumVectors = 0; 879*0b57cec5SDimitry Andric Float = false; 880*0b57cec5SDimitry Andric Signed = false; 881*0b57cec5SDimitry Andric break; 882*0b57cec5SDimitry Andric case 'O': 883*0b57cec5SDimitry Andric Bitwidth = ElementBitwidth = 64; 884*0b57cec5SDimitry Andric NumVectors = 0; 885*0b57cec5SDimitry Andric Float = false; 886*0b57cec5SDimitry Andric Signed = false; 887*0b57cec5SDimitry Andric break; 888*0b57cec5SDimitry Andric case 'f': 889*0b57cec5SDimitry Andric Float = true; 890*0b57cec5SDimitry Andric ElementBitwidth = 32; 891*0b57cec5SDimitry Andric break; 892*0b57cec5SDimitry Andric case 'F': 893*0b57cec5SDimitry Andric Float = true; 894*0b57cec5SDimitry Andric ElementBitwidth = 64; 895*0b57cec5SDimitry Andric break; 896*0b57cec5SDimitry Andric case 'H': 897*0b57cec5SDimitry Andric Float = true; 898*0b57cec5SDimitry Andric ElementBitwidth = 16; 899*0b57cec5SDimitry Andric break; 900*0b57cec5SDimitry Andric case '0': 901*0b57cec5SDimitry Andric Float = true; 902*0b57cec5SDimitry Andric if (AppliedQuad) 903*0b57cec5SDimitry Andric Bitwidth /= 2; 904*0b57cec5SDimitry Andric ElementBitwidth = 16; 905*0b57cec5SDimitry Andric break; 906*0b57cec5SDimitry Andric case '1': 907*0b57cec5SDimitry Andric Float = true; 908*0b57cec5SDimitry Andric if (!AppliedQuad) 909*0b57cec5SDimitry Andric Bitwidth *= 2; 910*0b57cec5SDimitry Andric ElementBitwidth = 16; 911*0b57cec5SDimitry Andric break; 912*0b57cec5SDimitry Andric case 'g': 913*0b57cec5SDimitry Andric if (AppliedQuad) 914*0b57cec5SDimitry Andric Bitwidth /= 2; 915*0b57cec5SDimitry Andric break; 916*0b57cec5SDimitry Andric case 'j': 917*0b57cec5SDimitry Andric if (!AppliedQuad) 918*0b57cec5SDimitry Andric Bitwidth *= 2; 919*0b57cec5SDimitry Andric break; 920*0b57cec5SDimitry Andric case 'w': 921*0b57cec5SDimitry Andric ElementBitwidth *= 2; 922*0b57cec5SDimitry Andric Bitwidth *= 2; 923*0b57cec5SDimitry Andric break; 924*0b57cec5SDimitry Andric case 'n': 925*0b57cec5SDimitry Andric ElementBitwidth *= 2; 926*0b57cec5SDimitry Andric break; 927*0b57cec5SDimitry Andric case 'i': 928*0b57cec5SDimitry Andric Float = false; 929*0b57cec5SDimitry Andric Poly = false; 930*0b57cec5SDimitry Andric ElementBitwidth = Bitwidth = 32; 931*0b57cec5SDimitry Andric NumVectors = 0; 932*0b57cec5SDimitry Andric Signed = true; 933*0b57cec5SDimitry Andric Immediate = true; 934*0b57cec5SDimitry Andric break; 935*0b57cec5SDimitry Andric case 'l': 936*0b57cec5SDimitry Andric Float = false; 937*0b57cec5SDimitry Andric Poly = false; 938*0b57cec5SDimitry Andric ElementBitwidth = Bitwidth = 64; 939*0b57cec5SDimitry Andric NumVectors = 0; 940*0b57cec5SDimitry Andric Signed = false; 941*0b57cec5SDimitry Andric Immediate = true; 942*0b57cec5SDimitry Andric break; 943*0b57cec5SDimitry Andric case 'z': 944*0b57cec5SDimitry Andric ElementBitwidth /= 2; 945*0b57cec5SDimitry Andric Bitwidth = ElementBitwidth; 946*0b57cec5SDimitry Andric NumVectors = 0; 947*0b57cec5SDimitry Andric break; 948*0b57cec5SDimitry Andric case 'r': 949*0b57cec5SDimitry Andric ElementBitwidth *= 2; 950*0b57cec5SDimitry Andric Bitwidth = ElementBitwidth; 951*0b57cec5SDimitry Andric NumVectors = 0; 952*0b57cec5SDimitry Andric break; 953*0b57cec5SDimitry Andric case 's': 954*0b57cec5SDimitry Andric case 'a': 955*0b57cec5SDimitry Andric Bitwidth = ElementBitwidth; 956*0b57cec5SDimitry Andric NumVectors = 0; 957*0b57cec5SDimitry Andric break; 958*0b57cec5SDimitry Andric case 'k': 959*0b57cec5SDimitry Andric Bitwidth *= 2; 960*0b57cec5SDimitry Andric break; 961*0b57cec5SDimitry Andric case 'c': 962*0b57cec5SDimitry Andric Constant = true; 963*0b57cec5SDimitry Andric LLVM_FALLTHROUGH; 964*0b57cec5SDimitry Andric case 'p': 965*0b57cec5SDimitry Andric Pointer = true; 966*0b57cec5SDimitry Andric Bitwidth = ElementBitwidth; 967*0b57cec5SDimitry Andric NumVectors = 0; 968*0b57cec5SDimitry Andric break; 969*0b57cec5SDimitry Andric case 'h': 970*0b57cec5SDimitry Andric ElementBitwidth /= 2; 971*0b57cec5SDimitry Andric break; 972*0b57cec5SDimitry Andric case 'q': 973*0b57cec5SDimitry Andric ElementBitwidth /= 2; 974*0b57cec5SDimitry Andric Bitwidth *= 2; 975*0b57cec5SDimitry Andric break; 976*0b57cec5SDimitry Andric case 'e': 977*0b57cec5SDimitry Andric ElementBitwidth /= 2; 978*0b57cec5SDimitry Andric Signed = false; 979*0b57cec5SDimitry Andric break; 980*0b57cec5SDimitry Andric case 'm': 981*0b57cec5SDimitry Andric ElementBitwidth /= 2; 982*0b57cec5SDimitry Andric Bitwidth /= 2; 983*0b57cec5SDimitry Andric break; 984*0b57cec5SDimitry Andric case 'd': 985*0b57cec5SDimitry Andric break; 986*0b57cec5SDimitry Andric case '2': 987*0b57cec5SDimitry Andric NumVectors = 2; 988*0b57cec5SDimitry Andric break; 989*0b57cec5SDimitry Andric case '3': 990*0b57cec5SDimitry Andric NumVectors = 3; 991*0b57cec5SDimitry Andric break; 992*0b57cec5SDimitry Andric case '4': 993*0b57cec5SDimitry Andric NumVectors = 4; 994*0b57cec5SDimitry Andric break; 995*0b57cec5SDimitry Andric case 'B': 996*0b57cec5SDimitry Andric NumVectors = 2; 997*0b57cec5SDimitry Andric if (!AppliedQuad) 998*0b57cec5SDimitry Andric Bitwidth *= 2; 999*0b57cec5SDimitry Andric break; 1000*0b57cec5SDimitry Andric case 'C': 1001*0b57cec5SDimitry Andric NumVectors = 3; 1002*0b57cec5SDimitry Andric if (!AppliedQuad) 1003*0b57cec5SDimitry Andric Bitwidth *= 2; 1004*0b57cec5SDimitry Andric break; 1005*0b57cec5SDimitry Andric case 'D': 1006*0b57cec5SDimitry Andric NumVectors = 4; 1007*0b57cec5SDimitry Andric if (!AppliedQuad) 1008*0b57cec5SDimitry Andric Bitwidth *= 2; 1009*0b57cec5SDimitry Andric break; 1010*0b57cec5SDimitry Andric case '7': 1011*0b57cec5SDimitry Andric if (AppliedQuad) 1012*0b57cec5SDimitry Andric Bitwidth /= 2; 1013*0b57cec5SDimitry Andric ElementBitwidth = 8; 1014*0b57cec5SDimitry Andric break; 1015*0b57cec5SDimitry Andric case '8': 1016*0b57cec5SDimitry Andric ElementBitwidth = 8; 1017*0b57cec5SDimitry Andric break; 1018*0b57cec5SDimitry Andric case '9': 1019*0b57cec5SDimitry Andric if (!AppliedQuad) 1020*0b57cec5SDimitry Andric Bitwidth *= 2; 1021*0b57cec5SDimitry Andric ElementBitwidth = 8; 1022*0b57cec5SDimitry Andric break; 1023*0b57cec5SDimitry Andric default: 1024*0b57cec5SDimitry Andric llvm_unreachable("Unhandled character!"); 1025*0b57cec5SDimitry Andric } 1026*0b57cec5SDimitry Andric } 1027*0b57cec5SDimitry Andric 1028*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1029*0b57cec5SDimitry Andric // Intrinsic implementation 1030*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1031*0b57cec5SDimitry Andric 1032*0b57cec5SDimitry Andric std::string Intrinsic::getInstTypeCode(Type T, ClassKind CK) const { 1033*0b57cec5SDimitry Andric char typeCode = '\0'; 1034*0b57cec5SDimitry Andric bool printNumber = true; 1035*0b57cec5SDimitry Andric 1036*0b57cec5SDimitry Andric if (CK == ClassB) 1037*0b57cec5SDimitry Andric return ""; 1038*0b57cec5SDimitry Andric 1039*0b57cec5SDimitry Andric if (T.isPoly()) 1040*0b57cec5SDimitry Andric typeCode = 'p'; 1041*0b57cec5SDimitry Andric else if (T.isInteger()) 1042*0b57cec5SDimitry Andric typeCode = T.isSigned() ? 's' : 'u'; 1043*0b57cec5SDimitry Andric else 1044*0b57cec5SDimitry Andric typeCode = 'f'; 1045*0b57cec5SDimitry Andric 1046*0b57cec5SDimitry Andric if (CK == ClassI) { 1047*0b57cec5SDimitry Andric switch (typeCode) { 1048*0b57cec5SDimitry Andric default: 1049*0b57cec5SDimitry Andric break; 1050*0b57cec5SDimitry Andric case 's': 1051*0b57cec5SDimitry Andric case 'u': 1052*0b57cec5SDimitry Andric case 'p': 1053*0b57cec5SDimitry Andric typeCode = 'i'; 1054*0b57cec5SDimitry Andric break; 1055*0b57cec5SDimitry Andric } 1056*0b57cec5SDimitry Andric } 1057*0b57cec5SDimitry Andric if (CK == ClassB) { 1058*0b57cec5SDimitry Andric typeCode = '\0'; 1059*0b57cec5SDimitry Andric } 1060*0b57cec5SDimitry Andric 1061*0b57cec5SDimitry Andric std::string S; 1062*0b57cec5SDimitry Andric if (typeCode != '\0') 1063*0b57cec5SDimitry Andric S.push_back(typeCode); 1064*0b57cec5SDimitry Andric if (printNumber) 1065*0b57cec5SDimitry Andric S += utostr(T.getElementSizeInBits()); 1066*0b57cec5SDimitry Andric 1067*0b57cec5SDimitry Andric return S; 1068*0b57cec5SDimitry Andric } 1069*0b57cec5SDimitry Andric 1070*0b57cec5SDimitry Andric static bool isFloatingPointProtoModifier(char Mod) { 1071*0b57cec5SDimitry Andric return Mod == 'F' || Mod == 'f' || Mod == 'H' || Mod == 'Y' || Mod == 'I'; 1072*0b57cec5SDimitry Andric } 1073*0b57cec5SDimitry Andric 1074*0b57cec5SDimitry Andric std::string Intrinsic::getBuiltinTypeStr() { 1075*0b57cec5SDimitry Andric ClassKind LocalCK = getClassKind(true); 1076*0b57cec5SDimitry Andric std::string S; 1077*0b57cec5SDimitry Andric 1078*0b57cec5SDimitry Andric Type RetT = getReturnType(); 1079*0b57cec5SDimitry Andric if ((LocalCK == ClassI || LocalCK == ClassW) && RetT.isScalar() && 1080*0b57cec5SDimitry Andric !RetT.isFloating()) 1081*0b57cec5SDimitry Andric RetT.makeInteger(RetT.getElementSizeInBits(), false); 1082*0b57cec5SDimitry Andric 1083*0b57cec5SDimitry Andric // Since the return value must be one type, return a vector type of the 1084*0b57cec5SDimitry Andric // appropriate width which we will bitcast. An exception is made for 1085*0b57cec5SDimitry Andric // returning structs of 2, 3, or 4 vectors which are returned in a sret-like 1086*0b57cec5SDimitry Andric // fashion, storing them to a pointer arg. 1087*0b57cec5SDimitry Andric if (RetT.getNumVectors() > 1) { 1088*0b57cec5SDimitry Andric S += "vv*"; // void result with void* first argument 1089*0b57cec5SDimitry Andric } else { 1090*0b57cec5SDimitry Andric if (RetT.isPoly()) 1091*0b57cec5SDimitry Andric RetT.makeInteger(RetT.getElementSizeInBits(), false); 1092*0b57cec5SDimitry Andric if (!RetT.isScalar() && !RetT.isSigned()) 1093*0b57cec5SDimitry Andric RetT.makeSigned(); 1094*0b57cec5SDimitry Andric 1095*0b57cec5SDimitry Andric bool ForcedVectorFloatingType = isFloatingPointProtoModifier(Proto[0]); 1096*0b57cec5SDimitry Andric if (LocalCK == ClassB && !RetT.isScalar() && !ForcedVectorFloatingType) 1097*0b57cec5SDimitry Andric // Cast to vector of 8-bit elements. 1098*0b57cec5SDimitry Andric RetT.makeInteger(8, true); 1099*0b57cec5SDimitry Andric 1100*0b57cec5SDimitry Andric S += RetT.builtin_str(); 1101*0b57cec5SDimitry Andric } 1102*0b57cec5SDimitry Andric 1103*0b57cec5SDimitry Andric for (unsigned I = 0; I < getNumParams(); ++I) { 1104*0b57cec5SDimitry Andric Type T = getParamType(I); 1105*0b57cec5SDimitry Andric if (T.isPoly()) 1106*0b57cec5SDimitry Andric T.makeInteger(T.getElementSizeInBits(), false); 1107*0b57cec5SDimitry Andric 1108*0b57cec5SDimitry Andric bool ForcedFloatingType = isFloatingPointProtoModifier(Proto[I + 1]); 1109*0b57cec5SDimitry Andric if (LocalCK == ClassB && !T.isScalar() && !ForcedFloatingType) 1110*0b57cec5SDimitry Andric T.makeInteger(8, true); 1111*0b57cec5SDimitry Andric // Halves always get converted to 8-bit elements. 1112*0b57cec5SDimitry Andric if (T.isHalf() && T.isVector() && !T.isScalarForMangling()) 1113*0b57cec5SDimitry Andric T.makeInteger(8, true); 1114*0b57cec5SDimitry Andric 1115*0b57cec5SDimitry Andric if (LocalCK == ClassI) 1116*0b57cec5SDimitry Andric T.makeSigned(); 1117*0b57cec5SDimitry Andric 1118*0b57cec5SDimitry Andric if (hasImmediate() && getImmediateIdx() == I) 1119*0b57cec5SDimitry Andric T.makeImmediate(32); 1120*0b57cec5SDimitry Andric 1121*0b57cec5SDimitry Andric S += T.builtin_str(); 1122*0b57cec5SDimitry Andric } 1123*0b57cec5SDimitry Andric 1124*0b57cec5SDimitry Andric // Extra constant integer to hold type class enum for this function, e.g. s8 1125*0b57cec5SDimitry Andric if (LocalCK == ClassB) 1126*0b57cec5SDimitry Andric S += "i"; 1127*0b57cec5SDimitry Andric 1128*0b57cec5SDimitry Andric return S; 1129*0b57cec5SDimitry Andric } 1130*0b57cec5SDimitry Andric 1131*0b57cec5SDimitry Andric std::string Intrinsic::getMangledName(bool ForceClassS) const { 1132*0b57cec5SDimitry Andric // Check if the prototype has a scalar operand with the type of the vector 1133*0b57cec5SDimitry Andric // elements. If not, bitcasting the args will take care of arg checking. 1134*0b57cec5SDimitry Andric // The actual signedness etc. will be taken care of with special enums. 1135*0b57cec5SDimitry Andric ClassKind LocalCK = CK; 1136*0b57cec5SDimitry Andric if (!protoHasScalar()) 1137*0b57cec5SDimitry Andric LocalCK = ClassB; 1138*0b57cec5SDimitry Andric 1139*0b57cec5SDimitry Andric return mangleName(Name, ForceClassS ? ClassS : LocalCK); 1140*0b57cec5SDimitry Andric } 1141*0b57cec5SDimitry Andric 1142*0b57cec5SDimitry Andric std::string Intrinsic::mangleName(std::string Name, ClassKind LocalCK) const { 1143*0b57cec5SDimitry Andric std::string typeCode = getInstTypeCode(BaseType, LocalCK); 1144*0b57cec5SDimitry Andric std::string S = Name; 1145*0b57cec5SDimitry Andric 1146*0b57cec5SDimitry Andric if (Name == "vcvt_f16_f32" || Name == "vcvt_f32_f16" || 1147*0b57cec5SDimitry Andric Name == "vcvt_f32_f64" || Name == "vcvt_f64_f32") 1148*0b57cec5SDimitry Andric return Name; 1149*0b57cec5SDimitry Andric 1150*0b57cec5SDimitry Andric if (!typeCode.empty()) { 1151*0b57cec5SDimitry Andric // If the name ends with _xN (N = 2,3,4), insert the typeCode before _xN. 1152*0b57cec5SDimitry Andric if (Name.size() >= 3 && isdigit(Name.back()) && 1153*0b57cec5SDimitry Andric Name[Name.length() - 2] == 'x' && Name[Name.length() - 3] == '_') 1154*0b57cec5SDimitry Andric S.insert(S.length() - 3, "_" + typeCode); 1155*0b57cec5SDimitry Andric else 1156*0b57cec5SDimitry Andric S += "_" + typeCode; 1157*0b57cec5SDimitry Andric } 1158*0b57cec5SDimitry Andric 1159*0b57cec5SDimitry Andric if (BaseType != InBaseType) { 1160*0b57cec5SDimitry Andric // A reinterpret - out the input base type at the end. 1161*0b57cec5SDimitry Andric S += "_" + getInstTypeCode(InBaseType, LocalCK); 1162*0b57cec5SDimitry Andric } 1163*0b57cec5SDimitry Andric 1164*0b57cec5SDimitry Andric if (LocalCK == ClassB) 1165*0b57cec5SDimitry Andric S += "_v"; 1166*0b57cec5SDimitry Andric 1167*0b57cec5SDimitry Andric // Insert a 'q' before the first '_' character so that it ends up before 1168*0b57cec5SDimitry Andric // _lane or _n on vector-scalar operations. 1169*0b57cec5SDimitry Andric if (BaseType.getSizeInBits() == 128 && !BaseType.noManglingQ()) { 1170*0b57cec5SDimitry Andric size_t Pos = S.find('_'); 1171*0b57cec5SDimitry Andric S.insert(Pos, "q"); 1172*0b57cec5SDimitry Andric } 1173*0b57cec5SDimitry Andric 1174*0b57cec5SDimitry Andric char Suffix = '\0'; 1175*0b57cec5SDimitry Andric if (BaseType.isScalarForMangling()) { 1176*0b57cec5SDimitry Andric switch (BaseType.getElementSizeInBits()) { 1177*0b57cec5SDimitry Andric case 8: Suffix = 'b'; break; 1178*0b57cec5SDimitry Andric case 16: Suffix = 'h'; break; 1179*0b57cec5SDimitry Andric case 32: Suffix = 's'; break; 1180*0b57cec5SDimitry Andric case 64: Suffix = 'd'; break; 1181*0b57cec5SDimitry Andric default: llvm_unreachable("Bad suffix!"); 1182*0b57cec5SDimitry Andric } 1183*0b57cec5SDimitry Andric } 1184*0b57cec5SDimitry Andric if (Suffix != '\0') { 1185*0b57cec5SDimitry Andric size_t Pos = S.find('_'); 1186*0b57cec5SDimitry Andric S.insert(Pos, &Suffix, 1); 1187*0b57cec5SDimitry Andric } 1188*0b57cec5SDimitry Andric 1189*0b57cec5SDimitry Andric return S; 1190*0b57cec5SDimitry Andric } 1191*0b57cec5SDimitry Andric 1192*0b57cec5SDimitry Andric std::string Intrinsic::replaceParamsIn(std::string S) { 1193*0b57cec5SDimitry Andric while (S.find('$') != std::string::npos) { 1194*0b57cec5SDimitry Andric size_t Pos = S.find('$'); 1195*0b57cec5SDimitry Andric size_t End = Pos + 1; 1196*0b57cec5SDimitry Andric while (isalpha(S[End])) 1197*0b57cec5SDimitry Andric ++End; 1198*0b57cec5SDimitry Andric 1199*0b57cec5SDimitry Andric std::string VarName = S.substr(Pos + 1, End - Pos - 1); 1200*0b57cec5SDimitry Andric assert_with_loc(Variables.find(VarName) != Variables.end(), 1201*0b57cec5SDimitry Andric "Variable not defined!"); 1202*0b57cec5SDimitry Andric S.replace(Pos, End - Pos, Variables.find(VarName)->second.getName()); 1203*0b57cec5SDimitry Andric } 1204*0b57cec5SDimitry Andric 1205*0b57cec5SDimitry Andric return S; 1206*0b57cec5SDimitry Andric } 1207*0b57cec5SDimitry Andric 1208*0b57cec5SDimitry Andric void Intrinsic::initVariables() { 1209*0b57cec5SDimitry Andric Variables.clear(); 1210*0b57cec5SDimitry Andric 1211*0b57cec5SDimitry Andric // Modify the TypeSpec per-argument to get a concrete Type, and create 1212*0b57cec5SDimitry Andric // known variables for each. 1213*0b57cec5SDimitry Andric for (unsigned I = 1; I < Proto.size(); ++I) { 1214*0b57cec5SDimitry Andric char NameC = '0' + (I - 1); 1215*0b57cec5SDimitry Andric std::string Name = "p"; 1216*0b57cec5SDimitry Andric Name.push_back(NameC); 1217*0b57cec5SDimitry Andric 1218*0b57cec5SDimitry Andric Variables[Name] = Variable(Types[I], Name + VariablePostfix); 1219*0b57cec5SDimitry Andric } 1220*0b57cec5SDimitry Andric RetVar = Variable(Types[0], "ret" + VariablePostfix); 1221*0b57cec5SDimitry Andric } 1222*0b57cec5SDimitry Andric 1223*0b57cec5SDimitry Andric void Intrinsic::emitPrototype(StringRef NamePrefix) { 1224*0b57cec5SDimitry Andric if (UseMacro) 1225*0b57cec5SDimitry Andric OS << "#define "; 1226*0b57cec5SDimitry Andric else 1227*0b57cec5SDimitry Andric OS << "__ai " << Types[0].str() << " "; 1228*0b57cec5SDimitry Andric 1229*0b57cec5SDimitry Andric OS << NamePrefix.str() << mangleName(Name, ClassS) << "("; 1230*0b57cec5SDimitry Andric 1231*0b57cec5SDimitry Andric for (unsigned I = 0; I < getNumParams(); ++I) { 1232*0b57cec5SDimitry Andric if (I != 0) 1233*0b57cec5SDimitry Andric OS << ", "; 1234*0b57cec5SDimitry Andric 1235*0b57cec5SDimitry Andric char NameC = '0' + I; 1236*0b57cec5SDimitry Andric std::string Name = "p"; 1237*0b57cec5SDimitry Andric Name.push_back(NameC); 1238*0b57cec5SDimitry Andric assert(Variables.find(Name) != Variables.end()); 1239*0b57cec5SDimitry Andric Variable &V = Variables[Name]; 1240*0b57cec5SDimitry Andric 1241*0b57cec5SDimitry Andric if (!UseMacro) 1242*0b57cec5SDimitry Andric OS << V.getType().str() << " "; 1243*0b57cec5SDimitry Andric OS << V.getName(); 1244*0b57cec5SDimitry Andric } 1245*0b57cec5SDimitry Andric 1246*0b57cec5SDimitry Andric OS << ")"; 1247*0b57cec5SDimitry Andric } 1248*0b57cec5SDimitry Andric 1249*0b57cec5SDimitry Andric void Intrinsic::emitOpeningBrace() { 1250*0b57cec5SDimitry Andric if (UseMacro) 1251*0b57cec5SDimitry Andric OS << " __extension__ ({"; 1252*0b57cec5SDimitry Andric else 1253*0b57cec5SDimitry Andric OS << " {"; 1254*0b57cec5SDimitry Andric emitNewLine(); 1255*0b57cec5SDimitry Andric } 1256*0b57cec5SDimitry Andric 1257*0b57cec5SDimitry Andric void Intrinsic::emitClosingBrace() { 1258*0b57cec5SDimitry Andric if (UseMacro) 1259*0b57cec5SDimitry Andric OS << "})"; 1260*0b57cec5SDimitry Andric else 1261*0b57cec5SDimitry Andric OS << "}"; 1262*0b57cec5SDimitry Andric } 1263*0b57cec5SDimitry Andric 1264*0b57cec5SDimitry Andric void Intrinsic::emitNewLine() { 1265*0b57cec5SDimitry Andric if (UseMacro) 1266*0b57cec5SDimitry Andric OS << " \\\n"; 1267*0b57cec5SDimitry Andric else 1268*0b57cec5SDimitry Andric OS << "\n"; 1269*0b57cec5SDimitry Andric } 1270*0b57cec5SDimitry Andric 1271*0b57cec5SDimitry Andric void Intrinsic::emitReverseVariable(Variable &Dest, Variable &Src) { 1272*0b57cec5SDimitry Andric if (Dest.getType().getNumVectors() > 1) { 1273*0b57cec5SDimitry Andric emitNewLine(); 1274*0b57cec5SDimitry Andric 1275*0b57cec5SDimitry Andric for (unsigned K = 0; K < Dest.getType().getNumVectors(); ++K) { 1276*0b57cec5SDimitry Andric OS << " " << Dest.getName() << ".val[" << K << "] = " 1277*0b57cec5SDimitry Andric << "__builtin_shufflevector(" 1278*0b57cec5SDimitry Andric << Src.getName() << ".val[" << K << "], " 1279*0b57cec5SDimitry Andric << Src.getName() << ".val[" << K << "]"; 1280*0b57cec5SDimitry Andric for (int J = Dest.getType().getNumElements() - 1; J >= 0; --J) 1281*0b57cec5SDimitry Andric OS << ", " << J; 1282*0b57cec5SDimitry Andric OS << ");"; 1283*0b57cec5SDimitry Andric emitNewLine(); 1284*0b57cec5SDimitry Andric } 1285*0b57cec5SDimitry Andric } else { 1286*0b57cec5SDimitry Andric OS << " " << Dest.getName() 1287*0b57cec5SDimitry Andric << " = __builtin_shufflevector(" << Src.getName() << ", " << Src.getName(); 1288*0b57cec5SDimitry Andric for (int J = Dest.getType().getNumElements() - 1; J >= 0; --J) 1289*0b57cec5SDimitry Andric OS << ", " << J; 1290*0b57cec5SDimitry Andric OS << ");"; 1291*0b57cec5SDimitry Andric emitNewLine(); 1292*0b57cec5SDimitry Andric } 1293*0b57cec5SDimitry Andric } 1294*0b57cec5SDimitry Andric 1295*0b57cec5SDimitry Andric void Intrinsic::emitArgumentReversal() { 1296*0b57cec5SDimitry Andric if (BigEndianSafe) 1297*0b57cec5SDimitry Andric return; 1298*0b57cec5SDimitry Andric 1299*0b57cec5SDimitry Andric // Reverse all vector arguments. 1300*0b57cec5SDimitry Andric for (unsigned I = 0; I < getNumParams(); ++I) { 1301*0b57cec5SDimitry Andric std::string Name = "p" + utostr(I); 1302*0b57cec5SDimitry Andric std::string NewName = "rev" + utostr(I); 1303*0b57cec5SDimitry Andric 1304*0b57cec5SDimitry Andric Variable &V = Variables[Name]; 1305*0b57cec5SDimitry Andric Variable NewV(V.getType(), NewName + VariablePostfix); 1306*0b57cec5SDimitry Andric 1307*0b57cec5SDimitry Andric if (!NewV.getType().isVector() || NewV.getType().getNumElements() == 1) 1308*0b57cec5SDimitry Andric continue; 1309*0b57cec5SDimitry Andric 1310*0b57cec5SDimitry Andric OS << " " << NewV.getType().str() << " " << NewV.getName() << ";"; 1311*0b57cec5SDimitry Andric emitReverseVariable(NewV, V); 1312*0b57cec5SDimitry Andric V = NewV; 1313*0b57cec5SDimitry Andric } 1314*0b57cec5SDimitry Andric } 1315*0b57cec5SDimitry Andric 1316*0b57cec5SDimitry Andric void Intrinsic::emitReturnReversal() { 1317*0b57cec5SDimitry Andric if (BigEndianSafe) 1318*0b57cec5SDimitry Andric return; 1319*0b57cec5SDimitry Andric if (!getReturnType().isVector() || getReturnType().isVoid() || 1320*0b57cec5SDimitry Andric getReturnType().getNumElements() == 1) 1321*0b57cec5SDimitry Andric return; 1322*0b57cec5SDimitry Andric emitReverseVariable(RetVar, RetVar); 1323*0b57cec5SDimitry Andric } 1324*0b57cec5SDimitry Andric 1325*0b57cec5SDimitry Andric void Intrinsic::emitShadowedArgs() { 1326*0b57cec5SDimitry Andric // Macro arguments are not type-checked like inline function arguments, 1327*0b57cec5SDimitry Andric // so assign them to local temporaries to get the right type checking. 1328*0b57cec5SDimitry Andric if (!UseMacro) 1329*0b57cec5SDimitry Andric return; 1330*0b57cec5SDimitry Andric 1331*0b57cec5SDimitry Andric for (unsigned I = 0; I < getNumParams(); ++I) { 1332*0b57cec5SDimitry Andric // Do not create a temporary for an immediate argument. 1333*0b57cec5SDimitry Andric // That would defeat the whole point of using a macro! 1334*0b57cec5SDimitry Andric if (hasImmediate() && Proto[I+1] == 'i') 1335*0b57cec5SDimitry Andric continue; 1336*0b57cec5SDimitry Andric // Do not create a temporary for pointer arguments. The input 1337*0b57cec5SDimitry Andric // pointer may have an alignment hint. 1338*0b57cec5SDimitry Andric if (getParamType(I).isPointer()) 1339*0b57cec5SDimitry Andric continue; 1340*0b57cec5SDimitry Andric 1341*0b57cec5SDimitry Andric std::string Name = "p" + utostr(I); 1342*0b57cec5SDimitry Andric 1343*0b57cec5SDimitry Andric assert(Variables.find(Name) != Variables.end()); 1344*0b57cec5SDimitry Andric Variable &V = Variables[Name]; 1345*0b57cec5SDimitry Andric 1346*0b57cec5SDimitry Andric std::string NewName = "s" + utostr(I); 1347*0b57cec5SDimitry Andric Variable V2(V.getType(), NewName + VariablePostfix); 1348*0b57cec5SDimitry Andric 1349*0b57cec5SDimitry Andric OS << " " << V2.getType().str() << " " << V2.getName() << " = " 1350*0b57cec5SDimitry Andric << V.getName() << ";"; 1351*0b57cec5SDimitry Andric emitNewLine(); 1352*0b57cec5SDimitry Andric 1353*0b57cec5SDimitry Andric V = V2; 1354*0b57cec5SDimitry Andric } 1355*0b57cec5SDimitry Andric } 1356*0b57cec5SDimitry Andric 1357*0b57cec5SDimitry Andric // We don't check 'a' in this function, because for builtin function the 1358*0b57cec5SDimitry Andric // argument matching to 'a' uses a vector type splatted from a scalar type. 1359*0b57cec5SDimitry Andric bool Intrinsic::protoHasScalar() const { 1360*0b57cec5SDimitry Andric return (Proto.find('s') != std::string::npos || 1361*0b57cec5SDimitry Andric Proto.find('z') != std::string::npos || 1362*0b57cec5SDimitry Andric Proto.find('r') != std::string::npos || 1363*0b57cec5SDimitry Andric Proto.find('b') != std::string::npos || 1364*0b57cec5SDimitry Andric Proto.find('$') != std::string::npos || 1365*0b57cec5SDimitry Andric Proto.find('y') != std::string::npos || 1366*0b57cec5SDimitry Andric Proto.find('o') != std::string::npos); 1367*0b57cec5SDimitry Andric } 1368*0b57cec5SDimitry Andric 1369*0b57cec5SDimitry Andric void Intrinsic::emitBodyAsBuiltinCall() { 1370*0b57cec5SDimitry Andric std::string S; 1371*0b57cec5SDimitry Andric 1372*0b57cec5SDimitry Andric // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit 1373*0b57cec5SDimitry Andric // sret-like argument. 1374*0b57cec5SDimitry Andric bool SRet = getReturnType().getNumVectors() >= 2; 1375*0b57cec5SDimitry Andric 1376*0b57cec5SDimitry Andric StringRef N = Name; 1377*0b57cec5SDimitry Andric if (hasSplat()) { 1378*0b57cec5SDimitry Andric // Call the non-splat builtin: chop off the "_n" suffix from the name. 1379*0b57cec5SDimitry Andric assert(N.endswith("_n")); 1380*0b57cec5SDimitry Andric N = N.drop_back(2); 1381*0b57cec5SDimitry Andric } 1382*0b57cec5SDimitry Andric 1383*0b57cec5SDimitry Andric ClassKind LocalCK = CK; 1384*0b57cec5SDimitry Andric if (!protoHasScalar()) 1385*0b57cec5SDimitry Andric LocalCK = ClassB; 1386*0b57cec5SDimitry Andric 1387*0b57cec5SDimitry Andric if (!getReturnType().isVoid() && !SRet) 1388*0b57cec5SDimitry Andric S += "(" + RetVar.getType().str() + ") "; 1389*0b57cec5SDimitry Andric 1390*0b57cec5SDimitry Andric S += "__builtin_neon_" + mangleName(N, LocalCK) + "("; 1391*0b57cec5SDimitry Andric 1392*0b57cec5SDimitry Andric if (SRet) 1393*0b57cec5SDimitry Andric S += "&" + RetVar.getName() + ", "; 1394*0b57cec5SDimitry Andric 1395*0b57cec5SDimitry Andric for (unsigned I = 0; I < getNumParams(); ++I) { 1396*0b57cec5SDimitry Andric Variable &V = Variables["p" + utostr(I)]; 1397*0b57cec5SDimitry Andric Type T = V.getType(); 1398*0b57cec5SDimitry Andric 1399*0b57cec5SDimitry Andric // Handle multiple-vector values specially, emitting each subvector as an 1400*0b57cec5SDimitry Andric // argument to the builtin. 1401*0b57cec5SDimitry Andric if (T.getNumVectors() > 1) { 1402*0b57cec5SDimitry Andric // Check if an explicit cast is needed. 1403*0b57cec5SDimitry Andric std::string Cast; 1404*0b57cec5SDimitry Andric if (T.isChar() || T.isPoly() || !T.isSigned()) { 1405*0b57cec5SDimitry Andric Type T2 = T; 1406*0b57cec5SDimitry Andric T2.makeOneVector(); 1407*0b57cec5SDimitry Andric T2.makeInteger(8, /*Signed=*/true); 1408*0b57cec5SDimitry Andric Cast = "(" + T2.str() + ")"; 1409*0b57cec5SDimitry Andric } 1410*0b57cec5SDimitry Andric 1411*0b57cec5SDimitry Andric for (unsigned J = 0; J < T.getNumVectors(); ++J) 1412*0b57cec5SDimitry Andric S += Cast + V.getName() + ".val[" + utostr(J) + "], "; 1413*0b57cec5SDimitry Andric continue; 1414*0b57cec5SDimitry Andric } 1415*0b57cec5SDimitry Andric 1416*0b57cec5SDimitry Andric std::string Arg; 1417*0b57cec5SDimitry Andric Type CastToType = T; 1418*0b57cec5SDimitry Andric if (hasSplat() && I == getSplatIdx()) { 1419*0b57cec5SDimitry Andric Arg = "(" + BaseType.str() + ") {"; 1420*0b57cec5SDimitry Andric for (unsigned J = 0; J < BaseType.getNumElements(); ++J) { 1421*0b57cec5SDimitry Andric if (J != 0) 1422*0b57cec5SDimitry Andric Arg += ", "; 1423*0b57cec5SDimitry Andric Arg += V.getName(); 1424*0b57cec5SDimitry Andric } 1425*0b57cec5SDimitry Andric Arg += "}"; 1426*0b57cec5SDimitry Andric 1427*0b57cec5SDimitry Andric CastToType = BaseType; 1428*0b57cec5SDimitry Andric } else { 1429*0b57cec5SDimitry Andric Arg = V.getName(); 1430*0b57cec5SDimitry Andric } 1431*0b57cec5SDimitry Andric 1432*0b57cec5SDimitry Andric // Check if an explicit cast is needed. 1433*0b57cec5SDimitry Andric if (CastToType.isVector()) { 1434*0b57cec5SDimitry Andric CastToType.makeInteger(8, true); 1435*0b57cec5SDimitry Andric Arg = "(" + CastToType.str() + ")" + Arg; 1436*0b57cec5SDimitry Andric } 1437*0b57cec5SDimitry Andric 1438*0b57cec5SDimitry Andric S += Arg + ", "; 1439*0b57cec5SDimitry Andric } 1440*0b57cec5SDimitry Andric 1441*0b57cec5SDimitry Andric // Extra constant integer to hold type class enum for this function, e.g. s8 1442*0b57cec5SDimitry Andric if (getClassKind(true) == ClassB) { 1443*0b57cec5SDimitry Andric Type ThisTy = getReturnType(); 1444*0b57cec5SDimitry Andric if (Proto[0] == 'v' || isFloatingPointProtoModifier(Proto[0])) 1445*0b57cec5SDimitry Andric ThisTy = getParamType(0); 1446*0b57cec5SDimitry Andric if (ThisTy.isPointer()) 1447*0b57cec5SDimitry Andric ThisTy = getParamType(1); 1448*0b57cec5SDimitry Andric 1449*0b57cec5SDimitry Andric S += utostr(ThisTy.getNeonEnum()); 1450*0b57cec5SDimitry Andric } else { 1451*0b57cec5SDimitry Andric // Remove extraneous ", ". 1452*0b57cec5SDimitry Andric S.pop_back(); 1453*0b57cec5SDimitry Andric S.pop_back(); 1454*0b57cec5SDimitry Andric } 1455*0b57cec5SDimitry Andric S += ");"; 1456*0b57cec5SDimitry Andric 1457*0b57cec5SDimitry Andric std::string RetExpr; 1458*0b57cec5SDimitry Andric if (!SRet && !RetVar.getType().isVoid()) 1459*0b57cec5SDimitry Andric RetExpr = RetVar.getName() + " = "; 1460*0b57cec5SDimitry Andric 1461*0b57cec5SDimitry Andric OS << " " << RetExpr << S; 1462*0b57cec5SDimitry Andric emitNewLine(); 1463*0b57cec5SDimitry Andric } 1464*0b57cec5SDimitry Andric 1465*0b57cec5SDimitry Andric void Intrinsic::emitBody(StringRef CallPrefix) { 1466*0b57cec5SDimitry Andric std::vector<std::string> Lines; 1467*0b57cec5SDimitry Andric 1468*0b57cec5SDimitry Andric assert(RetVar.getType() == Types[0]); 1469*0b57cec5SDimitry Andric // Create a return variable, if we're not void. 1470*0b57cec5SDimitry Andric if (!RetVar.getType().isVoid()) { 1471*0b57cec5SDimitry Andric OS << " " << RetVar.getType().str() << " " << RetVar.getName() << ";"; 1472*0b57cec5SDimitry Andric emitNewLine(); 1473*0b57cec5SDimitry Andric } 1474*0b57cec5SDimitry Andric 1475*0b57cec5SDimitry Andric if (!Body || Body->getValues().empty()) { 1476*0b57cec5SDimitry Andric // Nothing specific to output - must output a builtin. 1477*0b57cec5SDimitry Andric emitBodyAsBuiltinCall(); 1478*0b57cec5SDimitry Andric return; 1479*0b57cec5SDimitry Andric } 1480*0b57cec5SDimitry Andric 1481*0b57cec5SDimitry Andric // We have a list of "things to output". The last should be returned. 1482*0b57cec5SDimitry Andric for (auto *I : Body->getValues()) { 1483*0b57cec5SDimitry Andric if (StringInit *SI = dyn_cast<StringInit>(I)) { 1484*0b57cec5SDimitry Andric Lines.push_back(replaceParamsIn(SI->getAsString())); 1485*0b57cec5SDimitry Andric } else if (DagInit *DI = dyn_cast<DagInit>(I)) { 1486*0b57cec5SDimitry Andric DagEmitter DE(*this, CallPrefix); 1487*0b57cec5SDimitry Andric Lines.push_back(DE.emitDag(DI).second + ";"); 1488*0b57cec5SDimitry Andric } 1489*0b57cec5SDimitry Andric } 1490*0b57cec5SDimitry Andric 1491*0b57cec5SDimitry Andric assert(!Lines.empty() && "Empty def?"); 1492*0b57cec5SDimitry Andric if (!RetVar.getType().isVoid()) 1493*0b57cec5SDimitry Andric Lines.back().insert(0, RetVar.getName() + " = "); 1494*0b57cec5SDimitry Andric 1495*0b57cec5SDimitry Andric for (auto &L : Lines) { 1496*0b57cec5SDimitry Andric OS << " " << L; 1497*0b57cec5SDimitry Andric emitNewLine(); 1498*0b57cec5SDimitry Andric } 1499*0b57cec5SDimitry Andric } 1500*0b57cec5SDimitry Andric 1501*0b57cec5SDimitry Andric void Intrinsic::emitReturn() { 1502*0b57cec5SDimitry Andric if (RetVar.getType().isVoid()) 1503*0b57cec5SDimitry Andric return; 1504*0b57cec5SDimitry Andric if (UseMacro) 1505*0b57cec5SDimitry Andric OS << " " << RetVar.getName() << ";"; 1506*0b57cec5SDimitry Andric else 1507*0b57cec5SDimitry Andric OS << " return " << RetVar.getName() << ";"; 1508*0b57cec5SDimitry Andric emitNewLine(); 1509*0b57cec5SDimitry Andric } 1510*0b57cec5SDimitry Andric 1511*0b57cec5SDimitry Andric std::pair<Type, std::string> Intrinsic::DagEmitter::emitDag(DagInit *DI) { 1512*0b57cec5SDimitry Andric // At this point we should only be seeing a def. 1513*0b57cec5SDimitry Andric DefInit *DefI = cast<DefInit>(DI->getOperator()); 1514*0b57cec5SDimitry Andric std::string Op = DefI->getAsString(); 1515*0b57cec5SDimitry Andric 1516*0b57cec5SDimitry Andric if (Op == "cast" || Op == "bitcast") 1517*0b57cec5SDimitry Andric return emitDagCast(DI, Op == "bitcast"); 1518*0b57cec5SDimitry Andric if (Op == "shuffle") 1519*0b57cec5SDimitry Andric return emitDagShuffle(DI); 1520*0b57cec5SDimitry Andric if (Op == "dup") 1521*0b57cec5SDimitry Andric return emitDagDup(DI); 1522*0b57cec5SDimitry Andric if (Op == "dup_typed") 1523*0b57cec5SDimitry Andric return emitDagDupTyped(DI); 1524*0b57cec5SDimitry Andric if (Op == "splat") 1525*0b57cec5SDimitry Andric return emitDagSplat(DI); 1526*0b57cec5SDimitry Andric if (Op == "save_temp") 1527*0b57cec5SDimitry Andric return emitDagSaveTemp(DI); 1528*0b57cec5SDimitry Andric if (Op == "op") 1529*0b57cec5SDimitry Andric return emitDagOp(DI); 1530*0b57cec5SDimitry Andric if (Op == "call") 1531*0b57cec5SDimitry Andric return emitDagCall(DI); 1532*0b57cec5SDimitry Andric if (Op == "name_replace") 1533*0b57cec5SDimitry Andric return emitDagNameReplace(DI); 1534*0b57cec5SDimitry Andric if (Op == "literal") 1535*0b57cec5SDimitry Andric return emitDagLiteral(DI); 1536*0b57cec5SDimitry Andric assert_with_loc(false, "Unknown operation!"); 1537*0b57cec5SDimitry Andric return std::make_pair(Type::getVoid(), ""); 1538*0b57cec5SDimitry Andric } 1539*0b57cec5SDimitry Andric 1540*0b57cec5SDimitry Andric std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagOp(DagInit *DI) { 1541*0b57cec5SDimitry Andric std::string Op = cast<StringInit>(DI->getArg(0))->getAsUnquotedString(); 1542*0b57cec5SDimitry Andric if (DI->getNumArgs() == 2) { 1543*0b57cec5SDimitry Andric // Unary op. 1544*0b57cec5SDimitry Andric std::pair<Type, std::string> R = 1545*0b57cec5SDimitry Andric emitDagArg(DI->getArg(1), DI->getArgNameStr(1)); 1546*0b57cec5SDimitry Andric return std::make_pair(R.first, Op + R.second); 1547*0b57cec5SDimitry Andric } else { 1548*0b57cec5SDimitry Andric assert(DI->getNumArgs() == 3 && "Can only handle unary and binary ops!"); 1549*0b57cec5SDimitry Andric std::pair<Type, std::string> R1 = 1550*0b57cec5SDimitry Andric emitDagArg(DI->getArg(1), DI->getArgNameStr(1)); 1551*0b57cec5SDimitry Andric std::pair<Type, std::string> R2 = 1552*0b57cec5SDimitry Andric emitDagArg(DI->getArg(2), DI->getArgNameStr(2)); 1553*0b57cec5SDimitry Andric assert_with_loc(R1.first == R2.first, "Argument type mismatch!"); 1554*0b57cec5SDimitry Andric return std::make_pair(R1.first, R1.second + " " + Op + " " + R2.second); 1555*0b57cec5SDimitry Andric } 1556*0b57cec5SDimitry Andric } 1557*0b57cec5SDimitry Andric 1558*0b57cec5SDimitry Andric std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagCall(DagInit *DI) { 1559*0b57cec5SDimitry Andric std::vector<Type> Types; 1560*0b57cec5SDimitry Andric std::vector<std::string> Values; 1561*0b57cec5SDimitry Andric for (unsigned I = 0; I < DI->getNumArgs() - 1; ++I) { 1562*0b57cec5SDimitry Andric std::pair<Type, std::string> R = 1563*0b57cec5SDimitry Andric emitDagArg(DI->getArg(I + 1), DI->getArgNameStr(I + 1)); 1564*0b57cec5SDimitry Andric Types.push_back(R.first); 1565*0b57cec5SDimitry Andric Values.push_back(R.second); 1566*0b57cec5SDimitry Andric } 1567*0b57cec5SDimitry Andric 1568*0b57cec5SDimitry Andric // Look up the called intrinsic. 1569*0b57cec5SDimitry Andric std::string N; 1570*0b57cec5SDimitry Andric if (StringInit *SI = dyn_cast<StringInit>(DI->getArg(0))) 1571*0b57cec5SDimitry Andric N = SI->getAsUnquotedString(); 1572*0b57cec5SDimitry Andric else 1573*0b57cec5SDimitry Andric N = emitDagArg(DI->getArg(0), "").second; 1574*0b57cec5SDimitry Andric Intrinsic &Callee = Intr.Emitter.getIntrinsic(N, Types); 1575*0b57cec5SDimitry Andric 1576*0b57cec5SDimitry Andric // Make sure the callee is known as an early def. 1577*0b57cec5SDimitry Andric Callee.setNeededEarly(); 1578*0b57cec5SDimitry Andric Intr.Dependencies.insert(&Callee); 1579*0b57cec5SDimitry Andric 1580*0b57cec5SDimitry Andric // Now create the call itself. 1581*0b57cec5SDimitry Andric std::string S = CallPrefix.str() + Callee.getMangledName(true) + "("; 1582*0b57cec5SDimitry Andric for (unsigned I = 0; I < DI->getNumArgs() - 1; ++I) { 1583*0b57cec5SDimitry Andric if (I != 0) 1584*0b57cec5SDimitry Andric S += ", "; 1585*0b57cec5SDimitry Andric S += Values[I]; 1586*0b57cec5SDimitry Andric } 1587*0b57cec5SDimitry Andric S += ")"; 1588*0b57cec5SDimitry Andric 1589*0b57cec5SDimitry Andric return std::make_pair(Callee.getReturnType(), S); 1590*0b57cec5SDimitry Andric } 1591*0b57cec5SDimitry Andric 1592*0b57cec5SDimitry Andric std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagCast(DagInit *DI, 1593*0b57cec5SDimitry Andric bool IsBitCast){ 1594*0b57cec5SDimitry Andric // (cast MOD* VAL) -> cast VAL to type given by MOD. 1595*0b57cec5SDimitry Andric std::pair<Type, std::string> R = emitDagArg( 1596*0b57cec5SDimitry Andric DI->getArg(DI->getNumArgs() - 1), 1597*0b57cec5SDimitry Andric DI->getArgNameStr(DI->getNumArgs() - 1)); 1598*0b57cec5SDimitry Andric Type castToType = R.first; 1599*0b57cec5SDimitry Andric for (unsigned ArgIdx = 0; ArgIdx < DI->getNumArgs() - 1; ++ArgIdx) { 1600*0b57cec5SDimitry Andric 1601*0b57cec5SDimitry Andric // MOD can take several forms: 1602*0b57cec5SDimitry Andric // 1. $X - take the type of parameter / variable X. 1603*0b57cec5SDimitry Andric // 2. The value "R" - take the type of the return type. 1604*0b57cec5SDimitry Andric // 3. a type string 1605*0b57cec5SDimitry Andric // 4. The value "U" or "S" to switch the signedness. 1606*0b57cec5SDimitry Andric // 5. The value "H" or "D" to half or double the bitwidth. 1607*0b57cec5SDimitry Andric // 6. The value "8" to convert to 8-bit (signed) integer lanes. 1608*0b57cec5SDimitry Andric if (!DI->getArgNameStr(ArgIdx).empty()) { 1609*0b57cec5SDimitry Andric assert_with_loc(Intr.Variables.find(DI->getArgNameStr(ArgIdx)) != 1610*0b57cec5SDimitry Andric Intr.Variables.end(), 1611*0b57cec5SDimitry Andric "Variable not found"); 1612*0b57cec5SDimitry Andric castToType = Intr.Variables[DI->getArgNameStr(ArgIdx)].getType(); 1613*0b57cec5SDimitry Andric } else { 1614*0b57cec5SDimitry Andric StringInit *SI = dyn_cast<StringInit>(DI->getArg(ArgIdx)); 1615*0b57cec5SDimitry Andric assert_with_loc(SI, "Expected string type or $Name for cast type"); 1616*0b57cec5SDimitry Andric 1617*0b57cec5SDimitry Andric if (SI->getAsUnquotedString() == "R") { 1618*0b57cec5SDimitry Andric castToType = Intr.getReturnType(); 1619*0b57cec5SDimitry Andric } else if (SI->getAsUnquotedString() == "U") { 1620*0b57cec5SDimitry Andric castToType.makeUnsigned(); 1621*0b57cec5SDimitry Andric } else if (SI->getAsUnquotedString() == "S") { 1622*0b57cec5SDimitry Andric castToType.makeSigned(); 1623*0b57cec5SDimitry Andric } else if (SI->getAsUnquotedString() == "H") { 1624*0b57cec5SDimitry Andric castToType.halveLanes(); 1625*0b57cec5SDimitry Andric } else if (SI->getAsUnquotedString() == "D") { 1626*0b57cec5SDimitry Andric castToType.doubleLanes(); 1627*0b57cec5SDimitry Andric } else if (SI->getAsUnquotedString() == "8") { 1628*0b57cec5SDimitry Andric castToType.makeInteger(8, true); 1629*0b57cec5SDimitry Andric } else { 1630*0b57cec5SDimitry Andric castToType = Type::fromTypedefName(SI->getAsUnquotedString()); 1631*0b57cec5SDimitry Andric assert_with_loc(!castToType.isVoid(), "Unknown typedef"); 1632*0b57cec5SDimitry Andric } 1633*0b57cec5SDimitry Andric } 1634*0b57cec5SDimitry Andric } 1635*0b57cec5SDimitry Andric 1636*0b57cec5SDimitry Andric std::string S; 1637*0b57cec5SDimitry Andric if (IsBitCast) { 1638*0b57cec5SDimitry Andric // Emit a reinterpret cast. The second operand must be an lvalue, so create 1639*0b57cec5SDimitry Andric // a temporary. 1640*0b57cec5SDimitry Andric std::string N = "reint"; 1641*0b57cec5SDimitry Andric unsigned I = 0; 1642*0b57cec5SDimitry Andric while (Intr.Variables.find(N) != Intr.Variables.end()) 1643*0b57cec5SDimitry Andric N = "reint" + utostr(++I); 1644*0b57cec5SDimitry Andric Intr.Variables[N] = Variable(R.first, N + Intr.VariablePostfix); 1645*0b57cec5SDimitry Andric 1646*0b57cec5SDimitry Andric Intr.OS << R.first.str() << " " << Intr.Variables[N].getName() << " = " 1647*0b57cec5SDimitry Andric << R.second << ";"; 1648*0b57cec5SDimitry Andric Intr.emitNewLine(); 1649*0b57cec5SDimitry Andric 1650*0b57cec5SDimitry Andric S = "*(" + castToType.str() + " *) &" + Intr.Variables[N].getName() + ""; 1651*0b57cec5SDimitry Andric } else { 1652*0b57cec5SDimitry Andric // Emit a normal (static) cast. 1653*0b57cec5SDimitry Andric S = "(" + castToType.str() + ")(" + R.second + ")"; 1654*0b57cec5SDimitry Andric } 1655*0b57cec5SDimitry Andric 1656*0b57cec5SDimitry Andric return std::make_pair(castToType, S); 1657*0b57cec5SDimitry Andric } 1658*0b57cec5SDimitry Andric 1659*0b57cec5SDimitry Andric std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagShuffle(DagInit *DI){ 1660*0b57cec5SDimitry Andric // See the documentation in arm_neon.td for a description of these operators. 1661*0b57cec5SDimitry Andric class LowHalf : public SetTheory::Operator { 1662*0b57cec5SDimitry Andric public: 1663*0b57cec5SDimitry Andric void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, 1664*0b57cec5SDimitry Andric ArrayRef<SMLoc> Loc) override { 1665*0b57cec5SDimitry Andric SetTheory::RecSet Elts2; 1666*0b57cec5SDimitry Andric ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts2, Loc); 1667*0b57cec5SDimitry Andric Elts.insert(Elts2.begin(), Elts2.begin() + (Elts2.size() / 2)); 1668*0b57cec5SDimitry Andric } 1669*0b57cec5SDimitry Andric }; 1670*0b57cec5SDimitry Andric 1671*0b57cec5SDimitry Andric class HighHalf : public SetTheory::Operator { 1672*0b57cec5SDimitry Andric public: 1673*0b57cec5SDimitry Andric void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, 1674*0b57cec5SDimitry Andric ArrayRef<SMLoc> Loc) override { 1675*0b57cec5SDimitry Andric SetTheory::RecSet Elts2; 1676*0b57cec5SDimitry Andric ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts2, Loc); 1677*0b57cec5SDimitry Andric Elts.insert(Elts2.begin() + (Elts2.size() / 2), Elts2.end()); 1678*0b57cec5SDimitry Andric } 1679*0b57cec5SDimitry Andric }; 1680*0b57cec5SDimitry Andric 1681*0b57cec5SDimitry Andric class Rev : public SetTheory::Operator { 1682*0b57cec5SDimitry Andric unsigned ElementSize; 1683*0b57cec5SDimitry Andric 1684*0b57cec5SDimitry Andric public: 1685*0b57cec5SDimitry Andric Rev(unsigned ElementSize) : ElementSize(ElementSize) {} 1686*0b57cec5SDimitry Andric 1687*0b57cec5SDimitry Andric void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, 1688*0b57cec5SDimitry Andric ArrayRef<SMLoc> Loc) override { 1689*0b57cec5SDimitry Andric SetTheory::RecSet Elts2; 1690*0b57cec5SDimitry Andric ST.evaluate(Expr->arg_begin() + 1, Expr->arg_end(), Elts2, Loc); 1691*0b57cec5SDimitry Andric 1692*0b57cec5SDimitry Andric int64_t VectorSize = cast<IntInit>(Expr->getArg(0))->getValue(); 1693*0b57cec5SDimitry Andric VectorSize /= ElementSize; 1694*0b57cec5SDimitry Andric 1695*0b57cec5SDimitry Andric std::vector<Record *> Revved; 1696*0b57cec5SDimitry Andric for (unsigned VI = 0; VI < Elts2.size(); VI += VectorSize) { 1697*0b57cec5SDimitry Andric for (int LI = VectorSize - 1; LI >= 0; --LI) { 1698*0b57cec5SDimitry Andric Revved.push_back(Elts2[VI + LI]); 1699*0b57cec5SDimitry Andric } 1700*0b57cec5SDimitry Andric } 1701*0b57cec5SDimitry Andric 1702*0b57cec5SDimitry Andric Elts.insert(Revved.begin(), Revved.end()); 1703*0b57cec5SDimitry Andric } 1704*0b57cec5SDimitry Andric }; 1705*0b57cec5SDimitry Andric 1706*0b57cec5SDimitry Andric class MaskExpander : public SetTheory::Expander { 1707*0b57cec5SDimitry Andric unsigned N; 1708*0b57cec5SDimitry Andric 1709*0b57cec5SDimitry Andric public: 1710*0b57cec5SDimitry Andric MaskExpander(unsigned N) : N(N) {} 1711*0b57cec5SDimitry Andric 1712*0b57cec5SDimitry Andric void expand(SetTheory &ST, Record *R, SetTheory::RecSet &Elts) override { 1713*0b57cec5SDimitry Andric unsigned Addend = 0; 1714*0b57cec5SDimitry Andric if (R->getName() == "mask0") 1715*0b57cec5SDimitry Andric Addend = 0; 1716*0b57cec5SDimitry Andric else if (R->getName() == "mask1") 1717*0b57cec5SDimitry Andric Addend = N; 1718*0b57cec5SDimitry Andric else 1719*0b57cec5SDimitry Andric return; 1720*0b57cec5SDimitry Andric for (unsigned I = 0; I < N; ++I) 1721*0b57cec5SDimitry Andric Elts.insert(R->getRecords().getDef("sv" + utostr(I + Addend))); 1722*0b57cec5SDimitry Andric } 1723*0b57cec5SDimitry Andric }; 1724*0b57cec5SDimitry Andric 1725*0b57cec5SDimitry Andric // (shuffle arg1, arg2, sequence) 1726*0b57cec5SDimitry Andric std::pair<Type, std::string> Arg1 = 1727*0b57cec5SDimitry Andric emitDagArg(DI->getArg(0), DI->getArgNameStr(0)); 1728*0b57cec5SDimitry Andric std::pair<Type, std::string> Arg2 = 1729*0b57cec5SDimitry Andric emitDagArg(DI->getArg(1), DI->getArgNameStr(1)); 1730*0b57cec5SDimitry Andric assert_with_loc(Arg1.first == Arg2.first, 1731*0b57cec5SDimitry Andric "Different types in arguments to shuffle!"); 1732*0b57cec5SDimitry Andric 1733*0b57cec5SDimitry Andric SetTheory ST; 1734*0b57cec5SDimitry Andric SetTheory::RecSet Elts; 1735*0b57cec5SDimitry Andric ST.addOperator("lowhalf", llvm::make_unique<LowHalf>()); 1736*0b57cec5SDimitry Andric ST.addOperator("highhalf", llvm::make_unique<HighHalf>()); 1737*0b57cec5SDimitry Andric ST.addOperator("rev", 1738*0b57cec5SDimitry Andric llvm::make_unique<Rev>(Arg1.first.getElementSizeInBits())); 1739*0b57cec5SDimitry Andric ST.addExpander("MaskExpand", 1740*0b57cec5SDimitry Andric llvm::make_unique<MaskExpander>(Arg1.first.getNumElements())); 1741*0b57cec5SDimitry Andric ST.evaluate(DI->getArg(2), Elts, None); 1742*0b57cec5SDimitry Andric 1743*0b57cec5SDimitry Andric std::string S = "__builtin_shufflevector(" + Arg1.second + ", " + Arg2.second; 1744*0b57cec5SDimitry Andric for (auto &E : Elts) { 1745*0b57cec5SDimitry Andric StringRef Name = E->getName(); 1746*0b57cec5SDimitry Andric assert_with_loc(Name.startswith("sv"), 1747*0b57cec5SDimitry Andric "Incorrect element kind in shuffle mask!"); 1748*0b57cec5SDimitry Andric S += ", " + Name.drop_front(2).str(); 1749*0b57cec5SDimitry Andric } 1750*0b57cec5SDimitry Andric S += ")"; 1751*0b57cec5SDimitry Andric 1752*0b57cec5SDimitry Andric // Recalculate the return type - the shuffle may have halved or doubled it. 1753*0b57cec5SDimitry Andric Type T(Arg1.first); 1754*0b57cec5SDimitry Andric if (Elts.size() > T.getNumElements()) { 1755*0b57cec5SDimitry Andric assert_with_loc( 1756*0b57cec5SDimitry Andric Elts.size() == T.getNumElements() * 2, 1757*0b57cec5SDimitry Andric "Can only double or half the number of elements in a shuffle!"); 1758*0b57cec5SDimitry Andric T.doubleLanes(); 1759*0b57cec5SDimitry Andric } else if (Elts.size() < T.getNumElements()) { 1760*0b57cec5SDimitry Andric assert_with_loc( 1761*0b57cec5SDimitry Andric Elts.size() == T.getNumElements() / 2, 1762*0b57cec5SDimitry Andric "Can only double or half the number of elements in a shuffle!"); 1763*0b57cec5SDimitry Andric T.halveLanes(); 1764*0b57cec5SDimitry Andric } 1765*0b57cec5SDimitry Andric 1766*0b57cec5SDimitry Andric return std::make_pair(T, S); 1767*0b57cec5SDimitry Andric } 1768*0b57cec5SDimitry Andric 1769*0b57cec5SDimitry Andric std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagDup(DagInit *DI) { 1770*0b57cec5SDimitry Andric assert_with_loc(DI->getNumArgs() == 1, "dup() expects one argument"); 1771*0b57cec5SDimitry Andric std::pair<Type, std::string> A = emitDagArg(DI->getArg(0), 1772*0b57cec5SDimitry Andric DI->getArgNameStr(0)); 1773*0b57cec5SDimitry Andric assert_with_loc(A.first.isScalar(), "dup() expects a scalar argument"); 1774*0b57cec5SDimitry Andric 1775*0b57cec5SDimitry Andric Type T = Intr.getBaseType(); 1776*0b57cec5SDimitry Andric assert_with_loc(T.isVector(), "dup() used but default type is scalar!"); 1777*0b57cec5SDimitry Andric std::string S = "(" + T.str() + ") {"; 1778*0b57cec5SDimitry Andric for (unsigned I = 0; I < T.getNumElements(); ++I) { 1779*0b57cec5SDimitry Andric if (I != 0) 1780*0b57cec5SDimitry Andric S += ", "; 1781*0b57cec5SDimitry Andric S += A.second; 1782*0b57cec5SDimitry Andric } 1783*0b57cec5SDimitry Andric S += "}"; 1784*0b57cec5SDimitry Andric 1785*0b57cec5SDimitry Andric return std::make_pair(T, S); 1786*0b57cec5SDimitry Andric } 1787*0b57cec5SDimitry Andric 1788*0b57cec5SDimitry Andric std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagDupTyped(DagInit *DI) { 1789*0b57cec5SDimitry Andric assert_with_loc(DI->getNumArgs() == 2, "dup_typed() expects two arguments"); 1790*0b57cec5SDimitry Andric std::pair<Type, std::string> A = emitDagArg(DI->getArg(0), 1791*0b57cec5SDimitry Andric DI->getArgNameStr(0)); 1792*0b57cec5SDimitry Andric std::pair<Type, std::string> B = emitDagArg(DI->getArg(1), 1793*0b57cec5SDimitry Andric DI->getArgNameStr(1)); 1794*0b57cec5SDimitry Andric assert_with_loc(B.first.isScalar(), 1795*0b57cec5SDimitry Andric "dup_typed() requires a scalar as the second argument"); 1796*0b57cec5SDimitry Andric 1797*0b57cec5SDimitry Andric Type T = A.first; 1798*0b57cec5SDimitry Andric assert_with_loc(T.isVector(), "dup_typed() used but target type is scalar!"); 1799*0b57cec5SDimitry Andric std::string S = "(" + T.str() + ") {"; 1800*0b57cec5SDimitry Andric for (unsigned I = 0; I < T.getNumElements(); ++I) { 1801*0b57cec5SDimitry Andric if (I != 0) 1802*0b57cec5SDimitry Andric S += ", "; 1803*0b57cec5SDimitry Andric S += B.second; 1804*0b57cec5SDimitry Andric } 1805*0b57cec5SDimitry Andric S += "}"; 1806*0b57cec5SDimitry Andric 1807*0b57cec5SDimitry Andric return std::make_pair(T, S); 1808*0b57cec5SDimitry Andric } 1809*0b57cec5SDimitry Andric 1810*0b57cec5SDimitry Andric std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagSplat(DagInit *DI) { 1811*0b57cec5SDimitry Andric assert_with_loc(DI->getNumArgs() == 2, "splat() expects two arguments"); 1812*0b57cec5SDimitry Andric std::pair<Type, std::string> A = emitDagArg(DI->getArg(0), 1813*0b57cec5SDimitry Andric DI->getArgNameStr(0)); 1814*0b57cec5SDimitry Andric std::pair<Type, std::string> B = emitDagArg(DI->getArg(1), 1815*0b57cec5SDimitry Andric DI->getArgNameStr(1)); 1816*0b57cec5SDimitry Andric 1817*0b57cec5SDimitry Andric assert_with_loc(B.first.isScalar(), 1818*0b57cec5SDimitry Andric "splat() requires a scalar int as the second argument"); 1819*0b57cec5SDimitry Andric 1820*0b57cec5SDimitry Andric std::string S = "__builtin_shufflevector(" + A.second + ", " + A.second; 1821*0b57cec5SDimitry Andric for (unsigned I = 0; I < Intr.getBaseType().getNumElements(); ++I) { 1822*0b57cec5SDimitry Andric S += ", " + B.second; 1823*0b57cec5SDimitry Andric } 1824*0b57cec5SDimitry Andric S += ")"; 1825*0b57cec5SDimitry Andric 1826*0b57cec5SDimitry Andric return std::make_pair(Intr.getBaseType(), S); 1827*0b57cec5SDimitry Andric } 1828*0b57cec5SDimitry Andric 1829*0b57cec5SDimitry Andric std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagSaveTemp(DagInit *DI) { 1830*0b57cec5SDimitry Andric assert_with_loc(DI->getNumArgs() == 2, "save_temp() expects two arguments"); 1831*0b57cec5SDimitry Andric std::pair<Type, std::string> A = emitDagArg(DI->getArg(1), 1832*0b57cec5SDimitry Andric DI->getArgNameStr(1)); 1833*0b57cec5SDimitry Andric 1834*0b57cec5SDimitry Andric assert_with_loc(!A.first.isVoid(), 1835*0b57cec5SDimitry Andric "Argument to save_temp() must have non-void type!"); 1836*0b57cec5SDimitry Andric 1837*0b57cec5SDimitry Andric std::string N = DI->getArgNameStr(0); 1838*0b57cec5SDimitry Andric assert_with_loc(!N.empty(), 1839*0b57cec5SDimitry Andric "save_temp() expects a name as the first argument"); 1840*0b57cec5SDimitry Andric 1841*0b57cec5SDimitry Andric assert_with_loc(Intr.Variables.find(N) == Intr.Variables.end(), 1842*0b57cec5SDimitry Andric "Variable already defined!"); 1843*0b57cec5SDimitry Andric Intr.Variables[N] = Variable(A.first, N + Intr.VariablePostfix); 1844*0b57cec5SDimitry Andric 1845*0b57cec5SDimitry Andric std::string S = 1846*0b57cec5SDimitry Andric A.first.str() + " " + Intr.Variables[N].getName() + " = " + A.second; 1847*0b57cec5SDimitry Andric 1848*0b57cec5SDimitry Andric return std::make_pair(Type::getVoid(), S); 1849*0b57cec5SDimitry Andric } 1850*0b57cec5SDimitry Andric 1851*0b57cec5SDimitry Andric std::pair<Type, std::string> 1852*0b57cec5SDimitry Andric Intrinsic::DagEmitter::emitDagNameReplace(DagInit *DI) { 1853*0b57cec5SDimitry Andric std::string S = Intr.Name; 1854*0b57cec5SDimitry Andric 1855*0b57cec5SDimitry Andric assert_with_loc(DI->getNumArgs() == 2, "name_replace requires 2 arguments!"); 1856*0b57cec5SDimitry Andric std::string ToReplace = cast<StringInit>(DI->getArg(0))->getAsUnquotedString(); 1857*0b57cec5SDimitry Andric std::string ReplaceWith = cast<StringInit>(DI->getArg(1))->getAsUnquotedString(); 1858*0b57cec5SDimitry Andric 1859*0b57cec5SDimitry Andric size_t Idx = S.find(ToReplace); 1860*0b57cec5SDimitry Andric 1861*0b57cec5SDimitry Andric assert_with_loc(Idx != std::string::npos, "name should contain '" + ToReplace + "'!"); 1862*0b57cec5SDimitry Andric S.replace(Idx, ToReplace.size(), ReplaceWith); 1863*0b57cec5SDimitry Andric 1864*0b57cec5SDimitry Andric return std::make_pair(Type::getVoid(), S); 1865*0b57cec5SDimitry Andric } 1866*0b57cec5SDimitry Andric 1867*0b57cec5SDimitry Andric std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagLiteral(DagInit *DI){ 1868*0b57cec5SDimitry Andric std::string Ty = cast<StringInit>(DI->getArg(0))->getAsUnquotedString(); 1869*0b57cec5SDimitry Andric std::string Value = cast<StringInit>(DI->getArg(1))->getAsUnquotedString(); 1870*0b57cec5SDimitry Andric return std::make_pair(Type::fromTypedefName(Ty), Value); 1871*0b57cec5SDimitry Andric } 1872*0b57cec5SDimitry Andric 1873*0b57cec5SDimitry Andric std::pair<Type, std::string> 1874*0b57cec5SDimitry Andric Intrinsic::DagEmitter::emitDagArg(Init *Arg, std::string ArgName) { 1875*0b57cec5SDimitry Andric if (!ArgName.empty()) { 1876*0b57cec5SDimitry Andric assert_with_loc(!Arg->isComplete(), 1877*0b57cec5SDimitry Andric "Arguments must either be DAGs or names, not both!"); 1878*0b57cec5SDimitry Andric assert_with_loc(Intr.Variables.find(ArgName) != Intr.Variables.end(), 1879*0b57cec5SDimitry Andric "Variable not defined!"); 1880*0b57cec5SDimitry Andric Variable &V = Intr.Variables[ArgName]; 1881*0b57cec5SDimitry Andric return std::make_pair(V.getType(), V.getName()); 1882*0b57cec5SDimitry Andric } 1883*0b57cec5SDimitry Andric 1884*0b57cec5SDimitry Andric assert(Arg && "Neither ArgName nor Arg?!"); 1885*0b57cec5SDimitry Andric DagInit *DI = dyn_cast<DagInit>(Arg); 1886*0b57cec5SDimitry Andric assert_with_loc(DI, "Arguments must either be DAGs or names!"); 1887*0b57cec5SDimitry Andric 1888*0b57cec5SDimitry Andric return emitDag(DI); 1889*0b57cec5SDimitry Andric } 1890*0b57cec5SDimitry Andric 1891*0b57cec5SDimitry Andric std::string Intrinsic::generate() { 1892*0b57cec5SDimitry Andric // Little endian intrinsics are simple and don't require any argument 1893*0b57cec5SDimitry Andric // swapping. 1894*0b57cec5SDimitry Andric OS << "#ifdef __LITTLE_ENDIAN__\n"; 1895*0b57cec5SDimitry Andric 1896*0b57cec5SDimitry Andric generateImpl(false, "", ""); 1897*0b57cec5SDimitry Andric 1898*0b57cec5SDimitry Andric OS << "#else\n"; 1899*0b57cec5SDimitry Andric 1900*0b57cec5SDimitry Andric // Big endian intrinsics are more complex. The user intended these 1901*0b57cec5SDimitry Andric // intrinsics to operate on a vector "as-if" loaded by (V)LDR, 1902*0b57cec5SDimitry Andric // but we load as-if (V)LD1. So we should swap all arguments and 1903*0b57cec5SDimitry Andric // swap the return value too. 1904*0b57cec5SDimitry Andric // 1905*0b57cec5SDimitry Andric // If we call sub-intrinsics, we should call a version that does 1906*0b57cec5SDimitry Andric // not re-swap the arguments! 1907*0b57cec5SDimitry Andric generateImpl(true, "", "__noswap_"); 1908*0b57cec5SDimitry Andric 1909*0b57cec5SDimitry Andric // If we're needed early, create a non-swapping variant for 1910*0b57cec5SDimitry Andric // big-endian. 1911*0b57cec5SDimitry Andric if (NeededEarly) { 1912*0b57cec5SDimitry Andric generateImpl(false, "__noswap_", "__noswap_"); 1913*0b57cec5SDimitry Andric } 1914*0b57cec5SDimitry Andric OS << "#endif\n\n"; 1915*0b57cec5SDimitry Andric 1916*0b57cec5SDimitry Andric return OS.str(); 1917*0b57cec5SDimitry Andric } 1918*0b57cec5SDimitry Andric 1919*0b57cec5SDimitry Andric void Intrinsic::generateImpl(bool ReverseArguments, 1920*0b57cec5SDimitry Andric StringRef NamePrefix, StringRef CallPrefix) { 1921*0b57cec5SDimitry Andric CurrentRecord = R; 1922*0b57cec5SDimitry Andric 1923*0b57cec5SDimitry Andric // If we call a macro, our local variables may be corrupted due to 1924*0b57cec5SDimitry Andric // lack of proper lexical scoping. So, add a globally unique postfix 1925*0b57cec5SDimitry Andric // to every variable. 1926*0b57cec5SDimitry Andric // 1927*0b57cec5SDimitry Andric // indexBody() should have set up the Dependencies set by now. 1928*0b57cec5SDimitry Andric for (auto *I : Dependencies) 1929*0b57cec5SDimitry Andric if (I->UseMacro) { 1930*0b57cec5SDimitry Andric VariablePostfix = "_" + utostr(Emitter.getUniqueNumber()); 1931*0b57cec5SDimitry Andric break; 1932*0b57cec5SDimitry Andric } 1933*0b57cec5SDimitry Andric 1934*0b57cec5SDimitry Andric initVariables(); 1935*0b57cec5SDimitry Andric 1936*0b57cec5SDimitry Andric emitPrototype(NamePrefix); 1937*0b57cec5SDimitry Andric 1938*0b57cec5SDimitry Andric if (IsUnavailable) { 1939*0b57cec5SDimitry Andric OS << " __attribute__((unavailable));"; 1940*0b57cec5SDimitry Andric } else { 1941*0b57cec5SDimitry Andric emitOpeningBrace(); 1942*0b57cec5SDimitry Andric emitShadowedArgs(); 1943*0b57cec5SDimitry Andric if (ReverseArguments) 1944*0b57cec5SDimitry Andric emitArgumentReversal(); 1945*0b57cec5SDimitry Andric emitBody(CallPrefix); 1946*0b57cec5SDimitry Andric if (ReverseArguments) 1947*0b57cec5SDimitry Andric emitReturnReversal(); 1948*0b57cec5SDimitry Andric emitReturn(); 1949*0b57cec5SDimitry Andric emitClosingBrace(); 1950*0b57cec5SDimitry Andric } 1951*0b57cec5SDimitry Andric OS << "\n"; 1952*0b57cec5SDimitry Andric 1953*0b57cec5SDimitry Andric CurrentRecord = nullptr; 1954*0b57cec5SDimitry Andric } 1955*0b57cec5SDimitry Andric 1956*0b57cec5SDimitry Andric void Intrinsic::indexBody() { 1957*0b57cec5SDimitry Andric CurrentRecord = R; 1958*0b57cec5SDimitry Andric 1959*0b57cec5SDimitry Andric initVariables(); 1960*0b57cec5SDimitry Andric emitBody(""); 1961*0b57cec5SDimitry Andric OS.str(""); 1962*0b57cec5SDimitry Andric 1963*0b57cec5SDimitry Andric CurrentRecord = nullptr; 1964*0b57cec5SDimitry Andric } 1965*0b57cec5SDimitry Andric 1966*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1967*0b57cec5SDimitry Andric // NeonEmitter implementation 1968*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1969*0b57cec5SDimitry Andric 1970*0b57cec5SDimitry Andric Intrinsic &NeonEmitter::getIntrinsic(StringRef Name, ArrayRef<Type> Types) { 1971*0b57cec5SDimitry Andric // First, look up the name in the intrinsic map. 1972*0b57cec5SDimitry Andric assert_with_loc(IntrinsicMap.find(Name.str()) != IntrinsicMap.end(), 1973*0b57cec5SDimitry Andric ("Intrinsic '" + Name + "' not found!").str()); 1974*0b57cec5SDimitry Andric auto &V = IntrinsicMap.find(Name.str())->second; 1975*0b57cec5SDimitry Andric std::vector<Intrinsic *> GoodVec; 1976*0b57cec5SDimitry Andric 1977*0b57cec5SDimitry Andric // Create a string to print if we end up failing. 1978*0b57cec5SDimitry Andric std::string ErrMsg = "looking up intrinsic '" + Name.str() + "("; 1979*0b57cec5SDimitry Andric for (unsigned I = 0; I < Types.size(); ++I) { 1980*0b57cec5SDimitry Andric if (I != 0) 1981*0b57cec5SDimitry Andric ErrMsg += ", "; 1982*0b57cec5SDimitry Andric ErrMsg += Types[I].str(); 1983*0b57cec5SDimitry Andric } 1984*0b57cec5SDimitry Andric ErrMsg += ")'\n"; 1985*0b57cec5SDimitry Andric ErrMsg += "Available overloads:\n"; 1986*0b57cec5SDimitry Andric 1987*0b57cec5SDimitry Andric // Now, look through each intrinsic implementation and see if the types are 1988*0b57cec5SDimitry Andric // compatible. 1989*0b57cec5SDimitry Andric for (auto &I : V) { 1990*0b57cec5SDimitry Andric ErrMsg += " - " + I.getReturnType().str() + " " + I.getMangledName(); 1991*0b57cec5SDimitry Andric ErrMsg += "("; 1992*0b57cec5SDimitry Andric for (unsigned A = 0; A < I.getNumParams(); ++A) { 1993*0b57cec5SDimitry Andric if (A != 0) 1994*0b57cec5SDimitry Andric ErrMsg += ", "; 1995*0b57cec5SDimitry Andric ErrMsg += I.getParamType(A).str(); 1996*0b57cec5SDimitry Andric } 1997*0b57cec5SDimitry Andric ErrMsg += ")\n"; 1998*0b57cec5SDimitry Andric 1999*0b57cec5SDimitry Andric if (I.getNumParams() != Types.size()) 2000*0b57cec5SDimitry Andric continue; 2001*0b57cec5SDimitry Andric 2002*0b57cec5SDimitry Andric bool Good = true; 2003*0b57cec5SDimitry Andric for (unsigned Arg = 0; Arg < Types.size(); ++Arg) { 2004*0b57cec5SDimitry Andric if (I.getParamType(Arg) != Types[Arg]) { 2005*0b57cec5SDimitry Andric Good = false; 2006*0b57cec5SDimitry Andric break; 2007*0b57cec5SDimitry Andric } 2008*0b57cec5SDimitry Andric } 2009*0b57cec5SDimitry Andric if (Good) 2010*0b57cec5SDimitry Andric GoodVec.push_back(&I); 2011*0b57cec5SDimitry Andric } 2012*0b57cec5SDimitry Andric 2013*0b57cec5SDimitry Andric assert_with_loc(!GoodVec.empty(), 2014*0b57cec5SDimitry Andric "No compatible intrinsic found - " + ErrMsg); 2015*0b57cec5SDimitry Andric assert_with_loc(GoodVec.size() == 1, "Multiple overloads found - " + ErrMsg); 2016*0b57cec5SDimitry Andric 2017*0b57cec5SDimitry Andric return *GoodVec.front(); 2018*0b57cec5SDimitry Andric } 2019*0b57cec5SDimitry Andric 2020*0b57cec5SDimitry Andric void NeonEmitter::createIntrinsic(Record *R, 2021*0b57cec5SDimitry Andric SmallVectorImpl<Intrinsic *> &Out) { 2022*0b57cec5SDimitry Andric std::string Name = R->getValueAsString("Name"); 2023*0b57cec5SDimitry Andric std::string Proto = R->getValueAsString("Prototype"); 2024*0b57cec5SDimitry Andric std::string Types = R->getValueAsString("Types"); 2025*0b57cec5SDimitry Andric Record *OperationRec = R->getValueAsDef("Operation"); 2026*0b57cec5SDimitry Andric bool CartesianProductOfTypes = R->getValueAsBit("CartesianProductOfTypes"); 2027*0b57cec5SDimitry Andric bool BigEndianSafe = R->getValueAsBit("BigEndianSafe"); 2028*0b57cec5SDimitry Andric std::string Guard = R->getValueAsString("ArchGuard"); 2029*0b57cec5SDimitry Andric bool IsUnavailable = OperationRec->getValueAsBit("Unavailable"); 2030*0b57cec5SDimitry Andric 2031*0b57cec5SDimitry Andric // Set the global current record. This allows assert_with_loc to produce 2032*0b57cec5SDimitry Andric // decent location information even when highly nested. 2033*0b57cec5SDimitry Andric CurrentRecord = R; 2034*0b57cec5SDimitry Andric 2035*0b57cec5SDimitry Andric ListInit *Body = OperationRec->getValueAsListInit("Ops"); 2036*0b57cec5SDimitry Andric 2037*0b57cec5SDimitry Andric std::vector<TypeSpec> TypeSpecs = TypeSpec::fromTypeSpecs(Types); 2038*0b57cec5SDimitry Andric 2039*0b57cec5SDimitry Andric ClassKind CK = ClassNone; 2040*0b57cec5SDimitry Andric if (R->getSuperClasses().size() >= 2) 2041*0b57cec5SDimitry Andric CK = ClassMap[R->getSuperClasses()[1].first]; 2042*0b57cec5SDimitry Andric 2043*0b57cec5SDimitry Andric std::vector<std::pair<TypeSpec, TypeSpec>> NewTypeSpecs; 2044*0b57cec5SDimitry Andric for (auto TS : TypeSpecs) { 2045*0b57cec5SDimitry Andric if (CartesianProductOfTypes) { 2046*0b57cec5SDimitry Andric Type DefaultT(TS, 'd'); 2047*0b57cec5SDimitry Andric for (auto SrcTS : TypeSpecs) { 2048*0b57cec5SDimitry Andric Type DefaultSrcT(SrcTS, 'd'); 2049*0b57cec5SDimitry Andric if (TS == SrcTS || 2050*0b57cec5SDimitry Andric DefaultSrcT.getSizeInBits() != DefaultT.getSizeInBits()) 2051*0b57cec5SDimitry Andric continue; 2052*0b57cec5SDimitry Andric NewTypeSpecs.push_back(std::make_pair(TS, SrcTS)); 2053*0b57cec5SDimitry Andric } 2054*0b57cec5SDimitry Andric } else { 2055*0b57cec5SDimitry Andric NewTypeSpecs.push_back(std::make_pair(TS, TS)); 2056*0b57cec5SDimitry Andric } 2057*0b57cec5SDimitry Andric } 2058*0b57cec5SDimitry Andric 2059*0b57cec5SDimitry Andric llvm::sort(NewTypeSpecs); 2060*0b57cec5SDimitry Andric NewTypeSpecs.erase(std::unique(NewTypeSpecs.begin(), NewTypeSpecs.end()), 2061*0b57cec5SDimitry Andric NewTypeSpecs.end()); 2062*0b57cec5SDimitry Andric auto &Entry = IntrinsicMap[Name]; 2063*0b57cec5SDimitry Andric 2064*0b57cec5SDimitry Andric for (auto &I : NewTypeSpecs) { 2065*0b57cec5SDimitry Andric Entry.emplace_back(R, Name, Proto, I.first, I.second, CK, Body, *this, 2066*0b57cec5SDimitry Andric Guard, IsUnavailable, BigEndianSafe); 2067*0b57cec5SDimitry Andric Out.push_back(&Entry.back()); 2068*0b57cec5SDimitry Andric } 2069*0b57cec5SDimitry Andric 2070*0b57cec5SDimitry Andric CurrentRecord = nullptr; 2071*0b57cec5SDimitry Andric } 2072*0b57cec5SDimitry Andric 2073*0b57cec5SDimitry Andric /// genBuiltinsDef: Generate the BuiltinsARM.def and BuiltinsAArch64.def 2074*0b57cec5SDimitry Andric /// declaration of builtins, checking for unique builtin declarations. 2075*0b57cec5SDimitry Andric void NeonEmitter::genBuiltinsDef(raw_ostream &OS, 2076*0b57cec5SDimitry Andric SmallVectorImpl<Intrinsic *> &Defs) { 2077*0b57cec5SDimitry Andric OS << "#ifdef GET_NEON_BUILTINS\n"; 2078*0b57cec5SDimitry Andric 2079*0b57cec5SDimitry Andric // We only want to emit a builtin once, and we want to emit them in 2080*0b57cec5SDimitry Andric // alphabetical order, so use a std::set. 2081*0b57cec5SDimitry Andric std::set<std::string> Builtins; 2082*0b57cec5SDimitry Andric 2083*0b57cec5SDimitry Andric for (auto *Def : Defs) { 2084*0b57cec5SDimitry Andric if (Def->hasBody()) 2085*0b57cec5SDimitry Andric continue; 2086*0b57cec5SDimitry Andric // Functions with 'a' (the splat code) in the type prototype should not get 2087*0b57cec5SDimitry Andric // their own builtin as they use the non-splat variant. 2088*0b57cec5SDimitry Andric if (Def->hasSplat()) 2089*0b57cec5SDimitry Andric continue; 2090*0b57cec5SDimitry Andric 2091*0b57cec5SDimitry Andric std::string S = "BUILTIN(__builtin_neon_" + Def->getMangledName() + ", \""; 2092*0b57cec5SDimitry Andric 2093*0b57cec5SDimitry Andric S += Def->getBuiltinTypeStr(); 2094*0b57cec5SDimitry Andric S += "\", \"n\")"; 2095*0b57cec5SDimitry Andric 2096*0b57cec5SDimitry Andric Builtins.insert(S); 2097*0b57cec5SDimitry Andric } 2098*0b57cec5SDimitry Andric 2099*0b57cec5SDimitry Andric for (auto &S : Builtins) 2100*0b57cec5SDimitry Andric OS << S << "\n"; 2101*0b57cec5SDimitry Andric OS << "#endif\n\n"; 2102*0b57cec5SDimitry Andric } 2103*0b57cec5SDimitry Andric 2104*0b57cec5SDimitry Andric /// Generate the ARM and AArch64 overloaded type checking code for 2105*0b57cec5SDimitry Andric /// SemaChecking.cpp, checking for unique builtin declarations. 2106*0b57cec5SDimitry Andric void NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS, 2107*0b57cec5SDimitry Andric SmallVectorImpl<Intrinsic *> &Defs) { 2108*0b57cec5SDimitry Andric OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n"; 2109*0b57cec5SDimitry Andric 2110*0b57cec5SDimitry Andric // We record each overload check line before emitting because subsequent Inst 2111*0b57cec5SDimitry Andric // definitions may extend the number of permitted types (i.e. augment the 2112*0b57cec5SDimitry Andric // Mask). Use std::map to avoid sorting the table by hash number. 2113*0b57cec5SDimitry Andric struct OverloadInfo { 2114*0b57cec5SDimitry Andric uint64_t Mask; 2115*0b57cec5SDimitry Andric int PtrArgNum; 2116*0b57cec5SDimitry Andric bool HasConstPtr; 2117*0b57cec5SDimitry Andric OverloadInfo() : Mask(0ULL), PtrArgNum(0), HasConstPtr(false) {} 2118*0b57cec5SDimitry Andric }; 2119*0b57cec5SDimitry Andric std::map<std::string, OverloadInfo> OverloadMap; 2120*0b57cec5SDimitry Andric 2121*0b57cec5SDimitry Andric for (auto *Def : Defs) { 2122*0b57cec5SDimitry Andric // If the def has a body (that is, it has Operation DAGs), it won't call 2123*0b57cec5SDimitry Andric // __builtin_neon_* so we don't need to generate a definition for it. 2124*0b57cec5SDimitry Andric if (Def->hasBody()) 2125*0b57cec5SDimitry Andric continue; 2126*0b57cec5SDimitry Andric // Functions with 'a' (the splat code) in the type prototype should not get 2127*0b57cec5SDimitry Andric // their own builtin as they use the non-splat variant. 2128*0b57cec5SDimitry Andric if (Def->hasSplat()) 2129*0b57cec5SDimitry Andric continue; 2130*0b57cec5SDimitry Andric // Functions which have a scalar argument cannot be overloaded, no need to 2131*0b57cec5SDimitry Andric // check them if we are emitting the type checking code. 2132*0b57cec5SDimitry Andric if (Def->protoHasScalar()) 2133*0b57cec5SDimitry Andric continue; 2134*0b57cec5SDimitry Andric 2135*0b57cec5SDimitry Andric uint64_t Mask = 0ULL; 2136*0b57cec5SDimitry Andric Type Ty = Def->getReturnType(); 2137*0b57cec5SDimitry Andric if (Def->getProto()[0] == 'v' || 2138*0b57cec5SDimitry Andric isFloatingPointProtoModifier(Def->getProto()[0])) 2139*0b57cec5SDimitry Andric Ty = Def->getParamType(0); 2140*0b57cec5SDimitry Andric if (Ty.isPointer()) 2141*0b57cec5SDimitry Andric Ty = Def->getParamType(1); 2142*0b57cec5SDimitry Andric 2143*0b57cec5SDimitry Andric Mask |= 1ULL << Ty.getNeonEnum(); 2144*0b57cec5SDimitry Andric 2145*0b57cec5SDimitry Andric // Check if the function has a pointer or const pointer argument. 2146*0b57cec5SDimitry Andric std::string Proto = Def->getProto(); 2147*0b57cec5SDimitry Andric int PtrArgNum = -1; 2148*0b57cec5SDimitry Andric bool HasConstPtr = false; 2149*0b57cec5SDimitry Andric for (unsigned I = 0; I < Def->getNumParams(); ++I) { 2150*0b57cec5SDimitry Andric char ArgType = Proto[I + 1]; 2151*0b57cec5SDimitry Andric if (ArgType == 'c') { 2152*0b57cec5SDimitry Andric HasConstPtr = true; 2153*0b57cec5SDimitry Andric PtrArgNum = I; 2154*0b57cec5SDimitry Andric break; 2155*0b57cec5SDimitry Andric } 2156*0b57cec5SDimitry Andric if (ArgType == 'p') { 2157*0b57cec5SDimitry Andric PtrArgNum = I; 2158*0b57cec5SDimitry Andric break; 2159*0b57cec5SDimitry Andric } 2160*0b57cec5SDimitry Andric } 2161*0b57cec5SDimitry Andric // For sret builtins, adjust the pointer argument index. 2162*0b57cec5SDimitry Andric if (PtrArgNum >= 0 && Def->getReturnType().getNumVectors() > 1) 2163*0b57cec5SDimitry Andric PtrArgNum += 1; 2164*0b57cec5SDimitry Andric 2165*0b57cec5SDimitry Andric std::string Name = Def->getName(); 2166*0b57cec5SDimitry Andric // Omit type checking for the pointer arguments of vld1_lane, vld1_dup, 2167*0b57cec5SDimitry Andric // and vst1_lane intrinsics. Using a pointer to the vector element 2168*0b57cec5SDimitry Andric // type with one of those operations causes codegen to select an aligned 2169*0b57cec5SDimitry Andric // load/store instruction. If you want an unaligned operation, 2170*0b57cec5SDimitry Andric // the pointer argument needs to have less alignment than element type, 2171*0b57cec5SDimitry Andric // so just accept any pointer type. 2172*0b57cec5SDimitry Andric if (Name == "vld1_lane" || Name == "vld1_dup" || Name == "vst1_lane") { 2173*0b57cec5SDimitry Andric PtrArgNum = -1; 2174*0b57cec5SDimitry Andric HasConstPtr = false; 2175*0b57cec5SDimitry Andric } 2176*0b57cec5SDimitry Andric 2177*0b57cec5SDimitry Andric if (Mask) { 2178*0b57cec5SDimitry Andric std::string Name = Def->getMangledName(); 2179*0b57cec5SDimitry Andric OverloadMap.insert(std::make_pair(Name, OverloadInfo())); 2180*0b57cec5SDimitry Andric OverloadInfo &OI = OverloadMap[Name]; 2181*0b57cec5SDimitry Andric OI.Mask |= Mask; 2182*0b57cec5SDimitry Andric OI.PtrArgNum |= PtrArgNum; 2183*0b57cec5SDimitry Andric OI.HasConstPtr = HasConstPtr; 2184*0b57cec5SDimitry Andric } 2185*0b57cec5SDimitry Andric } 2186*0b57cec5SDimitry Andric 2187*0b57cec5SDimitry Andric for (auto &I : OverloadMap) { 2188*0b57cec5SDimitry Andric OverloadInfo &OI = I.second; 2189*0b57cec5SDimitry Andric 2190*0b57cec5SDimitry Andric OS << "case NEON::BI__builtin_neon_" << I.first << ": "; 2191*0b57cec5SDimitry Andric OS << "mask = 0x" << Twine::utohexstr(OI.Mask) << "ULL"; 2192*0b57cec5SDimitry Andric if (OI.PtrArgNum >= 0) 2193*0b57cec5SDimitry Andric OS << "; PtrArgNum = " << OI.PtrArgNum; 2194*0b57cec5SDimitry Andric if (OI.HasConstPtr) 2195*0b57cec5SDimitry Andric OS << "; HasConstPtr = true"; 2196*0b57cec5SDimitry Andric OS << "; break;\n"; 2197*0b57cec5SDimitry Andric } 2198*0b57cec5SDimitry Andric OS << "#endif\n\n"; 2199*0b57cec5SDimitry Andric } 2200*0b57cec5SDimitry Andric 2201*0b57cec5SDimitry Andric void NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS, 2202*0b57cec5SDimitry Andric SmallVectorImpl<Intrinsic *> &Defs) { 2203*0b57cec5SDimitry Andric OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n"; 2204*0b57cec5SDimitry Andric 2205*0b57cec5SDimitry Andric std::set<std::string> Emitted; 2206*0b57cec5SDimitry Andric 2207*0b57cec5SDimitry Andric for (auto *Def : Defs) { 2208*0b57cec5SDimitry Andric if (Def->hasBody()) 2209*0b57cec5SDimitry Andric continue; 2210*0b57cec5SDimitry Andric // Functions with 'a' (the splat code) in the type prototype should not get 2211*0b57cec5SDimitry Andric // their own builtin as they use the non-splat variant. 2212*0b57cec5SDimitry Andric if (Def->hasSplat()) 2213*0b57cec5SDimitry Andric continue; 2214*0b57cec5SDimitry Andric // Functions which do not have an immediate do not need to have range 2215*0b57cec5SDimitry Andric // checking code emitted. 2216*0b57cec5SDimitry Andric if (!Def->hasImmediate()) 2217*0b57cec5SDimitry Andric continue; 2218*0b57cec5SDimitry Andric if (Emitted.find(Def->getMangledName()) != Emitted.end()) 2219*0b57cec5SDimitry Andric continue; 2220*0b57cec5SDimitry Andric 2221*0b57cec5SDimitry Andric std::string LowerBound, UpperBound; 2222*0b57cec5SDimitry Andric 2223*0b57cec5SDimitry Andric Record *R = Def->getRecord(); 2224*0b57cec5SDimitry Andric if (R->getValueAsBit("isVCVT_N")) { 2225*0b57cec5SDimitry Andric // VCVT between floating- and fixed-point values takes an immediate 2226*0b57cec5SDimitry Andric // in the range [1, 32) for f32 or [1, 64) for f64 or [1, 16) for f16. 2227*0b57cec5SDimitry Andric LowerBound = "1"; 2228*0b57cec5SDimitry Andric if (Def->getBaseType().getElementSizeInBits() == 16 || 2229*0b57cec5SDimitry Andric Def->getName().find('h') != std::string::npos) 2230*0b57cec5SDimitry Andric // VCVTh operating on FP16 intrinsics in range [1, 16) 2231*0b57cec5SDimitry Andric UpperBound = "15"; 2232*0b57cec5SDimitry Andric else if (Def->getBaseType().getElementSizeInBits() == 32) 2233*0b57cec5SDimitry Andric UpperBound = "31"; 2234*0b57cec5SDimitry Andric else 2235*0b57cec5SDimitry Andric UpperBound = "63"; 2236*0b57cec5SDimitry Andric } else if (R->getValueAsBit("isScalarShift")) { 2237*0b57cec5SDimitry Andric // Right shifts have an 'r' in the name, left shifts do not. Convert 2238*0b57cec5SDimitry Andric // instructions have the same bounds and right shifts. 2239*0b57cec5SDimitry Andric if (Def->getName().find('r') != std::string::npos || 2240*0b57cec5SDimitry Andric Def->getName().find("cvt") != std::string::npos) 2241*0b57cec5SDimitry Andric LowerBound = "1"; 2242*0b57cec5SDimitry Andric 2243*0b57cec5SDimitry Andric UpperBound = utostr(Def->getReturnType().getElementSizeInBits() - 1); 2244*0b57cec5SDimitry Andric } else if (R->getValueAsBit("isShift")) { 2245*0b57cec5SDimitry Andric // Builtins which are overloaded by type will need to have their upper 2246*0b57cec5SDimitry Andric // bound computed at Sema time based on the type constant. 2247*0b57cec5SDimitry Andric 2248*0b57cec5SDimitry Andric // Right shifts have an 'r' in the name, left shifts do not. 2249*0b57cec5SDimitry Andric if (Def->getName().find('r') != std::string::npos) 2250*0b57cec5SDimitry Andric LowerBound = "1"; 2251*0b57cec5SDimitry Andric UpperBound = "RFT(TV, true)"; 2252*0b57cec5SDimitry Andric } else if (Def->getClassKind(true) == ClassB) { 2253*0b57cec5SDimitry Andric // ClassB intrinsics have a type (and hence lane number) that is only 2254*0b57cec5SDimitry Andric // known at runtime. 2255*0b57cec5SDimitry Andric if (R->getValueAsBit("isLaneQ")) 2256*0b57cec5SDimitry Andric UpperBound = "RFT(TV, false, true)"; 2257*0b57cec5SDimitry Andric else 2258*0b57cec5SDimitry Andric UpperBound = "RFT(TV, false, false)"; 2259*0b57cec5SDimitry Andric } else { 2260*0b57cec5SDimitry Andric // The immediate generally refers to a lane in the preceding argument. 2261*0b57cec5SDimitry Andric assert(Def->getImmediateIdx() > 0); 2262*0b57cec5SDimitry Andric Type T = Def->getParamType(Def->getImmediateIdx() - 1); 2263*0b57cec5SDimitry Andric UpperBound = utostr(T.getNumElements() - 1); 2264*0b57cec5SDimitry Andric } 2265*0b57cec5SDimitry Andric 2266*0b57cec5SDimitry Andric // Calculate the index of the immediate that should be range checked. 2267*0b57cec5SDimitry Andric unsigned Idx = Def->getNumParams(); 2268*0b57cec5SDimitry Andric if (Def->hasImmediate()) 2269*0b57cec5SDimitry Andric Idx = Def->getGeneratedParamIdx(Def->getImmediateIdx()); 2270*0b57cec5SDimitry Andric 2271*0b57cec5SDimitry Andric OS << "case NEON::BI__builtin_neon_" << Def->getMangledName() << ": " 2272*0b57cec5SDimitry Andric << "i = " << Idx << ";"; 2273*0b57cec5SDimitry Andric if (!LowerBound.empty()) 2274*0b57cec5SDimitry Andric OS << " l = " << LowerBound << ";"; 2275*0b57cec5SDimitry Andric if (!UpperBound.empty()) 2276*0b57cec5SDimitry Andric OS << " u = " << UpperBound << ";"; 2277*0b57cec5SDimitry Andric OS << " break;\n"; 2278*0b57cec5SDimitry Andric 2279*0b57cec5SDimitry Andric Emitted.insert(Def->getMangledName()); 2280*0b57cec5SDimitry Andric } 2281*0b57cec5SDimitry Andric 2282*0b57cec5SDimitry Andric OS << "#endif\n\n"; 2283*0b57cec5SDimitry Andric } 2284*0b57cec5SDimitry Andric 2285*0b57cec5SDimitry Andric /// runHeader - Emit a file with sections defining: 2286*0b57cec5SDimitry Andric /// 1. the NEON section of BuiltinsARM.def and BuiltinsAArch64.def. 2287*0b57cec5SDimitry Andric /// 2. the SemaChecking code for the type overload checking. 2288*0b57cec5SDimitry Andric /// 3. the SemaChecking code for validation of intrinsic immediate arguments. 2289*0b57cec5SDimitry Andric void NeonEmitter::runHeader(raw_ostream &OS) { 2290*0b57cec5SDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 2291*0b57cec5SDimitry Andric 2292*0b57cec5SDimitry Andric SmallVector<Intrinsic *, 128> Defs; 2293*0b57cec5SDimitry Andric for (auto *R : RV) 2294*0b57cec5SDimitry Andric createIntrinsic(R, Defs); 2295*0b57cec5SDimitry Andric 2296*0b57cec5SDimitry Andric // Generate shared BuiltinsXXX.def 2297*0b57cec5SDimitry Andric genBuiltinsDef(OS, Defs); 2298*0b57cec5SDimitry Andric 2299*0b57cec5SDimitry Andric // Generate ARM overloaded type checking code for SemaChecking.cpp 2300*0b57cec5SDimitry Andric genOverloadTypeCheckCode(OS, Defs); 2301*0b57cec5SDimitry Andric 2302*0b57cec5SDimitry Andric // Generate ARM range checking code for shift/lane immediates. 2303*0b57cec5SDimitry Andric genIntrinsicRangeCheckCode(OS, Defs); 2304*0b57cec5SDimitry Andric } 2305*0b57cec5SDimitry Andric 2306*0b57cec5SDimitry Andric /// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h 2307*0b57cec5SDimitry Andric /// is comprised of type definitions and function declarations. 2308*0b57cec5SDimitry Andric void NeonEmitter::run(raw_ostream &OS) { 2309*0b57cec5SDimitry Andric OS << "/*===---- arm_neon.h - ARM Neon intrinsics " 2310*0b57cec5SDimitry Andric "------------------------------" 2311*0b57cec5SDimitry Andric "---===\n" 2312*0b57cec5SDimitry Andric " *\n" 2313*0b57cec5SDimitry Andric " * Permission is hereby granted, free of charge, to any person " 2314*0b57cec5SDimitry Andric "obtaining " 2315*0b57cec5SDimitry Andric "a copy\n" 2316*0b57cec5SDimitry Andric " * of this software and associated documentation files (the " 2317*0b57cec5SDimitry Andric "\"Software\")," 2318*0b57cec5SDimitry Andric " to deal\n" 2319*0b57cec5SDimitry Andric " * in the Software without restriction, including without limitation " 2320*0b57cec5SDimitry Andric "the " 2321*0b57cec5SDimitry Andric "rights\n" 2322*0b57cec5SDimitry Andric " * to use, copy, modify, merge, publish, distribute, sublicense, " 2323*0b57cec5SDimitry Andric "and/or sell\n" 2324*0b57cec5SDimitry Andric " * copies of the Software, and to permit persons to whom the Software " 2325*0b57cec5SDimitry Andric "is\n" 2326*0b57cec5SDimitry Andric " * furnished to do so, subject to the following conditions:\n" 2327*0b57cec5SDimitry Andric " *\n" 2328*0b57cec5SDimitry Andric " * The above copyright notice and this permission notice shall be " 2329*0b57cec5SDimitry Andric "included in\n" 2330*0b57cec5SDimitry Andric " * all copies or substantial portions of the Software.\n" 2331*0b57cec5SDimitry Andric " *\n" 2332*0b57cec5SDimitry Andric " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, " 2333*0b57cec5SDimitry Andric "EXPRESS OR\n" 2334*0b57cec5SDimitry Andric " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " 2335*0b57cec5SDimitry Andric "MERCHANTABILITY,\n" 2336*0b57cec5SDimitry Andric " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT " 2337*0b57cec5SDimitry Andric "SHALL THE\n" 2338*0b57cec5SDimitry Andric " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR " 2339*0b57cec5SDimitry Andric "OTHER\n" 2340*0b57cec5SDimitry Andric " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, " 2341*0b57cec5SDimitry Andric "ARISING FROM,\n" 2342*0b57cec5SDimitry Andric " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER " 2343*0b57cec5SDimitry Andric "DEALINGS IN\n" 2344*0b57cec5SDimitry Andric " * THE SOFTWARE.\n" 2345*0b57cec5SDimitry Andric " *\n" 2346*0b57cec5SDimitry Andric " *===-----------------------------------------------------------------" 2347*0b57cec5SDimitry Andric "---" 2348*0b57cec5SDimitry Andric "---===\n" 2349*0b57cec5SDimitry Andric " */\n\n"; 2350*0b57cec5SDimitry Andric 2351*0b57cec5SDimitry Andric OS << "#ifndef __ARM_NEON_H\n"; 2352*0b57cec5SDimitry Andric OS << "#define __ARM_NEON_H\n\n"; 2353*0b57cec5SDimitry Andric 2354*0b57cec5SDimitry Andric OS << "#if !defined(__ARM_NEON)\n"; 2355*0b57cec5SDimitry Andric OS << "#error \"NEON support not enabled\"\n"; 2356*0b57cec5SDimitry Andric OS << "#endif\n\n"; 2357*0b57cec5SDimitry Andric 2358*0b57cec5SDimitry Andric OS << "#include <stdint.h>\n\n"; 2359*0b57cec5SDimitry Andric 2360*0b57cec5SDimitry Andric // Emit NEON-specific scalar typedefs. 2361*0b57cec5SDimitry Andric OS << "typedef float float32_t;\n"; 2362*0b57cec5SDimitry Andric OS << "typedef __fp16 float16_t;\n"; 2363*0b57cec5SDimitry Andric 2364*0b57cec5SDimitry Andric OS << "#ifdef __aarch64__\n"; 2365*0b57cec5SDimitry Andric OS << "typedef double float64_t;\n"; 2366*0b57cec5SDimitry Andric OS << "#endif\n\n"; 2367*0b57cec5SDimitry Andric 2368*0b57cec5SDimitry Andric // For now, signedness of polynomial types depends on target 2369*0b57cec5SDimitry Andric OS << "#ifdef __aarch64__\n"; 2370*0b57cec5SDimitry Andric OS << "typedef uint8_t poly8_t;\n"; 2371*0b57cec5SDimitry Andric OS << "typedef uint16_t poly16_t;\n"; 2372*0b57cec5SDimitry Andric OS << "typedef uint64_t poly64_t;\n"; 2373*0b57cec5SDimitry Andric OS << "typedef __uint128_t poly128_t;\n"; 2374*0b57cec5SDimitry Andric OS << "#else\n"; 2375*0b57cec5SDimitry Andric OS << "typedef int8_t poly8_t;\n"; 2376*0b57cec5SDimitry Andric OS << "typedef int16_t poly16_t;\n"; 2377*0b57cec5SDimitry Andric OS << "#endif\n"; 2378*0b57cec5SDimitry Andric 2379*0b57cec5SDimitry Andric // Emit Neon vector typedefs. 2380*0b57cec5SDimitry Andric std::string TypedefTypes( 2381*0b57cec5SDimitry Andric "cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQdPcQPcPsQPsPlQPl"); 2382*0b57cec5SDimitry Andric std::vector<TypeSpec> TDTypeVec = TypeSpec::fromTypeSpecs(TypedefTypes); 2383*0b57cec5SDimitry Andric 2384*0b57cec5SDimitry Andric // Emit vector typedefs. 2385*0b57cec5SDimitry Andric bool InIfdef = false; 2386*0b57cec5SDimitry Andric for (auto &TS : TDTypeVec) { 2387*0b57cec5SDimitry Andric bool IsA64 = false; 2388*0b57cec5SDimitry Andric Type T(TS, 'd'); 2389*0b57cec5SDimitry Andric if (T.isDouble() || (T.isPoly() && T.isLong())) 2390*0b57cec5SDimitry Andric IsA64 = true; 2391*0b57cec5SDimitry Andric 2392*0b57cec5SDimitry Andric if (InIfdef && !IsA64) { 2393*0b57cec5SDimitry Andric OS << "#endif\n"; 2394*0b57cec5SDimitry Andric InIfdef = false; 2395*0b57cec5SDimitry Andric } 2396*0b57cec5SDimitry Andric if (!InIfdef && IsA64) { 2397*0b57cec5SDimitry Andric OS << "#ifdef __aarch64__\n"; 2398*0b57cec5SDimitry Andric InIfdef = true; 2399*0b57cec5SDimitry Andric } 2400*0b57cec5SDimitry Andric 2401*0b57cec5SDimitry Andric if (T.isPoly()) 2402*0b57cec5SDimitry Andric OS << "typedef __attribute__((neon_polyvector_type("; 2403*0b57cec5SDimitry Andric else 2404*0b57cec5SDimitry Andric OS << "typedef __attribute__((neon_vector_type("; 2405*0b57cec5SDimitry Andric 2406*0b57cec5SDimitry Andric Type T2 = T; 2407*0b57cec5SDimitry Andric T2.makeScalar(); 2408*0b57cec5SDimitry Andric OS << T.getNumElements() << "))) "; 2409*0b57cec5SDimitry Andric OS << T2.str(); 2410*0b57cec5SDimitry Andric OS << " " << T.str() << ";\n"; 2411*0b57cec5SDimitry Andric } 2412*0b57cec5SDimitry Andric if (InIfdef) 2413*0b57cec5SDimitry Andric OS << "#endif\n"; 2414*0b57cec5SDimitry Andric OS << "\n"; 2415*0b57cec5SDimitry Andric 2416*0b57cec5SDimitry Andric // Emit struct typedefs. 2417*0b57cec5SDimitry Andric InIfdef = false; 2418*0b57cec5SDimitry Andric for (unsigned NumMembers = 2; NumMembers <= 4; ++NumMembers) { 2419*0b57cec5SDimitry Andric for (auto &TS : TDTypeVec) { 2420*0b57cec5SDimitry Andric bool IsA64 = false; 2421*0b57cec5SDimitry Andric Type T(TS, 'd'); 2422*0b57cec5SDimitry Andric if (T.isDouble() || (T.isPoly() && T.isLong())) 2423*0b57cec5SDimitry Andric IsA64 = true; 2424*0b57cec5SDimitry Andric 2425*0b57cec5SDimitry Andric if (InIfdef && !IsA64) { 2426*0b57cec5SDimitry Andric OS << "#endif\n"; 2427*0b57cec5SDimitry Andric InIfdef = false; 2428*0b57cec5SDimitry Andric } 2429*0b57cec5SDimitry Andric if (!InIfdef && IsA64) { 2430*0b57cec5SDimitry Andric OS << "#ifdef __aarch64__\n"; 2431*0b57cec5SDimitry Andric InIfdef = true; 2432*0b57cec5SDimitry Andric } 2433*0b57cec5SDimitry Andric 2434*0b57cec5SDimitry Andric char M = '2' + (NumMembers - 2); 2435*0b57cec5SDimitry Andric Type VT(TS, M); 2436*0b57cec5SDimitry Andric OS << "typedef struct " << VT.str() << " {\n"; 2437*0b57cec5SDimitry Andric OS << " " << T.str() << " val"; 2438*0b57cec5SDimitry Andric OS << "[" << NumMembers << "]"; 2439*0b57cec5SDimitry Andric OS << ";\n} "; 2440*0b57cec5SDimitry Andric OS << VT.str() << ";\n"; 2441*0b57cec5SDimitry Andric OS << "\n"; 2442*0b57cec5SDimitry Andric } 2443*0b57cec5SDimitry Andric } 2444*0b57cec5SDimitry Andric if (InIfdef) 2445*0b57cec5SDimitry Andric OS << "#endif\n"; 2446*0b57cec5SDimitry Andric OS << "\n"; 2447*0b57cec5SDimitry Andric 2448*0b57cec5SDimitry Andric OS << "#define __ai static __inline__ __attribute__((__always_inline__, " 2449*0b57cec5SDimitry Andric "__nodebug__))\n\n"; 2450*0b57cec5SDimitry Andric 2451*0b57cec5SDimitry Andric SmallVector<Intrinsic *, 128> Defs; 2452*0b57cec5SDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 2453*0b57cec5SDimitry Andric for (auto *R : RV) 2454*0b57cec5SDimitry Andric createIntrinsic(R, Defs); 2455*0b57cec5SDimitry Andric 2456*0b57cec5SDimitry Andric for (auto *I : Defs) 2457*0b57cec5SDimitry Andric I->indexBody(); 2458*0b57cec5SDimitry Andric 2459*0b57cec5SDimitry Andric llvm::stable_sort(Defs, llvm::less_ptr<Intrinsic>()); 2460*0b57cec5SDimitry Andric 2461*0b57cec5SDimitry Andric // Only emit a def when its requirements have been met. 2462*0b57cec5SDimitry Andric // FIXME: This loop could be made faster, but it's fast enough for now. 2463*0b57cec5SDimitry Andric bool MadeProgress = true; 2464*0b57cec5SDimitry Andric std::string InGuard; 2465*0b57cec5SDimitry Andric while (!Defs.empty() && MadeProgress) { 2466*0b57cec5SDimitry Andric MadeProgress = false; 2467*0b57cec5SDimitry Andric 2468*0b57cec5SDimitry Andric for (SmallVector<Intrinsic *, 128>::iterator I = Defs.begin(); 2469*0b57cec5SDimitry Andric I != Defs.end(); /*No step*/) { 2470*0b57cec5SDimitry Andric bool DependenciesSatisfied = true; 2471*0b57cec5SDimitry Andric for (auto *II : (*I)->getDependencies()) { 2472*0b57cec5SDimitry Andric if (llvm::is_contained(Defs, II)) 2473*0b57cec5SDimitry Andric DependenciesSatisfied = false; 2474*0b57cec5SDimitry Andric } 2475*0b57cec5SDimitry Andric if (!DependenciesSatisfied) { 2476*0b57cec5SDimitry Andric // Try the next one. 2477*0b57cec5SDimitry Andric ++I; 2478*0b57cec5SDimitry Andric continue; 2479*0b57cec5SDimitry Andric } 2480*0b57cec5SDimitry Andric 2481*0b57cec5SDimitry Andric // Emit #endif/#if pair if needed. 2482*0b57cec5SDimitry Andric if ((*I)->getGuard() != InGuard) { 2483*0b57cec5SDimitry Andric if (!InGuard.empty()) 2484*0b57cec5SDimitry Andric OS << "#endif\n"; 2485*0b57cec5SDimitry Andric InGuard = (*I)->getGuard(); 2486*0b57cec5SDimitry Andric if (!InGuard.empty()) 2487*0b57cec5SDimitry Andric OS << "#if " << InGuard << "\n"; 2488*0b57cec5SDimitry Andric } 2489*0b57cec5SDimitry Andric 2490*0b57cec5SDimitry Andric // Actually generate the intrinsic code. 2491*0b57cec5SDimitry Andric OS << (*I)->generate(); 2492*0b57cec5SDimitry Andric 2493*0b57cec5SDimitry Andric MadeProgress = true; 2494*0b57cec5SDimitry Andric I = Defs.erase(I); 2495*0b57cec5SDimitry Andric } 2496*0b57cec5SDimitry Andric } 2497*0b57cec5SDimitry Andric assert(Defs.empty() && "Some requirements were not satisfied!"); 2498*0b57cec5SDimitry Andric if (!InGuard.empty()) 2499*0b57cec5SDimitry Andric OS << "#endif\n"; 2500*0b57cec5SDimitry Andric 2501*0b57cec5SDimitry Andric OS << "\n"; 2502*0b57cec5SDimitry Andric OS << "#undef __ai\n\n"; 2503*0b57cec5SDimitry Andric OS << "#endif /* __ARM_NEON_H */\n"; 2504*0b57cec5SDimitry Andric } 2505*0b57cec5SDimitry Andric 2506*0b57cec5SDimitry Andric /// run - Read the records in arm_fp16.td and output arm_fp16.h. arm_fp16.h 2507*0b57cec5SDimitry Andric /// is comprised of type definitions and function declarations. 2508*0b57cec5SDimitry Andric void NeonEmitter::runFP16(raw_ostream &OS) { 2509*0b57cec5SDimitry Andric OS << "/*===---- arm_fp16.h - ARM FP16 intrinsics " 2510*0b57cec5SDimitry Andric "------------------------------" 2511*0b57cec5SDimitry Andric "---===\n" 2512*0b57cec5SDimitry Andric " *\n" 2513*0b57cec5SDimitry Andric " * Permission is hereby granted, free of charge, to any person " 2514*0b57cec5SDimitry Andric "obtaining a copy\n" 2515*0b57cec5SDimitry Andric " * of this software and associated documentation files (the " 2516*0b57cec5SDimitry Andric "\"Software\"), to deal\n" 2517*0b57cec5SDimitry Andric " * in the Software without restriction, including without limitation " 2518*0b57cec5SDimitry Andric "the rights\n" 2519*0b57cec5SDimitry Andric " * to use, copy, modify, merge, publish, distribute, sublicense, " 2520*0b57cec5SDimitry Andric "and/or sell\n" 2521*0b57cec5SDimitry Andric " * copies of the Software, and to permit persons to whom the Software " 2522*0b57cec5SDimitry Andric "is\n" 2523*0b57cec5SDimitry Andric " * furnished to do so, subject to the following conditions:\n" 2524*0b57cec5SDimitry Andric " *\n" 2525*0b57cec5SDimitry Andric " * The above copyright notice and this permission notice shall be " 2526*0b57cec5SDimitry Andric "included in\n" 2527*0b57cec5SDimitry Andric " * all copies or substantial portions of the Software.\n" 2528*0b57cec5SDimitry Andric " *\n" 2529*0b57cec5SDimitry Andric " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, " 2530*0b57cec5SDimitry Andric "EXPRESS OR\n" 2531*0b57cec5SDimitry Andric " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " 2532*0b57cec5SDimitry Andric "MERCHANTABILITY,\n" 2533*0b57cec5SDimitry Andric " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT " 2534*0b57cec5SDimitry Andric "SHALL THE\n" 2535*0b57cec5SDimitry Andric " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR " 2536*0b57cec5SDimitry Andric "OTHER\n" 2537*0b57cec5SDimitry Andric " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, " 2538*0b57cec5SDimitry Andric "ARISING FROM,\n" 2539*0b57cec5SDimitry Andric " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER " 2540*0b57cec5SDimitry Andric "DEALINGS IN\n" 2541*0b57cec5SDimitry Andric " * THE SOFTWARE.\n" 2542*0b57cec5SDimitry Andric " *\n" 2543*0b57cec5SDimitry Andric " *===-----------------------------------------------------------------" 2544*0b57cec5SDimitry Andric "---" 2545*0b57cec5SDimitry Andric "---===\n" 2546*0b57cec5SDimitry Andric " */\n\n"; 2547*0b57cec5SDimitry Andric 2548*0b57cec5SDimitry Andric OS << "#ifndef __ARM_FP16_H\n"; 2549*0b57cec5SDimitry Andric OS << "#define __ARM_FP16_H\n\n"; 2550*0b57cec5SDimitry Andric 2551*0b57cec5SDimitry Andric OS << "#include <stdint.h>\n\n"; 2552*0b57cec5SDimitry Andric 2553*0b57cec5SDimitry Andric OS << "typedef __fp16 float16_t;\n"; 2554*0b57cec5SDimitry Andric 2555*0b57cec5SDimitry Andric OS << "#define __ai static __inline__ __attribute__((__always_inline__, " 2556*0b57cec5SDimitry Andric "__nodebug__))\n\n"; 2557*0b57cec5SDimitry Andric 2558*0b57cec5SDimitry Andric SmallVector<Intrinsic *, 128> Defs; 2559*0b57cec5SDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 2560*0b57cec5SDimitry Andric for (auto *R : RV) 2561*0b57cec5SDimitry Andric createIntrinsic(R, Defs); 2562*0b57cec5SDimitry Andric 2563*0b57cec5SDimitry Andric for (auto *I : Defs) 2564*0b57cec5SDimitry Andric I->indexBody(); 2565*0b57cec5SDimitry Andric 2566*0b57cec5SDimitry Andric llvm::stable_sort(Defs, llvm::less_ptr<Intrinsic>()); 2567*0b57cec5SDimitry Andric 2568*0b57cec5SDimitry Andric // Only emit a def when its requirements have been met. 2569*0b57cec5SDimitry Andric // FIXME: This loop could be made faster, but it's fast enough for now. 2570*0b57cec5SDimitry Andric bool MadeProgress = true; 2571*0b57cec5SDimitry Andric std::string InGuard; 2572*0b57cec5SDimitry Andric while (!Defs.empty() && MadeProgress) { 2573*0b57cec5SDimitry Andric MadeProgress = false; 2574*0b57cec5SDimitry Andric 2575*0b57cec5SDimitry Andric for (SmallVector<Intrinsic *, 128>::iterator I = Defs.begin(); 2576*0b57cec5SDimitry Andric I != Defs.end(); /*No step*/) { 2577*0b57cec5SDimitry Andric bool DependenciesSatisfied = true; 2578*0b57cec5SDimitry Andric for (auto *II : (*I)->getDependencies()) { 2579*0b57cec5SDimitry Andric if (llvm::is_contained(Defs, II)) 2580*0b57cec5SDimitry Andric DependenciesSatisfied = false; 2581*0b57cec5SDimitry Andric } 2582*0b57cec5SDimitry Andric if (!DependenciesSatisfied) { 2583*0b57cec5SDimitry Andric // Try the next one. 2584*0b57cec5SDimitry Andric ++I; 2585*0b57cec5SDimitry Andric continue; 2586*0b57cec5SDimitry Andric } 2587*0b57cec5SDimitry Andric 2588*0b57cec5SDimitry Andric // Emit #endif/#if pair if needed. 2589*0b57cec5SDimitry Andric if ((*I)->getGuard() != InGuard) { 2590*0b57cec5SDimitry Andric if (!InGuard.empty()) 2591*0b57cec5SDimitry Andric OS << "#endif\n"; 2592*0b57cec5SDimitry Andric InGuard = (*I)->getGuard(); 2593*0b57cec5SDimitry Andric if (!InGuard.empty()) 2594*0b57cec5SDimitry Andric OS << "#if " << InGuard << "\n"; 2595*0b57cec5SDimitry Andric } 2596*0b57cec5SDimitry Andric 2597*0b57cec5SDimitry Andric // Actually generate the intrinsic code. 2598*0b57cec5SDimitry Andric OS << (*I)->generate(); 2599*0b57cec5SDimitry Andric 2600*0b57cec5SDimitry Andric MadeProgress = true; 2601*0b57cec5SDimitry Andric I = Defs.erase(I); 2602*0b57cec5SDimitry Andric } 2603*0b57cec5SDimitry Andric } 2604*0b57cec5SDimitry Andric assert(Defs.empty() && "Some requirements were not satisfied!"); 2605*0b57cec5SDimitry Andric if (!InGuard.empty()) 2606*0b57cec5SDimitry Andric OS << "#endif\n"; 2607*0b57cec5SDimitry Andric 2608*0b57cec5SDimitry Andric OS << "\n"; 2609*0b57cec5SDimitry Andric OS << "#undef __ai\n\n"; 2610*0b57cec5SDimitry Andric OS << "#endif /* __ARM_FP16_H */\n"; 2611*0b57cec5SDimitry Andric } 2612*0b57cec5SDimitry Andric 2613*0b57cec5SDimitry Andric namespace clang { 2614*0b57cec5SDimitry Andric 2615*0b57cec5SDimitry Andric void EmitNeon(RecordKeeper &Records, raw_ostream &OS) { 2616*0b57cec5SDimitry Andric NeonEmitter(Records).run(OS); 2617*0b57cec5SDimitry Andric } 2618*0b57cec5SDimitry Andric 2619*0b57cec5SDimitry Andric void EmitFP16(RecordKeeper &Records, raw_ostream &OS) { 2620*0b57cec5SDimitry Andric NeonEmitter(Records).runFP16(OS); 2621*0b57cec5SDimitry Andric } 2622*0b57cec5SDimitry Andric 2623*0b57cec5SDimitry Andric void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) { 2624*0b57cec5SDimitry Andric NeonEmitter(Records).runHeader(OS); 2625*0b57cec5SDimitry Andric } 2626*0b57cec5SDimitry Andric 2627*0b57cec5SDimitry Andric void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) { 2628*0b57cec5SDimitry Andric llvm_unreachable("Neon test generation no longer implemented!"); 2629*0b57cec5SDimitry Andric } 2630*0b57cec5SDimitry Andric 2631*0b57cec5SDimitry Andric } // end namespace clang 2632