| //===- subzero/src/IceIntrinsics.cpp - Functions related to intrinsics ----===// | 
 | // | 
 | //                        The Subzero Code Generator | 
 | // | 
 | // This file is distributed under the University of Illinois Open Source | 
 | // License. See LICENSE.TXT for details. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | /// | 
 | /// \file | 
 | /// \brief Implements the Intrinsics utilities for matching and then dispatching | 
 | /// by name. | 
 | /// | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "IceIntrinsics.h" | 
 |  | 
 | #include "IceCfg.h" | 
 | #include "IceCfgNode.h" | 
 | #include "IceInst.h" | 
 | #include "IceLiveness.h" | 
 | #include "IceOperand.h" | 
 | #include "IceStringPool.h" | 
 |  | 
 | #include <utility> | 
 |  | 
 | namespace Ice { | 
 |  | 
 | static_assert(sizeof(Intrinsics::IntrinsicInfo) == 4, | 
 |               "Unexpected sizeof(IntrinsicInfo)"); | 
 |  | 
 | namespace { | 
 |  | 
 | #define INTRIN(ID, SE, RT, MW)                                                 \ | 
 |   { Intrinsics::ID, Intrinsics::SE, Intrinsics::RT, Intrinsics::MW } | 
 |  | 
 | // Build list of intrinsics with their attributes and expected prototypes. List | 
 | // is sorted alphabetically. | 
 | const struct IceIntrinsicsEntry_ { | 
 |   Intrinsics::FullIntrinsicInfo Info; | 
 |   const char *IntrinsicName; | 
 | } IceIntrinsicsTable[] = { | 
 |  | 
 | #define AtomicCmpxchgInit(Overload, NameSuffix)                                  \ | 
 |   {                                                                              \ | 
 |     {                                                                            \ | 
 |       INTRIN(AtomicCmpxchg, SideEffects_T, ReturnsTwice_F, MemoryWrite_T),       \ | 
 |           {Overload, IceType_i32, Overload, Overload, IceType_i32, IceType_i32}, \ | 
 |           6                                                                      \ | 
 |     }                                                                            \ | 
 |     , "llvm.nacl.atomic.cmpxchg." NameSuffix                                     \ | 
 |   } | 
 |     AtomicCmpxchgInit(IceType_i8, "i8"), | 
 |     AtomicCmpxchgInit(IceType_i16, "i16"), | 
 |     AtomicCmpxchgInit(IceType_i32, "i32"), | 
 |     AtomicCmpxchgInit(IceType_i64, "i64"), | 
 | #undef AtomicCmpxchgInit | 
 |  | 
 |     {{INTRIN(AtomicFence, SideEffects_T, ReturnsTwice_F, MemoryWrite_T), | 
 |       {IceType_void, IceType_i32}, | 
 |       2}, | 
 |      "llvm.nacl.atomic.fence"}, | 
 |     {{INTRIN(AtomicFenceAll, SideEffects_T, ReturnsTwice_F, MemoryWrite_T), | 
 |       {IceType_void}, | 
 |       1}, | 
 |      "llvm.nacl.atomic.fence.all"}, | 
 |     {{INTRIN(AtomicIsLockFree, SideEffects_F, ReturnsTwice_F, MemoryWrite_F), | 
 |       {IceType_i1, IceType_i32, IceType_i32}, | 
 |       3}, | 
 |      "llvm.nacl.atomic.is.lock.free"}, | 
 |  | 
 | #define AtomicLoadInit(Overload, NameSuffix)                                   \ | 
 |   {                                                                            \ | 
 |     {                                                                          \ | 
 |       INTRIN(AtomicLoad, SideEffects_T, ReturnsTwice_F, MemoryWrite_T),        \ | 
 |           {Overload, IceType_i32, IceType_i32}, 3                              \ | 
 |     }                                                                          \ | 
 |     , "llvm.nacl.atomic.load." NameSuffix                                      \ | 
 |   } | 
 |     AtomicLoadInit(IceType_i8, "i8"), | 
 |     AtomicLoadInit(IceType_i16, "i16"), | 
 |     AtomicLoadInit(IceType_i32, "i32"), | 
 |     AtomicLoadInit(IceType_i64, "i64"), | 
 | #undef AtomicLoadInit | 
 |  | 
 | #define AtomicRMWInit(Overload, NameSuffix)                                    \ | 
 |   {                                                                            \ | 
 |     {                                                                          \ | 
 |       INTRIN(AtomicRMW, SideEffects_T, ReturnsTwice_F, MemoryWrite_T)          \ | 
 |       , {Overload, IceType_i32, IceType_i32, Overload, IceType_i32}, 5         \ | 
 |     }                                                                          \ | 
 |     , "llvm.nacl.atomic.rmw." NameSuffix                                       \ | 
 |   } | 
 |     AtomicRMWInit(IceType_i8, "i8"), | 
 |     AtomicRMWInit(IceType_i16, "i16"), | 
 |     AtomicRMWInit(IceType_i32, "i32"), | 
 |     AtomicRMWInit(IceType_i64, "i64"), | 
 | #undef AtomicRMWInit | 
 |  | 
 | #define AtomicStoreInit(Overload, NameSuffix)                                  \ | 
 |   {                                                                            \ | 
 |     {                                                                          \ | 
 |       INTRIN(AtomicStore, SideEffects_T, ReturnsTwice_F, MemoryWrite_T)        \ | 
 |       , {IceType_void, Overload, IceType_i32, IceType_i32}, 4                  \ | 
 |     }                                                                          \ | 
 |     , "llvm.nacl.atomic.store." NameSuffix                                     \ | 
 |   } | 
 |     AtomicStoreInit(IceType_i8, "i8"), | 
 |     AtomicStoreInit(IceType_i16, "i16"), | 
 |     AtomicStoreInit(IceType_i32, "i32"), | 
 |     AtomicStoreInit(IceType_i64, "i64"), | 
 | #undef AtomicStoreInit | 
 |  | 
 | #define BswapInit(Overload, NameSuffix)                                        \ | 
 |   {                                                                            \ | 
 |     {                                                                          \ | 
 |       INTRIN(Bswap, SideEffects_F, ReturnsTwice_F, MemoryWrite_F)              \ | 
 |       , {Overload, Overload}, 2                                                \ | 
 |     }                                                                          \ | 
 |     , "llvm.bswap." NameSuffix                                                 \ | 
 |   } | 
 |     BswapInit(IceType_i16, "i16"), | 
 |     BswapInit(IceType_i32, "i32"), | 
 |     BswapInit(IceType_i64, "i64"), | 
 | #undef BswapInit | 
 |  | 
 | #define CtlzInit(Overload, NameSuffix)                                         \ | 
 |   {                                                                            \ | 
 |     {                                                                          \ | 
 |       INTRIN(Ctlz, SideEffects_F, ReturnsTwice_F, MemoryWrite_F)               \ | 
 |       , {Overload, Overload, IceType_i1}, 3                                    \ | 
 |     }                                                                          \ | 
 |     , "llvm.ctlz." NameSuffix                                                  \ | 
 |   } | 
 |     CtlzInit(IceType_i32, "i32"), | 
 |     CtlzInit(IceType_i64, "i64"), | 
 | #undef CtlzInit | 
 |  | 
 | #define CtpopInit(Overload, NameSuffix)                                        \ | 
 |   {                                                                            \ | 
 |     {                                                                          \ | 
 |       INTRIN(Ctpop, SideEffects_F, ReturnsTwice_F, MemoryWrite_F)              \ | 
 |       , {Overload, Overload}, 2                                                \ | 
 |     }                                                                          \ | 
 |     , "llvm.ctpop." NameSuffix                                                 \ | 
 |   } | 
 |     CtpopInit(IceType_i32, "i32"), | 
 |     CtpopInit(IceType_i64, "i64"), | 
 | #undef CtpopInit | 
 |  | 
 | #define CttzInit(Overload, NameSuffix)                                         \ | 
 |   {                                                                            \ | 
 |     {                                                                          \ | 
 |       INTRIN(Cttz, SideEffects_F, ReturnsTwice_F, MemoryWrite_F)               \ | 
 |       , {Overload, Overload, IceType_i1}, 3                                    \ | 
 |     }                                                                          \ | 
 |     , "llvm.cttz." NameSuffix                                                  \ | 
 |   } | 
 |     CttzInit(IceType_i32, "i32"), | 
 |     CttzInit(IceType_i64, "i64"), | 
 | #undef CttzInit | 
 |  | 
 | #define FabsInit(Overload, NameSuffix)                                         \ | 
 |   {                                                                            \ | 
 |     {                                                                          \ | 
 |       INTRIN(Fabs, SideEffects_F, ReturnsTwice_F, MemoryWrite_F),              \ | 
 |           {Overload, Overload}, 2                                              \ | 
 |     }                                                                          \ | 
 |     , "llvm.fabs." NameSuffix                                                  \ | 
 |   } | 
 |     FabsInit(IceType_f32, "f32"), | 
 |     FabsInit(IceType_f64, "f64"), | 
 |     FabsInit(IceType_v4f32, "v4f32"), | 
 | #undef FabsInit | 
 |  | 
 |     {{INTRIN(Longjmp, SideEffects_T, ReturnsTwice_F, MemoryWrite_F), | 
 |       {IceType_void, IceType_i32, IceType_i32}, | 
 |       3}, | 
 |      "llvm.nacl.longjmp"}, | 
 |     {{INTRIN(Memcpy, SideEffects_T, ReturnsTwice_F, MemoryWrite_T), | 
 |       {IceType_void, IceType_i32, IceType_i32, IceType_i32, IceType_i32, | 
 |        IceType_i1}, | 
 |       6}, | 
 |      "llvm.memcpy.p0i8.p0i8.i32"}, | 
 |     {{INTRIN(Memmove, SideEffects_T, ReturnsTwice_F, MemoryWrite_T), | 
 |       {IceType_void, IceType_i32, IceType_i32, IceType_i32, IceType_i32, | 
 |        IceType_i1}, | 
 |       6}, | 
 |      "llvm.memmove.p0i8.p0i8.i32"}, | 
 |     {{INTRIN(Memset, SideEffects_T, ReturnsTwice_F, MemoryWrite_T), | 
 |       {IceType_void, IceType_i32, IceType_i8, IceType_i32, IceType_i32, | 
 |        IceType_i1}, | 
 |       6}, | 
 |      "llvm.memset.p0i8.i32"}, | 
 |     {{INTRIN(NaClReadTP, SideEffects_F, ReturnsTwice_F, MemoryWrite_F), | 
 |       {IceType_i32}, | 
 |       1}, | 
 |      "llvm.nacl.read.tp"}, | 
 |     {{INTRIN(Setjmp, SideEffects_T, ReturnsTwice_T, MemoryWrite_T), | 
 |       {IceType_i32, IceType_i32}, | 
 |       2}, | 
 |      "llvm.nacl.setjmp"}, | 
 |  | 
 | #define SqrtInit(Overload, NameSuffix)                                         \ | 
 |   {                                                                            \ | 
 |     {                                                                          \ | 
 |       INTRIN(Sqrt, SideEffects_F, ReturnsTwice_F, MemoryWrite_F),              \ | 
 |           {Overload, Overload}, 2                                              \ | 
 |     }                                                                          \ | 
 |     , "llvm.sqrt." NameSuffix                                                  \ | 
 |   } | 
 |     SqrtInit(IceType_f32, "f32"), | 
 |     SqrtInit(IceType_f64, "f64"), | 
 | #undef SqrtInit | 
 |  | 
 |     {{INTRIN(Stacksave, SideEffects_T, ReturnsTwice_F, MemoryWrite_F), | 
 |       {IceType_i32}, | 
 |       1}, | 
 |      "llvm.stacksave"}, | 
 |     {{INTRIN(Stackrestore, SideEffects_T, ReturnsTwice_F, MemoryWrite_F), | 
 |       {IceType_void, IceType_i32}, | 
 |       2}, | 
 |      "llvm.stackrestore"}, | 
 |     {{INTRIN(Trap, SideEffects_T, ReturnsTwice_F, MemoryWrite_F), | 
 |       {IceType_void}, | 
 |       1}, | 
 |      "llvm.trap"}}; | 
 | const size_t IceIntrinsicsTableSize = llvm::array_lengthof(IceIntrinsicsTable); | 
 |  | 
 | #undef INTRIN | 
 |  | 
 | } // end of anonymous namespace | 
 |  | 
 | Intrinsics::Intrinsics(GlobalContext *Ctx) { | 
 |   for (size_t I = 0; I < IceIntrinsicsTableSize; ++I) { | 
 |     const struct IceIntrinsicsEntry_ &Entry = IceIntrinsicsTable[I]; | 
 |     assert(Entry.Info.NumTypes <= kMaxIntrinsicParameters); | 
 |     Map.insert( | 
 |         std::make_pair(Ctx->getGlobalString(Entry.IntrinsicName), Entry.Info)); | 
 |   } | 
 | } | 
 |  | 
 | const Intrinsics::FullIntrinsicInfo *Intrinsics::find(GlobalString Name, | 
 |                                                       bool &Error) const { | 
 |   static constexpr char LLVMPrefix[] = "llvm."; | 
 |   constexpr size_t LLVMPrefixLen = llvm::array_lengthof(LLVMPrefix) - 1; | 
 |   Error = false; | 
 |   if (Name.toString().substr(0, LLVMPrefixLen) != LLVMPrefix) | 
 |     return nullptr; | 
 |   auto Iter = Map.find(Name); | 
 |   if (Iter == Map.end()) { | 
 |     Error = true; | 
 |     return nullptr; | 
 |   } | 
 |   return &Iter->second; | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | // Returns whether PNaCl allows the given memory ordering in general. | 
 | bool isMemoryOrderValidPNaCl(uint64_t Order) { | 
 |   switch (Order) { | 
 |   case Intrinsics::MemoryOrderAcquire: | 
 |   case Intrinsics::MemoryOrderRelease: | 
 |   case Intrinsics::MemoryOrderAcquireRelease: | 
 |   case Intrinsics::MemoryOrderSequentiallyConsistent: | 
 |     return true; | 
 |   default: | 
 |     return false; | 
 |   } | 
 | } | 
 |  | 
 | } // end of anonymous namespace | 
 |  | 
 | bool Intrinsics::isMemoryOrderValid(IntrinsicID ID, uint64_t Order, | 
 |                                     uint64_t OrderOther) { | 
 |   // Reject orderings not allowed in PNaCl. | 
 |   if (!isMemoryOrderValidPNaCl(Order)) | 
 |     return false; | 
 |   if (ID == AtomicCmpxchg && !isMemoryOrderValidPNaCl(OrderOther)) | 
 |     return false; | 
 |   // Reject orderings not allowed by C++11. | 
 |   switch (ID) { | 
 |   default: | 
 |     llvm_unreachable("isMemoryOrderValid: Unknown IntrinsicID"); | 
 |     return false; | 
 |   case AtomicFence: | 
 |   case AtomicFenceAll: | 
 |   case AtomicRMW: | 
 |     return true; | 
 |   case AtomicCmpxchg: | 
 |     // Reject orderings that are disallowed by C++11 as invalid combinations | 
 |     // for cmpxchg. | 
 |     switch (OrderOther) { | 
 |     case MemoryOrderRelaxed: | 
 |     case MemoryOrderConsume: | 
 |     case MemoryOrderAcquire: | 
 |     case MemoryOrderSequentiallyConsistent: | 
 |       if (OrderOther > Order) | 
 |         return false; | 
 |       if (Order == MemoryOrderRelease && OrderOther != MemoryOrderRelaxed) | 
 |         return false; | 
 |       return true; | 
 |     default: | 
 |       return false; | 
 |     } | 
 |   case AtomicLoad: | 
 |     switch (Order) { | 
 |     case MemoryOrderRelease: | 
 |     case MemoryOrderAcquireRelease: | 
 |       return false; | 
 |     default: | 
 |       return true; | 
 |     } | 
 |   case AtomicStore: | 
 |     switch (Order) { | 
 |     case MemoryOrderConsume: | 
 |     case MemoryOrderAcquire: | 
 |     case MemoryOrderAcquireRelease: | 
 |       return false; | 
 |     default: | 
 |       return true; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | Intrinsics::ValidateCallValue | 
 | Intrinsics::FullIntrinsicInfo::validateCall(const InstCall *Call, | 
 |                                             SizeT &ArgIndex) const { | 
 |   assert(NumTypes >= 1); | 
 |   Variable *Result = Call->getDest(); | 
 |   if (Result == nullptr) { | 
 |     if (getReturnType() != IceType_void) | 
 |       return Intrinsics::BadReturnType; | 
 |   } else if (getReturnType() != Result->getType()) { | 
 |     return Intrinsics::BadReturnType; | 
 |   } | 
 |   if (Call->getNumArgs() != getNumArgs()) { | 
 |     return Intrinsics::WrongNumOfArgs; | 
 |   } | 
 |   for (size_t i = 1; i < NumTypes; ++i) { | 
 |     if (Call->getArg(i - 1)->getType() != Signature[i]) { | 
 |       ArgIndex = i - 1; | 
 |       return Intrinsics::WrongCallArgType; | 
 |     } | 
 |   } | 
 |   return Intrinsics::IsValidCall; | 
 | } | 
 |  | 
 | Type Intrinsics::FullIntrinsicInfo::getArgType(SizeT Index) const { | 
 |   assert(NumTypes > 1); | 
 |   assert(Index + 1 < NumTypes); | 
 |   return Signature[Index + 1]; | 
 | } | 
 |  | 
 | } // end of namespace Ice |