blob: 307745ea62d65dbb2207dd6f536dd6656fe12a37 [file] [log] [blame]
Jan Voung3bd9f1a2014-06-18 10:50:57 -07001//===- subzero/src/IceIntrinsics.cpp - Functions related to intrinsics ----===//
2//
3// The Subzero Code Generator
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the Intrinsics utilities for matching and
11// then dispatching by name.
12//
13//===----------------------------------------------------------------------===//
14
John Porto67f8de92015-06-25 10:14:17 -070015#include "IceIntrinsics.h"
16
Jan Voung3bd9f1a2014-06-18 10:50:57 -070017#include "IceCfg.h"
18#include "IceCfgNode.h"
Karl Schimpf8df26f32014-09-19 09:33:26 -070019#include "IceInst.h"
Jan Voung3bd9f1a2014-06-18 10:50:57 -070020#include "IceLiveness.h"
21#include "IceOperand.h"
22
23#include <utility>
24
25namespace Ice {
26
Jim Stichnothfac55172014-10-01 13:06:21 -070027static_assert(sizeof(Intrinsics::IntrinsicInfo) == 4,
28 "Unexpected sizeof(IntrinsicInfo)");
Jan Voung3bd9f1a2014-06-18 10:50:57 -070029
Jim Stichnothfac55172014-10-01 13:06:21 -070030namespace {
Jan Voung44d53e12014-09-11 19:18:03 -070031
Jim Stichnothdd842db2015-01-27 12:53:53 -080032#define INTRIN(ID, SE, RT) \
33 { Intrinsics::ID, Intrinsics::SE, Intrinsics::RT }
Jan Voung44d53e12014-09-11 19:18:03 -070034
35// Build list of intrinsics with their attributes and expected prototypes.
36// List is sorted alphabetically.
Jan Voung3bd9f1a2014-06-18 10:50:57 -070037const struct IceIntrinsicsEntry_ {
38 Intrinsics::FullIntrinsicInfo Info;
39 const char *IntrinsicName;
40} IceIntrinsicsTable[] = {
Jan Voung44d53e12014-09-11 19:18:03 -070041
Jan Voung3bd9f1a2014-06-18 10:50:57 -070042#define AtomicCmpxchgInit(Overload, NameSuffix) \
43 { \
44 { \
Jim Stichnothdd842db2015-01-27 12:53:53 -080045 INTRIN(AtomicCmpxchg, SideEffects_T, ReturnsTwice_F), {Overload, \
46 IceType_i32, \
47 Overload, \
48 Overload, \
49 IceType_i32, \
50 IceType_i32}, \
51 6 \
52 } \
53 , "nacl.atomic.cmpxchg." NameSuffix \
Jan Voung3bd9f1a2014-06-18 10:50:57 -070054 }
Jim Stichnothd9dc82e2015-03-03 17:06:33 -080055 AtomicCmpxchgInit(IceType_i8, "i8"),
56 AtomicCmpxchgInit(IceType_i16, "i16"),
57 AtomicCmpxchgInit(IceType_i32, "i32"),
58 AtomicCmpxchgInit(IceType_i64, "i64"),
Jan Voung3bd9f1a2014-06-18 10:50:57 -070059#undef AtomicCmpxchgInit
Jan Voung44d53e12014-09-11 19:18:03 -070060
Jim Stichnothd9dc82e2015-03-03 17:06:33 -080061 {{INTRIN(AtomicFence, SideEffects_T, ReturnsTwice_F),
62 {IceType_void, IceType_i32},
63 2},
64 "nacl.atomic.fence"},
65 {{INTRIN(AtomicFenceAll, SideEffects_T, ReturnsTwice_F), {IceType_void}, 1},
66 "nacl.atomic.fence.all"},
67 {{INTRIN(AtomicIsLockFree, SideEffects_F, ReturnsTwice_F),
68 {IceType_i1, IceType_i32, IceType_i32},
69 3},
70 "nacl.atomic.is.lock.free"},
Jan Voung3bd9f1a2014-06-18 10:50:57 -070071
72#define AtomicLoadInit(Overload, NameSuffix) \
73 { \
74 { \
Jan Voung44d53e12014-09-11 19:18:03 -070075 INTRIN(AtomicLoad, SideEffects_T, ReturnsTwice_F), \
Jim Stichnothdd842db2015-01-27 12:53:53 -080076 {Overload, IceType_i32, IceType_i32}, 3 \
77 } \
78 , "nacl.atomic.load." NameSuffix \
Jan Voung3bd9f1a2014-06-18 10:50:57 -070079 }
Jim Stichnothd9dc82e2015-03-03 17:06:33 -080080 AtomicLoadInit(IceType_i8, "i8"),
81 AtomicLoadInit(IceType_i16, "i16"),
82 AtomicLoadInit(IceType_i32, "i32"),
83 AtomicLoadInit(IceType_i64, "i64"),
Jan Voung3bd9f1a2014-06-18 10:50:57 -070084#undef AtomicLoadInit
85
86#define AtomicRMWInit(Overload, NameSuffix) \
87 { \
88 { \
Jan Voung44d53e12014-09-11 19:18:03 -070089 INTRIN(AtomicRMW, SideEffects_T, ReturnsTwice_F) \
Jim Stichnothdd842db2015-01-27 12:53:53 -080090 , {Overload, IceType_i32, IceType_i32, Overload, IceType_i32}, 5 \
Jan Voung3bd9f1a2014-06-18 10:50:57 -070091 } \
92 , "nacl.atomic.rmw." NameSuffix \
93 }
Jim Stichnothd9dc82e2015-03-03 17:06:33 -080094 AtomicRMWInit(IceType_i8, "i8"),
95 AtomicRMWInit(IceType_i16, "i16"),
96 AtomicRMWInit(IceType_i32, "i32"),
97 AtomicRMWInit(IceType_i64, "i64"),
Jan Voung3bd9f1a2014-06-18 10:50:57 -070098#undef AtomicRMWInit
99
100#define AtomicStoreInit(Overload, NameSuffix) \
101 { \
102 { \
Jan Voung44d53e12014-09-11 19:18:03 -0700103 INTRIN(AtomicStore, SideEffects_T, ReturnsTwice_F) \
Jim Stichnothdd842db2015-01-27 12:53:53 -0800104 , {IceType_void, Overload, IceType_i32, IceType_i32}, 4 \
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700105 } \
106 , "nacl.atomic.store." NameSuffix \
107 }
Jim Stichnothd9dc82e2015-03-03 17:06:33 -0800108 AtomicStoreInit(IceType_i8, "i8"),
109 AtomicStoreInit(IceType_i16, "i16"),
110 AtomicStoreInit(IceType_i32, "i32"),
111 AtomicStoreInit(IceType_i64, "i64"),
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700112#undef AtomicStoreInit
113
114#define BswapInit(Overload, NameSuffix) \
115 { \
116 { \
Jan Voung44d53e12014-09-11 19:18:03 -0700117 INTRIN(Bswap, SideEffects_F, ReturnsTwice_F) \
Jim Stichnothdd842db2015-01-27 12:53:53 -0800118 , {Overload, Overload}, 2 \
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700119 } \
120 , "bswap." NameSuffix \
121 }
Jim Stichnothd9dc82e2015-03-03 17:06:33 -0800122 BswapInit(IceType_i16, "i16"),
123 BswapInit(IceType_i32, "i32"),
124 BswapInit(IceType_i64, "i64"),
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700125#undef BswapInit
126
127#define CtlzInit(Overload, NameSuffix) \
128 { \
129 { \
Jan Voung44d53e12014-09-11 19:18:03 -0700130 INTRIN(Ctlz, SideEffects_F, ReturnsTwice_F) \
Jim Stichnothdd842db2015-01-27 12:53:53 -0800131 , {Overload, Overload, IceType_i1}, 3 \
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700132 } \
133 , "ctlz." NameSuffix \
134 }
Jim Stichnothd9dc82e2015-03-03 17:06:33 -0800135 CtlzInit(IceType_i32, "i32"),
136 CtlzInit(IceType_i64, "i64"),
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700137#undef CtlzInit
138
139#define CtpopInit(Overload, NameSuffix) \
140 { \
141 { \
Jan Voung44d53e12014-09-11 19:18:03 -0700142 INTRIN(Ctpop, SideEffects_F, ReturnsTwice_F) \
Jim Stichnothdd842db2015-01-27 12:53:53 -0800143 , {Overload, Overload}, 2 \
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700144 } \
145 , "ctpop." NameSuffix \
146 }
Jim Stichnothd9dc82e2015-03-03 17:06:33 -0800147 CtpopInit(IceType_i32, "i32"),
148 CtpopInit(IceType_i64, "i64"),
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700149#undef CtpopInit
150
151#define CttzInit(Overload, NameSuffix) \
152 { \
153 { \
Jan Voung44d53e12014-09-11 19:18:03 -0700154 INTRIN(Cttz, SideEffects_F, ReturnsTwice_F) \
Jim Stichnothdd842db2015-01-27 12:53:53 -0800155 , {Overload, Overload, IceType_i1}, 3 \
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700156 } \
157 , "cttz." NameSuffix \
158 }
Jim Stichnothd9dc82e2015-03-03 17:06:33 -0800159 CttzInit(IceType_i32, "i32"),
160 CttzInit(IceType_i64, "i64"),
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700161#undef CttzInit
Jan Voung44d53e12014-09-11 19:18:03 -0700162
Jim Stichnoth8c980d02015-03-19 13:01:50 -0700163#define FabsInit(Overload, NameSuffix) \
164 { \
165 { INTRIN(Fabs, SideEffects_F, ReturnsTwice_F), {Overload, Overload}, 2 } \
166 , "fabs." NameSuffix \
167 }
168 FabsInit(IceType_f32, "f32"),
169 FabsInit(IceType_f64, "f64"),
170 FabsInit(IceType_v4f32, "v4f32"),
171#undef FabsInit
172
Jim Stichnothd9dc82e2015-03-03 17:06:33 -0800173 {{INTRIN(Longjmp, SideEffects_T, ReturnsTwice_F),
174 {IceType_void, IceType_i32, IceType_i32},
175 3},
176 "nacl.longjmp"},
177 {{INTRIN(Memcpy, SideEffects_T, ReturnsTwice_F),
178 {IceType_void, IceType_i32, IceType_i32, IceType_i32, IceType_i32,
179 IceType_i1},
180 6},
181 "memcpy.p0i8.p0i8.i32"},
182 {{INTRIN(Memmove, SideEffects_T, ReturnsTwice_F),
183 {IceType_void, IceType_i32, IceType_i32, IceType_i32, IceType_i32,
184 IceType_i1},
185 6},
186 "memmove.p0i8.p0i8.i32"},
187 {{INTRIN(Memset, SideEffects_T, ReturnsTwice_F),
188 {IceType_void, IceType_i32, IceType_i8, IceType_i32, IceType_i32,
189 IceType_i1},
190 6},
191 "memset.p0i8.i32"},
192 {{INTRIN(NaClReadTP, SideEffects_F, ReturnsTwice_F), {IceType_i32}, 1},
193 "nacl.read.tp"},
194 {{INTRIN(Setjmp, SideEffects_T, ReturnsTwice_T),
195 {IceType_i32, IceType_i32},
196 2},
197 "nacl.setjmp"},
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700198
199#define SqrtInit(Overload, NameSuffix) \
200 { \
Jim Stichnothdd842db2015-01-27 12:53:53 -0800201 { INTRIN(Sqrt, SideEffects_F, ReturnsTwice_F), {Overload, Overload}, 2 } \
202 , "sqrt." NameSuffix \
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700203 }
Jim Stichnothd9dc82e2015-03-03 17:06:33 -0800204 SqrtInit(IceType_f32, "f32"),
205 SqrtInit(IceType_f64, "f64"),
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700206#undef SqrtInit
Jan Voung44d53e12014-09-11 19:18:03 -0700207
Jim Stichnothd9dc82e2015-03-03 17:06:33 -0800208 {{INTRIN(Stacksave, SideEffects_T, ReturnsTwice_F), {IceType_i32}, 1},
209 "stacksave"},
210 {{INTRIN(Stackrestore, SideEffects_T, ReturnsTwice_F),
211 {IceType_void, IceType_i32},
212 2},
213 "stackrestore"},
214 {{INTRIN(Trap, SideEffects_T, ReturnsTwice_F), {IceType_void}, 1}, "trap"}};
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700215const size_t IceIntrinsicsTableSize = llvm::array_lengthof(IceIntrinsicsTable);
216
Jan Voung44d53e12014-09-11 19:18:03 -0700217#undef INTRIN
218
Jim Stichnoth989a7032014-08-08 10:13:44 -0700219} // end of anonymous namespace
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700220
221Intrinsics::Intrinsics() {
222 for (size_t I = 0; I < IceIntrinsicsTableSize; ++I) {
223 const struct IceIntrinsicsEntry_ &Entry = IceIntrinsicsTable[I];
224 assert(Entry.Info.NumTypes <= kMaxIntrinsicParameters);
Jim Stichnothf44f3712014-10-01 14:05:51 -0700225 Map.insert(std::make_pair(IceString(Entry.IntrinsicName), Entry.Info));
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700226 }
227}
228
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700229Intrinsics::~Intrinsics() = default;
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700230
Jim Stichnotha67fc442015-03-03 16:13:11 -0800231const Intrinsics::FullIntrinsicInfo *Intrinsics::find(const IceString &Name,
232 bool &Error) const {
233 static const char LLVMPrefix[] = "llvm.";
234 const size_t LLVMPrefixLen = strlen(LLVMPrefix);
235 Error = false;
236 if (Name.substr(0, LLVMPrefixLen) != LLVMPrefix)
Jim Stichnothae953202014-12-20 06:17:49 -0800237 return nullptr;
Jim Stichnotha67fc442015-03-03 16:13:11 -0800238 IceString NameSuffix = Name.substr(LLVMPrefixLen);
239 auto it = Map.find(NameSuffix);
240 if (it == Map.end()) {
241 Error = true;
242 return nullptr;
243 }
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700244 return &it->second;
245}
246
Jim Stichnoth1c335ef2015-03-18 09:01:52 -0700247namespace {
248
249// Returns whether PNaCl allows the given memory ordering in general.
250bool isMemoryOrderValidPNaCl(uint64_t Order) {
251 switch (Order) {
252 case Intrinsics::MemoryOrderAcquire:
253 case Intrinsics::MemoryOrderRelease:
254 case Intrinsics::MemoryOrderAcquireRelease:
255 case Intrinsics::MemoryOrderSequentiallyConsistent:
256 return true;
257 default:
258 return false;
259 }
260}
261
262} // end of anonymous namespace
263
264bool Intrinsics::isMemoryOrderValid(IntrinsicID ID, uint64_t Order,
265 uint64_t OrderOther) {
266 // Reject orderings not allowed in PNaCl.
267 if (!isMemoryOrderValidPNaCl(Order))
268 return false;
269 if (ID == AtomicCmpxchg && !isMemoryOrderValidPNaCl(OrderOther))
270 return false;
271 // Reject orderings not allowed by C++11.
272 switch (ID) {
273 default:
274 llvm_unreachable("isMemoryOrderValid: Unknown IntrinsicID");
275 return false;
276 case AtomicFence:
277 case AtomicFenceAll:
278 case AtomicRMW:
279 return true;
280 case AtomicCmpxchg:
281 // Reject orderings that are disallowed by C++11 as invalid
282 // combinations for cmpxchg.
283 switch (OrderOther) {
284 case MemoryOrderRelaxed:
285 case MemoryOrderConsume:
286 case MemoryOrderAcquire:
287 case MemoryOrderSequentiallyConsistent:
288 if (OrderOther > Order)
289 return false;
290 if (Order == MemoryOrderRelease && OrderOther != MemoryOrderRelaxed)
291 return false;
292 return true;
293 default:
294 return false;
295 }
296 case AtomicLoad:
297 switch (Order) {
298 case MemoryOrderRelease:
299 case MemoryOrderAcquireRelease:
300 return false;
301 default:
302 return true;
303 }
304 case AtomicStore:
305 switch (Order) {
306 case MemoryOrderConsume:
307 case MemoryOrderAcquire:
308 case MemoryOrderAcquireRelease:
309 return false;
310 default:
311 return true;
312 }
313 }
Jan Voung5cd240d2014-06-25 10:36:46 -0700314}
315
Karl Schimpf8df26f32014-09-19 09:33:26 -0700316Intrinsics::ValidateCallValue
317Intrinsics::FullIntrinsicInfo::validateCall(const Ice::InstCall *Call,
318 SizeT &ArgIndex) const {
319 assert(NumTypes >= 1);
320 Variable *Result = Call->getDest();
Jim Stichnothae953202014-12-20 06:17:49 -0800321 if (Result == nullptr) {
Karl Schimpf8df26f32014-09-19 09:33:26 -0700322 if (Signature[0] != Ice::IceType_void)
323 return Intrinsics::BadReturnType;
324 } else if (Signature[0] != Result->getType()) {
325 return Intrinsics::BadReturnType;
326 }
327 if (Call->getNumArgs() + 1 != NumTypes) {
328 return Intrinsics::WrongNumOfArgs;
329 }
330 for (size_t i = 1; i < NumTypes; ++i) {
331 if (Call->getArg(i - 1)->getType() != Signature[i]) {
332 ArgIndex = i;
333 return Intrinsics::WrongCallArgType;
334 }
335 }
336 return Intrinsics::IsValidCall;
337}
338
339Type Intrinsics::FullIntrinsicInfo::getArgType(SizeT Index) const {
340 assert(NumTypes > 1);
341 assert(Index + 1 < NumTypes);
342 return Signature[Index + 1];
343}
344
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700345} // end of namespace Ice