4e38cd42b96a03926e17e610cb476d8e5a63366d
[ghc.git] / compiler / cmm / CmmMachOp.hs
1
2 module CmmMachOp
3 ( MachOp(..)
4 , pprMachOp, isCommutableMachOp, isAssociativeMachOp
5 , isComparisonMachOp, machOpResultType
6 , machOpArgReps, maybeInvertComparison
7
8 -- MachOp builders
9 , mo_wordAdd, mo_wordSub, mo_wordEq, mo_wordNe,mo_wordMul, mo_wordSQuot
10 , mo_wordSRem, mo_wordSNeg, mo_wordUQuot, mo_wordURem
11 , mo_wordSGe, mo_wordSLe, mo_wordSGt, mo_wordSLt, mo_wordUGe
12 , mo_wordULe, mo_wordUGt, mo_wordULt
13 , mo_wordAnd, mo_wordOr, mo_wordXor, mo_wordNot, mo_wordShl, mo_wordSShr, mo_wordUShr
14 , mo_u_8To32, mo_s_8To32, mo_u_16To32, mo_s_16To32
15 , mo_u_8ToWord, mo_s_8ToWord, mo_u_16ToWord, mo_s_16ToWord, mo_u_32ToWord, mo_s_32ToWord
16 , mo_32To8, mo_32To16, mo_WordTo8, mo_WordTo16, mo_WordTo32, mo_WordTo64
17
18 -- CallishMachOp
19 , CallishMachOp(..), callishMachOpHints
20 , pprCallishMachOp
21 )
22 where
23
24 #include "HsVersions.h"
25
26 import CmmType
27 import Outputable
28 import DynFlags
29
30 -----------------------------------------------------------------------------
31 -- MachOp
32 -----------------------------------------------------------------------------
33
34 {- |
35 Machine-level primops; ones which we can reasonably delegate to the
36 native code generators to handle.
37
38 Most operations are parameterised by the 'Width' that they operate on.
39 Some operations have separate signed and unsigned versions, and float
40 and integer versions.
41 -}
42
43 data MachOp
44 -- Integer operations (insensitive to signed/unsigned)
45 = MO_Add Width
46 | MO_Sub Width
47 | MO_Eq Width
48 | MO_Ne Width
49 | MO_Mul Width -- low word of multiply
50
51 -- Signed multiply/divide
52 | MO_S_MulMayOflo Width -- nonzero if signed multiply overflows
53 | MO_S_Quot Width -- signed / (same semantics as IntQuotOp)
54 | MO_S_Rem Width -- signed % (same semantics as IntRemOp)
55 | MO_S_Neg Width -- unary -
56
57 -- Unsigned multiply/divide
58 | MO_U_MulMayOflo Width -- nonzero if unsigned multiply overflows
59 | MO_U_Quot Width -- unsigned / (same semantics as WordQuotOp)
60 | MO_U_Rem Width -- unsigned % (same semantics as WordRemOp)
61
62 -- Signed comparisons
63 | MO_S_Ge Width
64 | MO_S_Le Width
65 | MO_S_Gt Width
66 | MO_S_Lt Width
67
68 -- Unsigned comparisons
69 | MO_U_Ge Width
70 | MO_U_Le Width
71 | MO_U_Gt Width
72 | MO_U_Lt Width
73
74 -- Floating point arithmetic
75 | MO_F_Add Width
76 | MO_F_Sub Width
77 | MO_F_Neg Width -- unary -
78 | MO_F_Mul Width
79 | MO_F_Quot Width
80
81 -- Floating point comparison
82 | MO_F_Eq Width
83 | MO_F_Ne Width
84 | MO_F_Ge Width
85 | MO_F_Le Width
86 | MO_F_Gt Width
87 | MO_F_Lt Width
88
89 -- Bitwise operations. Not all of these may be supported
90 -- at all sizes, and only integral Widths are valid.
91 | MO_And Width
92 | MO_Or Width
93 | MO_Xor Width
94 | MO_Not Width
95 | MO_Shl Width
96 | MO_U_Shr Width -- unsigned shift right
97 | MO_S_Shr Width -- signed shift right
98
99 -- Conversions. Some of these will be NOPs.
100 -- Floating-point conversions use the signed variant.
101 | MO_SF_Conv Width Width -- Signed int -> Float
102 | MO_FS_Conv Width Width -- Float -> Signed int
103 | MO_SS_Conv Width Width -- Signed int -> Signed int
104 | MO_UU_Conv Width Width -- unsigned int -> unsigned int
105 | MO_FF_Conv Width Width -- Float -> Float
106
107 -- Vector element insertion and extraction operations
108 | MO_V_Insert Length Width -- Insert scalar into vector
109 | MO_V_Extract Length Width -- Extract scalar from vector
110
111 -- Integer vector operations
112 | MO_V_Add Length Width
113 | MO_V_Sub Length Width
114 | MO_V_Mul Length Width
115
116 -- Signed vector multiply/divide
117 | MO_VS_Quot Length Width
118 | MO_VS_Rem Length Width
119 | MO_VS_Neg Length Width
120
121 -- Floating point vector operations
122 | MO_VF_Add Length Width
123 | MO_VF_Sub Length Width
124 | MO_VF_Neg Length Width -- unary -
125 | MO_VF_Mul Length Width
126 | MO_VF_Quot Length Width
127 deriving (Eq, Show)
128
129 pprMachOp :: MachOp -> SDoc
130 pprMachOp mo = text (show mo)
131
132
133
134 -- -----------------------------------------------------------------------------
135 -- Some common MachReps
136
137 -- A 'wordRep' is a machine word on the target architecture
138 -- Specifically, it is the size of an Int#, Word#, Addr#
139 -- and the unit of allocation on the stack and the heap
140 -- Any pointer is also guaranteed to be a wordRep.
141
142 mo_wordAdd, mo_wordSub, mo_wordEq, mo_wordNe,mo_wordMul, mo_wordSQuot
143 , mo_wordSRem, mo_wordSNeg, mo_wordUQuot, mo_wordURem
144 , mo_wordSGe, mo_wordSLe, mo_wordSGt, mo_wordSLt, mo_wordUGe
145 , mo_wordULe, mo_wordUGt, mo_wordULt
146 , mo_wordAnd, mo_wordOr, mo_wordXor, mo_wordNot, mo_wordShl, mo_wordSShr, mo_wordUShr
147 , mo_u_8ToWord, mo_s_8ToWord, mo_u_16ToWord, mo_s_16ToWord, mo_u_32ToWord, mo_s_32ToWord
148 , mo_WordTo8, mo_WordTo16, mo_WordTo32, mo_WordTo64
149 :: DynFlags -> MachOp
150
151 mo_u_8To32, mo_s_8To32, mo_u_16To32, mo_s_16To32
152 , mo_32To8, mo_32To16
153 :: MachOp
154
155 mo_wordAdd dflags = MO_Add (wordWidth dflags)
156 mo_wordSub dflags = MO_Sub (wordWidth dflags)
157 mo_wordEq dflags = MO_Eq (wordWidth dflags)
158 mo_wordNe dflags = MO_Ne (wordWidth dflags)
159 mo_wordMul dflags = MO_Mul (wordWidth dflags)
160 mo_wordSQuot dflags = MO_S_Quot (wordWidth dflags)
161 mo_wordSRem dflags = MO_S_Rem (wordWidth dflags)
162 mo_wordSNeg dflags = MO_S_Neg (wordWidth dflags)
163 mo_wordUQuot dflags = MO_U_Quot (wordWidth dflags)
164 mo_wordURem dflags = MO_U_Rem (wordWidth dflags)
165
166 mo_wordSGe dflags = MO_S_Ge (wordWidth dflags)
167 mo_wordSLe dflags = MO_S_Le (wordWidth dflags)
168 mo_wordSGt dflags = MO_S_Gt (wordWidth dflags)
169 mo_wordSLt dflags = MO_S_Lt (wordWidth dflags)
170
171 mo_wordUGe dflags = MO_U_Ge (wordWidth dflags)
172 mo_wordULe dflags = MO_U_Le (wordWidth dflags)
173 mo_wordUGt dflags = MO_U_Gt (wordWidth dflags)
174 mo_wordULt dflags = MO_U_Lt (wordWidth dflags)
175
176 mo_wordAnd dflags = MO_And (wordWidth dflags)
177 mo_wordOr dflags = MO_Or (wordWidth dflags)
178 mo_wordXor dflags = MO_Xor (wordWidth dflags)
179 mo_wordNot dflags = MO_Not (wordWidth dflags)
180 mo_wordShl dflags = MO_Shl (wordWidth dflags)
181 mo_wordSShr dflags = MO_S_Shr (wordWidth dflags)
182 mo_wordUShr dflags = MO_U_Shr (wordWidth dflags)
183
184 mo_u_8To32 = MO_UU_Conv W8 W32
185 mo_s_8To32 = MO_SS_Conv W8 W32
186 mo_u_16To32 = MO_UU_Conv W16 W32
187 mo_s_16To32 = MO_SS_Conv W16 W32
188
189 mo_u_8ToWord dflags = MO_UU_Conv W8 (wordWidth dflags)
190 mo_s_8ToWord dflags = MO_SS_Conv W8 (wordWidth dflags)
191 mo_u_16ToWord dflags = MO_UU_Conv W16 (wordWidth dflags)
192 mo_s_16ToWord dflags = MO_SS_Conv W16 (wordWidth dflags)
193 mo_s_32ToWord dflags = MO_SS_Conv W32 (wordWidth dflags)
194 mo_u_32ToWord dflags = MO_UU_Conv W32 (wordWidth dflags)
195
196 mo_WordTo8 dflags = MO_UU_Conv (wordWidth dflags) W8
197 mo_WordTo16 dflags = MO_UU_Conv (wordWidth dflags) W16
198 mo_WordTo32 dflags = MO_UU_Conv (wordWidth dflags) W32
199 mo_WordTo64 dflags = MO_UU_Conv (wordWidth dflags) W64
200
201 mo_32To8 = MO_UU_Conv W32 W8
202 mo_32To16 = MO_UU_Conv W32 W16
203
204
205 -- ----------------------------------------------------------------------------
206 -- isCommutableMachOp
207
208 {- |
209 Returns 'True' if the MachOp has commutable arguments. This is used
210 in the platform-independent Cmm optimisations.
211
212 If in doubt, return 'False'. This generates worse code on the
213 native routes, but is otherwise harmless.
214 -}
215 isCommutableMachOp :: MachOp -> Bool
216 isCommutableMachOp mop =
217 case mop of
218 MO_Add _ -> True
219 MO_Eq _ -> True
220 MO_Ne _ -> True
221 MO_Mul _ -> True
222 MO_S_MulMayOflo _ -> True
223 MO_U_MulMayOflo _ -> True
224 MO_And _ -> True
225 MO_Or _ -> True
226 MO_Xor _ -> True
227 MO_F_Add _ -> True
228 MO_F_Mul _ -> True
229 _other -> False
230
231 -- ----------------------------------------------------------------------------
232 -- isAssociativeMachOp
233
234 {- |
235 Returns 'True' if the MachOp is associative (i.e. @(x+y)+z == x+(y+z)@)
236 This is used in the platform-independent Cmm optimisations.
237
238 If in doubt, return 'False'. This generates worse code on the
239 native routes, but is otherwise harmless.
240 -}
241 isAssociativeMachOp :: MachOp -> Bool
242 isAssociativeMachOp mop =
243 case mop of
244 MO_Add {} -> True -- NB: does not include
245 MO_Mul {} -> True -- floatint point!
246 MO_And {} -> True
247 MO_Or {} -> True
248 MO_Xor {} -> True
249 _other -> False
250
251 -- ----------------------------------------------------------------------------
252 -- isComparisonMachOp
253
254 {- |
255 Returns 'True' if the MachOp is a comparison.
256
257 If in doubt, return False. This generates worse code on the
258 native routes, but is otherwise harmless.
259 -}
260 isComparisonMachOp :: MachOp -> Bool
261 isComparisonMachOp mop =
262 case mop of
263 MO_Eq _ -> True
264 MO_Ne _ -> True
265 MO_S_Ge _ -> True
266 MO_S_Le _ -> True
267 MO_S_Gt _ -> True
268 MO_S_Lt _ -> True
269 MO_U_Ge _ -> True
270 MO_U_Le _ -> True
271 MO_U_Gt _ -> True
272 MO_U_Lt _ -> True
273 MO_F_Eq {} -> True
274 MO_F_Ne {} -> True
275 MO_F_Ge {} -> True
276 MO_F_Le {} -> True
277 MO_F_Gt {} -> True
278 MO_F_Lt {} -> True
279 _other -> False
280
281 -- -----------------------------------------------------------------------------
282 -- Inverting conditions
283
284 -- Sometimes it's useful to be able to invert the sense of a
285 -- condition. Not all conditional tests are invertible: in
286 -- particular, floating point conditionals cannot be inverted, because
287 -- there exist floating-point values which return False for both senses
288 -- of a condition (eg. !(NaN > NaN) && !(NaN /<= NaN)).
289
290 maybeInvertComparison :: MachOp -> Maybe MachOp
291 maybeInvertComparison op
292 = case op of -- None of these Just cases include floating point
293 MO_Eq r -> Just (MO_Ne r)
294 MO_Ne r -> Just (MO_Eq r)
295 MO_U_Lt r -> Just (MO_U_Ge r)
296 MO_U_Gt r -> Just (MO_U_Le r)
297 MO_U_Le r -> Just (MO_U_Gt r)
298 MO_U_Ge r -> Just (MO_U_Lt r)
299 MO_S_Lt r -> Just (MO_S_Ge r)
300 MO_S_Gt r -> Just (MO_S_Le r)
301 MO_S_Le r -> Just (MO_S_Gt r)
302 MO_S_Ge r -> Just (MO_S_Lt r)
303 _other -> Nothing
304
305 -- ----------------------------------------------------------------------------
306 -- machOpResultType
307
308 {- |
309 Returns the MachRep of the result of a MachOp.
310 -}
311 machOpResultType :: DynFlags -> MachOp -> [CmmType] -> CmmType
312 machOpResultType dflags mop tys =
313 case mop of
314 MO_Add {} -> ty1 -- Preserve GC-ptr-hood
315 MO_Sub {} -> ty1 -- of first arg
316 MO_Mul r -> cmmBits r
317 MO_S_MulMayOflo r -> cmmBits r
318 MO_S_Quot r -> cmmBits r
319 MO_S_Rem r -> cmmBits r
320 MO_S_Neg r -> cmmBits r
321 MO_U_MulMayOflo r -> cmmBits r
322 MO_U_Quot r -> cmmBits r
323 MO_U_Rem r -> cmmBits r
324
325 MO_Eq {} -> comparisonResultRep dflags
326 MO_Ne {} -> comparisonResultRep dflags
327 MO_S_Ge {} -> comparisonResultRep dflags
328 MO_S_Le {} -> comparisonResultRep dflags
329 MO_S_Gt {} -> comparisonResultRep dflags
330 MO_S_Lt {} -> comparisonResultRep dflags
331
332 MO_U_Ge {} -> comparisonResultRep dflags
333 MO_U_Le {} -> comparisonResultRep dflags
334 MO_U_Gt {} -> comparisonResultRep dflags
335 MO_U_Lt {} -> comparisonResultRep dflags
336
337 MO_F_Add r -> cmmFloat r
338 MO_F_Sub r -> cmmFloat r
339 MO_F_Mul r -> cmmFloat r
340 MO_F_Quot r -> cmmFloat r
341 MO_F_Neg r -> cmmFloat r
342 MO_F_Eq {} -> comparisonResultRep dflags
343 MO_F_Ne {} -> comparisonResultRep dflags
344 MO_F_Ge {} -> comparisonResultRep dflags
345 MO_F_Le {} -> comparisonResultRep dflags
346 MO_F_Gt {} -> comparisonResultRep dflags
347 MO_F_Lt {} -> comparisonResultRep dflags
348
349 MO_And {} -> ty1 -- Used for pointer masking
350 MO_Or {} -> ty1
351 MO_Xor {} -> ty1
352 MO_Not r -> cmmBits r
353 MO_Shl r -> cmmBits r
354 MO_U_Shr r -> cmmBits r
355 MO_S_Shr r -> cmmBits r
356
357 MO_SS_Conv _ to -> cmmBits to
358 MO_UU_Conv _ to -> cmmBits to
359 MO_FS_Conv _ to -> cmmBits to
360 MO_SF_Conv _ to -> cmmFloat to
361 MO_FF_Conv _ to -> cmmFloat to
362
363 MO_V_Insert {} -> ty1
364 MO_V_Extract {} -> vecElemType ty1
365
366 MO_V_Add {} -> ty1
367 MO_V_Sub {} -> ty1
368 MO_V_Mul {} -> ty1
369
370 MO_VS_Quot {} -> ty1
371 MO_VS_Rem {} -> ty1
372 MO_VS_Neg {} -> ty1
373
374 MO_VF_Add {} -> ty1
375 MO_VF_Sub {} -> ty1
376 MO_VF_Mul {} -> ty1
377 MO_VF_Quot {} -> ty1
378 MO_VF_Neg {} -> ty1
379 where
380 (ty1:_) = tys
381
382 comparisonResultRep :: DynFlags -> CmmType
383 comparisonResultRep = bWord -- is it?
384
385
386 -- -----------------------------------------------------------------------------
387 -- machOpArgReps
388
389 -- | This function is used for debugging only: we can check whether an
390 -- application of a MachOp is "type-correct" by checking that the MachReps of
391 -- its arguments are the same as the MachOp expects. This is used when
392 -- linting a CmmExpr.
393
394 machOpArgReps :: DynFlags -> MachOp -> [Width]
395 machOpArgReps dflags op =
396 case op of
397 MO_Add r -> [r,r]
398 MO_Sub r -> [r,r]
399 MO_Eq r -> [r,r]
400 MO_Ne r -> [r,r]
401 MO_Mul r -> [r,r]
402 MO_S_MulMayOflo r -> [r,r]
403 MO_S_Quot r -> [r,r]
404 MO_S_Rem r -> [r,r]
405 MO_S_Neg r -> [r]
406 MO_U_MulMayOflo r -> [r,r]
407 MO_U_Quot r -> [r,r]
408 MO_U_Rem r -> [r,r]
409
410 MO_S_Ge r -> [r,r]
411 MO_S_Le r -> [r,r]
412 MO_S_Gt r -> [r,r]
413 MO_S_Lt r -> [r,r]
414
415 MO_U_Ge r -> [r,r]
416 MO_U_Le r -> [r,r]
417 MO_U_Gt r -> [r,r]
418 MO_U_Lt r -> [r,r]
419
420 MO_F_Add r -> [r,r]
421 MO_F_Sub r -> [r,r]
422 MO_F_Mul r -> [r,r]
423 MO_F_Quot r -> [r,r]
424 MO_F_Neg r -> [r]
425 MO_F_Eq r -> [r,r]
426 MO_F_Ne r -> [r,r]
427 MO_F_Ge r -> [r,r]
428 MO_F_Le r -> [r,r]
429 MO_F_Gt r -> [r,r]
430 MO_F_Lt r -> [r,r]
431
432 MO_And r -> [r,r]
433 MO_Or r -> [r,r]
434 MO_Xor r -> [r,r]
435 MO_Not r -> [r]
436 MO_Shl r -> [r, wordWidth dflags]
437 MO_U_Shr r -> [r, wordWidth dflags]
438 MO_S_Shr r -> [r, wordWidth dflags]
439
440 MO_SS_Conv from _ -> [from]
441 MO_UU_Conv from _ -> [from]
442 MO_SF_Conv from _ -> [from]
443 MO_FS_Conv from _ -> [from]
444 MO_FF_Conv from _ -> [from]
445
446 MO_V_Insert l r -> [typeWidth (vec l (cmmFloat r)),r,wordWidth dflags]
447 MO_V_Extract l r -> [typeWidth (vec l (cmmFloat r)),wordWidth dflags]
448
449 MO_V_Add _ r -> [r,r]
450 MO_V_Sub _ r -> [r,r]
451 MO_V_Mul _ r -> [r,r]
452
453 MO_VS_Quot _ r -> [r,r]
454 MO_VS_Rem _ r -> [r,r]
455 MO_VS_Neg _ r -> [r]
456
457 MO_VF_Add _ r -> [r,r]
458 MO_VF_Sub _ r -> [r,r]
459 MO_VF_Mul _ r -> [r,r]
460 MO_VF_Quot _ r -> [r,r]
461 MO_VF_Neg _ r -> [r]
462
463 -----------------------------------------------------------------------------
464 -- CallishMachOp
465 -----------------------------------------------------------------------------
466
467 -- CallishMachOps tend to be implemented by foreign calls in some backends,
468 -- so we separate them out. In Cmm, these can only occur in a
469 -- statement position, in contrast to an ordinary MachOp which can occur
470 -- anywhere in an expression.
471 data CallishMachOp
472 = MO_F64_Pwr
473 | MO_F64_Sin
474 | MO_F64_Cos
475 | MO_F64_Tan
476 | MO_F64_Sinh
477 | MO_F64_Cosh
478 | MO_F64_Tanh
479 | MO_F64_Asin
480 | MO_F64_Acos
481 | MO_F64_Atan
482 | MO_F64_Log
483 | MO_F64_Exp
484 | MO_F64_Sqrt
485 | MO_F32_Pwr
486 | MO_F32_Sin
487 | MO_F32_Cos
488 | MO_F32_Tan
489 | MO_F32_Sinh
490 | MO_F32_Cosh
491 | MO_F32_Tanh
492 | MO_F32_Asin
493 | MO_F32_Acos
494 | MO_F32_Atan
495 | MO_F32_Log
496 | MO_F32_Exp
497 | MO_F32_Sqrt
498
499 | MO_UF_Conv Width
500
501 | MO_S_QuotRem Width
502 | MO_U_QuotRem Width
503 | MO_U_QuotRem2 Width
504 | MO_Add2 Width
505 | MO_U_Mul2 Width
506
507 | MO_WriteBarrier
508 | MO_Touch -- Keep variables live (when using interior pointers)
509
510 -- Note that these three MachOps all take 1 extra parameter than the
511 -- standard C lib versions. The extra (last) parameter contains
512 -- alignment of the pointers. Used for optimisation in backends.
513 | MO_Memcpy
514 | MO_Memset
515 | MO_Memmove
516
517 | MO_PopCnt Width
518 deriving (Eq, Show)
519
520 pprCallishMachOp :: CallishMachOp -> SDoc
521 pprCallishMachOp mo = text (show mo)
522
523 callishMachOpHints :: CallishMachOp -> ([ForeignHint], [ForeignHint])
524 callishMachOpHints op = case op of
525 MO_Memcpy -> ([], [AddrHint,AddrHint,NoHint,NoHint])
526 MO_Memset -> ([], [AddrHint,NoHint,NoHint,NoHint])
527 MO_Memmove -> ([], [AddrHint,AddrHint,NoHint,NoHint])
528 _ -> ([],[])
529 -- empty lists indicate NoHint