1 | # Copyright (C) 2012-2021 Apple Inc. All rights reserved.
|
---|
2 | #
|
---|
3 | # Redistribution and use in source and binary forms, with or without
|
---|
4 | # modification, are permitted provided that the following conditions
|
---|
5 | # are met:
|
---|
6 | # 1. Redistributions of source code must retain the above copyright
|
---|
7 | # notice, this list of conditions and the following disclaimer.
|
---|
8 | # 2. Redistributions in binary form must reproduce the above copyright
|
---|
9 | # notice, this list of conditions and the following disclaimer in the
|
---|
10 | # documentation and/or other materials provided with the distribution.
|
---|
11 | #
|
---|
12 | # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
|
---|
13 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
---|
14 | # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
---|
15 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
|
---|
16 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
---|
17 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
---|
18 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
---|
19 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
---|
20 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
---|
21 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
---|
22 | # THE POSSIBILITY OF SUCH DAMAGE.
|
---|
23 |
|
---|
24 | require "config"
|
---|
25 | require "ast"
|
---|
26 | require "opt"
|
---|
27 |
|
---|
28 | # The CLoop llint backend is initially based on the ARMv7 backend, and
|
---|
29 | # then further enhanced with a few instructions from the x86 backend to
|
---|
30 | # support building for X64 targets. Hence, the shape of the generated
|
---|
31 | # code and the usage convention of registers will look a lot like the
|
---|
32 | # ARMv7 backend's.
|
---|
33 |
|
---|
34 | def cloopMapType(type)
|
---|
35 | case type
|
---|
36 | when :intptr; ".i()"
|
---|
37 | when :uintptr; ".u()"
|
---|
38 | when :int32; ".i32()"
|
---|
39 | when :uint32; ".u32()"
|
---|
40 | when :int64; ".i64()"
|
---|
41 | when :uint64; ".u64()"
|
---|
42 | when :int8; ".i8()"
|
---|
43 | when :uint8; ".u8()"
|
---|
44 | when :int8Ptr; ".i8p()"
|
---|
45 | when :voidPtr; ".vp()"
|
---|
46 | when :nativeFunc; ".nativeFunc()"
|
---|
47 | when :double; ".d()"
|
---|
48 | when :bitsAsDouble; ".bitsAsDouble()"
|
---|
49 | when :bitsAsInt64; ".bitsAsInt64()"
|
---|
50 | when :opcode; ".opcode()"
|
---|
51 | else;
|
---|
52 | raise "Unsupported type"
|
---|
53 | end
|
---|
54 | end
|
---|
55 |
|
---|
56 |
|
---|
57 | class SpecialRegister < NoChildren
|
---|
58 | def clLValue(type=:intptr)
|
---|
59 | clDump
|
---|
60 | end
|
---|
61 | def clDump
|
---|
62 | @name
|
---|
63 | end
|
---|
64 | def clValue(type=:intptr)
|
---|
65 | @name + cloopMapType(type)
|
---|
66 | end
|
---|
67 | end
|
---|
68 |
|
---|
69 | C_LOOP_SCRATCH_FPR = SpecialRegister.new("d6")
|
---|
70 |
|
---|
71 | class RegisterID
|
---|
72 | def clDump
|
---|
73 | case name
|
---|
74 | # The cloop is modelled on the ARM implementation. Hence, the a0-a3
|
---|
75 | # registers are aliases for r0-r3 i.e. t0-t3 in our case.
|
---|
76 | when "t0", "a0", "r0"
|
---|
77 | "t0"
|
---|
78 | when "t1", "a1", "r1"
|
---|
79 | "t1"
|
---|
80 | when "t2", "a2"
|
---|
81 | "t2"
|
---|
82 | when "t3", "a3"
|
---|
83 | "t3"
|
---|
84 | when "t4"
|
---|
85 | "pc"
|
---|
86 | when "t5"
|
---|
87 | "t5"
|
---|
88 | when "csr0"
|
---|
89 | "pcBase"
|
---|
90 | when "csr1"
|
---|
91 | "numberTag"
|
---|
92 | when "csr2"
|
---|
93 | "notCellMask"
|
---|
94 | when "csr3"
|
---|
95 | "metadataTable"
|
---|
96 | when "cfr"
|
---|
97 | "cfr"
|
---|
98 | when "lr"
|
---|
99 | "lr"
|
---|
100 | when "sp"
|
---|
101 | "sp"
|
---|
102 | else
|
---|
103 | raise "Bad register #{name} for C_LOOP at #{codeOriginString}"
|
---|
104 | end
|
---|
105 | end
|
---|
106 | def clLValue(type=:intptr)
|
---|
107 | clDump
|
---|
108 | end
|
---|
109 | def clValue(type=:intptr)
|
---|
110 | clDump + cloopMapType(type)
|
---|
111 | end
|
---|
112 | end
|
---|
113 |
|
---|
114 | class FPRegisterID
|
---|
115 | def clDump
|
---|
116 | case name
|
---|
117 | when "ft0", "fr"
|
---|
118 | "d0"
|
---|
119 | when "ft1"
|
---|
120 | "d1"
|
---|
121 | when "ft2"
|
---|
122 | "d2"
|
---|
123 | when "ft3"
|
---|
124 | "d3"
|
---|
125 | when "ft4"
|
---|
126 | "d4"
|
---|
127 | when "ft5"
|
---|
128 | "d5"
|
---|
129 | else
|
---|
130 | raise "Bad register #{name} for C_LOOP at #{codeOriginString}"
|
---|
131 | end
|
---|
132 | end
|
---|
133 | def clLValue(type=:intptr)
|
---|
134 | clDump
|
---|
135 | end
|
---|
136 | def clValue(type=:intptr)
|
---|
137 | clDump + cloopMapType(type)
|
---|
138 | end
|
---|
139 | end
|
---|
140 |
|
---|
141 | class Immediate
|
---|
142 | def clDump
|
---|
143 | "#{value}"
|
---|
144 | end
|
---|
145 | def clLValue(type=:intptr)
|
---|
146 | raise "Immediate cannot be used as an LValue"
|
---|
147 | end
|
---|
148 | def clValue(type=:intptr)
|
---|
149 | # There is a case of a very large unsigned number (0x8000000000000000)
|
---|
150 | # which we wish to encode. Unfortunately, the C/C++ compiler
|
---|
151 | # complains if we express that number as a positive decimal integer.
|
---|
152 | # Hence, for positive values, we just convert the number into hex form
|
---|
153 | # to keep the compiler happy.
|
---|
154 | #
|
---|
155 | # However, for negative values, the to_s(16) hex conversion method does
|
---|
156 | # not strip the "-" sign resulting in a meaningless "0x-..." valueStr.
|
---|
157 | # To workaround this, we simply don't encode negative numbers as hex.
|
---|
158 |
|
---|
159 | valueStr = (value < 0) ? "#{value}" : "0x#{value.to_s(16)}"
|
---|
160 |
|
---|
161 | case type
|
---|
162 | when :int8; "int8_t(#{valueStr})"
|
---|
163 | when :int16; "int16_t(#{valueStr})"
|
---|
164 | when :int32; "int32_t(#{valueStr})"
|
---|
165 | when :int64; "int64_t(#{valueStr})"
|
---|
166 | when :intptr; "intptr_t(#{valueStr})"
|
---|
167 | when :uint8; "uint8_t(#{valueStr})"
|
---|
168 | when :uint32; "uint32_t(#{valueStr})"
|
---|
169 | when :uint64; "uint64_t(#{valueStr})"
|
---|
170 | when :uintptr; "uintptr_t(#{valueStr})"
|
---|
171 | else
|
---|
172 | raise "Not implemented immediate of type: #{type}"
|
---|
173 | end
|
---|
174 | end
|
---|
175 | end
|
---|
176 |
|
---|
177 | class Address
|
---|
178 | def clDump
|
---|
179 | "[#{base.clDump}, #{offset.value}]"
|
---|
180 | end
|
---|
181 | def clLValue(type=:intptr)
|
---|
182 | clValue(type)
|
---|
183 | end
|
---|
184 | def clValue(type=:intptr)
|
---|
185 | case type
|
---|
186 | when :int8; int8MemRef
|
---|
187 | when :int16; int16MemRef
|
---|
188 | when :int32; int32MemRef
|
---|
189 | when :int64; int64MemRef
|
---|
190 | when :intptr; intptrMemRef
|
---|
191 | when :uint8; uint8MemRef
|
---|
192 | when :uint32; uint32MemRef
|
---|
193 | when :uint64; uint64MemRef
|
---|
194 | when :uintptr; uintptrMemRef
|
---|
195 | when :opcode; opcodeMemRef
|
---|
196 | when :nativeFunc; nativeFuncMemRef
|
---|
197 | else
|
---|
198 | raise "Unexpected Address type: #{type}"
|
---|
199 | end
|
---|
200 | end
|
---|
201 | def pointerExpr
|
---|
202 | if offset.value == 0
|
---|
203 | "#{base.clValue(:int8Ptr)}"
|
---|
204 | elsif offset.value > 0
|
---|
205 | "#{base.clValue(:int8Ptr)} + #{offset.value}"
|
---|
206 | else
|
---|
207 | "#{base.clValue(:int8Ptr)} - #{-offset.value}"
|
---|
208 | end
|
---|
209 | end
|
---|
210 | def int8MemRef
|
---|
211 | "*CAST<int8_t*>(#{pointerExpr})"
|
---|
212 | end
|
---|
213 | def int16MemRef
|
---|
214 | "*CAST<int16_t*>(#{pointerExpr})"
|
---|
215 | end
|
---|
216 | def int32MemRef
|
---|
217 | "*CAST<int32_t*>(#{pointerExpr})"
|
---|
218 | end
|
---|
219 | def int64MemRef
|
---|
220 | "*CAST<int64_t*>(#{pointerExpr})"
|
---|
221 | end
|
---|
222 | def intptrMemRef
|
---|
223 | "*CAST<intptr_t*>(#{pointerExpr})"
|
---|
224 | end
|
---|
225 | def uint8MemRef
|
---|
226 | "*CAST<uint8_t*>(#{pointerExpr})"
|
---|
227 | end
|
---|
228 | def uint16MemRef
|
---|
229 | "*CAST<uint16_t*>(#{pointerExpr})"
|
---|
230 | end
|
---|
231 | def uint32MemRef
|
---|
232 | "*CAST<uint32_t*>(#{pointerExpr})"
|
---|
233 | end
|
---|
234 | def uint64MemRef
|
---|
235 | "*CAST<uint64_t*>(#{pointerExpr})"
|
---|
236 | end
|
---|
237 | def uintptrMemRef
|
---|
238 | "*CAST<uintptr_t*>(#{pointerExpr})"
|
---|
239 | end
|
---|
240 | def nativeFuncMemRef
|
---|
241 | "*CAST<NativeFunction*>(#{pointerExpr})"
|
---|
242 | end
|
---|
243 | def opcodeMemRef
|
---|
244 | "*CAST<Opcode*>(#{pointerExpr})"
|
---|
245 | end
|
---|
246 | def dblMemRef
|
---|
247 | "*CAST<double*>(#{pointerExpr})"
|
---|
248 | end
|
---|
249 | end
|
---|
250 |
|
---|
251 | class BaseIndex
|
---|
252 | def clDump
|
---|
253 | "[#{base.clDump}, #{offset.clDump}, #{index.clDump} << #{scaleShift}]"
|
---|
254 | end
|
---|
255 | def clLValue(type=:intptr)
|
---|
256 | clValue(type)
|
---|
257 | end
|
---|
258 | def clValue(type=:intptr)
|
---|
259 | case type
|
---|
260 | when :int8; int8MemRef
|
---|
261 | when :int32; int32MemRef
|
---|
262 | when :int16; int16MemRef
|
---|
263 | when :int64; int64MemRef
|
---|
264 | when :intptr; intptrMemRef
|
---|
265 | when :uint8; uint8MemRef
|
---|
266 | when :uint16; uint16MemRef
|
---|
267 | when :uint32; uint32MemRef
|
---|
268 | when :uint64; uint64MemRef
|
---|
269 | when :uintptr; uintptrMemRef
|
---|
270 | when :opcode; opcodeMemRef
|
---|
271 | else
|
---|
272 | raise "Unexpected BaseIndex type: #{type}"
|
---|
273 | end
|
---|
274 | end
|
---|
275 | def pointerExpr
|
---|
276 | if offset.value == 0
|
---|
277 | "#{base.clValue(:int8Ptr)} + (#{index.clValue} << #{scaleShift})"
|
---|
278 | else
|
---|
279 | "#{base.clValue(:int8Ptr)} + (#{index.clValue} << #{scaleShift}) + #{offset.clValue}"
|
---|
280 | end
|
---|
281 | end
|
---|
282 | def int8MemRef
|
---|
283 | "*CAST<int8_t*>(#{pointerExpr})"
|
---|
284 | end
|
---|
285 | def int16MemRef
|
---|
286 | "*CAST<int16_t*>(#{pointerExpr})"
|
---|
287 | end
|
---|
288 | def int32MemRef
|
---|
289 | "*CAST<int32_t*>(#{pointerExpr})"
|
---|
290 | end
|
---|
291 | def int64MemRef
|
---|
292 | "*CAST<int64_t*>(#{pointerExpr})"
|
---|
293 | end
|
---|
294 | def intptrMemRef
|
---|
295 | "*CAST<intptr_t*>(#{pointerExpr})"
|
---|
296 | end
|
---|
297 | def uint8MemRef
|
---|
298 | "*CAST<uint8_t*>(#{pointerExpr})"
|
---|
299 | end
|
---|
300 | def uint16MemRef
|
---|
301 | "*CAST<uint16_t*>(#{pointerExpr})"
|
---|
302 | end
|
---|
303 | def uint32MemRef
|
---|
304 | "*CAST<uint32_t*>(#{pointerExpr})"
|
---|
305 | end
|
---|
306 | def uint64MemRef
|
---|
307 | "*CAST<uint64_t*>(#{pointerExpr})"
|
---|
308 | end
|
---|
309 | def uintptrMemRef
|
---|
310 | "*CAST<uintptr_t*>(#{pointerExpr})"
|
---|
311 | end
|
---|
312 | def opcodeMemRef
|
---|
313 | "*CAST<Opcode*>(#{pointerExpr})"
|
---|
314 | end
|
---|
315 | def dblMemRef
|
---|
316 | "*CAST<double*>(#{pointerExpr})"
|
---|
317 | end
|
---|
318 | end
|
---|
319 |
|
---|
320 | class AbsoluteAddress
|
---|
321 | def clDump
|
---|
322 | "#{codeOriginString}"
|
---|
323 | end
|
---|
324 | def clLValue(type=:intptr)
|
---|
325 | clValue(type)
|
---|
326 | end
|
---|
327 | def clValue
|
---|
328 | clDump
|
---|
329 | end
|
---|
330 | end
|
---|
331 |
|
---|
332 | class LabelReference
|
---|
333 | def intptrMemRef
|
---|
334 | "*CAST<intptr_t*>(&#{cLabel})"
|
---|
335 | end
|
---|
336 | def cloopEmitLea(destination, type)
|
---|
337 | $asm.putc "#{destination.clLValue(:voidPtr)} = CAST<void*>(&#{cLabel});"
|
---|
338 | if offset != 0
|
---|
339 | $asm.putc "#{destination.clLValue(:int8Ptr)} = #{destination.clValue(:int8Ptr)} + #{offset};"
|
---|
340 | end
|
---|
341 | end
|
---|
342 | end
|
---|
343 |
|
---|
344 |
|
---|
345 | #
|
---|
346 | # Lea support.
|
---|
347 | #
|
---|
348 |
|
---|
349 | class Address
|
---|
350 | def cloopEmitLea(destination, type)
|
---|
351 | if destination == base
|
---|
352 | $asm.putc "#{destination.clLValue(:int8Ptr)} = #{destination.clValue(:int8Ptr)} + #{offset.clValue(type)};"
|
---|
353 | else
|
---|
354 | $asm.putc "#{destination.clLValue(:int8Ptr)} = #{base.clValue(:int8Ptr)} + #{offset.clValue(type)};"
|
---|
355 | end
|
---|
356 | end
|
---|
357 | end
|
---|
358 |
|
---|
359 | class BaseIndex
|
---|
360 | def cloopEmitLea(destination, type)
|
---|
361 | raise "Malformed BaseIndex, offset should be zero at #{codeOriginString}" unless offset.value == 0
|
---|
362 | $asm.putc "#{destination.clLValue(:int8Ptr)} = #{base.clValue(:int8Ptr)} + (#{index.clValue} << #{scaleShift});"
|
---|
363 | end
|
---|
364 | end
|
---|
365 |
|
---|
366 | #
|
---|
367 | # Actual lowering code follows.
|
---|
368 | #
|
---|
369 |
|
---|
370 | class Sequence
|
---|
371 | def getModifiedListC_LOOP
|
---|
372 | myList = @list
|
---|
373 |
|
---|
374 | # Verify that we will only see instructions and labels.
|
---|
375 | myList.each {
|
---|
376 | | node |
|
---|
377 | unless node.is_a? Instruction or
|
---|
378 | node.is_a? Label or
|
---|
379 | node.is_a? LocalLabel or
|
---|
380 | node.is_a? Skip
|
---|
381 | raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
|
---|
382 | end
|
---|
383 | }
|
---|
384 |
|
---|
385 | return myList
|
---|
386 | end
|
---|
387 | end
|
---|
388 |
|
---|
389 | def clOperands(operands)
|
---|
390 | operands.map{|v| v.clDump}.join(", ")
|
---|
391 | end
|
---|
392 |
|
---|
393 |
|
---|
394 | def cloopEmitOperation(operands, type, operator)
|
---|
395 | raise unless type == :intptr || type == :uintptr || type == :int32 || type == :uint32 || \
|
---|
396 | type == :int64 || type == :uint64 || type == :double || type == :int16
|
---|
397 | if operands.size == 3
|
---|
398 | op1 = operands[0]
|
---|
399 | op2 = operands[1]
|
---|
400 | dst = operands[2]
|
---|
401 | else
|
---|
402 | raise unless operands.size == 2
|
---|
403 | op1 = operands[1]
|
---|
404 | op2 = operands[0]
|
---|
405 | dst = operands[1]
|
---|
406 | end
|
---|
407 | raise unless not dst.is_a? Immediate
|
---|
408 | if dst.is_a? RegisterID and (type == :int32 or type == :uint32)
|
---|
409 | truncationHeader = "(uint32_t)("
|
---|
410 | truncationFooter = ")"
|
---|
411 | elsif dst.is_a? RegisterID and (type == :int16)
|
---|
412 | truncationHeader = "(uint16_t)("
|
---|
413 | truncationFooter = ")"
|
---|
414 | else
|
---|
415 | truncationHeader = ""
|
---|
416 | truncationFooter = ""
|
---|
417 | end
|
---|
418 | $asm.putc "#{dst.clLValue(type)} = #{truncationHeader}#{op1.clValue(type)} #{operator} #{op2.clValue(type)}#{truncationFooter};"
|
---|
419 | end
|
---|
420 |
|
---|
421 | def cloopEmitShiftOperation(operands, type, operator)
|
---|
422 | raise unless type == :intptr || type == :uintptr || type == :int32 || type == :uint32 || type == :int64 || type == :uint64
|
---|
423 | if operands.size == 3
|
---|
424 | op1 = operands[0]
|
---|
425 | op2 = operands[1]
|
---|
426 | dst = operands[2]
|
---|
427 | else
|
---|
428 | op1 = operands[1]
|
---|
429 | op2 = operands[0]
|
---|
430 | dst = operands[1]
|
---|
431 | end
|
---|
432 | if dst.is_a? RegisterID and (type == :int32 or type == :uint32)
|
---|
433 | truncationHeader = "(uint32_t)("
|
---|
434 | truncationFooter = ")"
|
---|
435 | else
|
---|
436 | truncationHeader = ""
|
---|
437 | truncationFooter = ""
|
---|
438 | end
|
---|
439 | shiftMask = "((sizeof(uintptr_t) == 8) ? 0x3f : 0x1f)" if type == :intptr || type == :uintptr
|
---|
440 | shiftMask = "0x3f" if type == :int64 || type == :uint64
|
---|
441 | shiftMask = "0x1f" if type == :int32 || type == :uint32
|
---|
442 | $asm.putc "#{dst.clLValue(type)} = #{truncationHeader}#{operands[1].clValue(type)} #{operator} (#{operands[0].clValue(:intptr)} & #{shiftMask})#{truncationFooter};"
|
---|
443 | end
|
---|
444 |
|
---|
445 | def cloopEmitUnaryOperation(operands, type, operator)
|
---|
446 | raise unless type == :intptr || type == :uintptr || type == :int32 || type == :uint32 || type == :int64 || type == :uint64
|
---|
447 | raise unless operands.size == 1
|
---|
448 | raise unless not operands[0].is_a? Immediate
|
---|
449 | op = operands[0]
|
---|
450 | dst = operands[0]
|
---|
451 | if dst.is_a? RegisterID and (type == :int32 or type == :uint32)
|
---|
452 | truncationHeader = "(uint32_t)("
|
---|
453 | truncationFooter = ")"
|
---|
454 | else
|
---|
455 | truncationHeader = ""
|
---|
456 | truncationFooter = ""
|
---|
457 | end
|
---|
458 | $asm.putc "#{dst.clLValue(type)} = #{truncationHeader}#{operator}#{op.clValue(type)}#{truncationFooter};"
|
---|
459 | end
|
---|
460 |
|
---|
461 | def cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, condition)
|
---|
462 | $asm.putc "if (std::isnan(#{operands[0].clValue(:double)}) || std::isnan(#{operands[1].clValue(:double)})"
|
---|
463 | $asm.putc " || (#{operands[0].clValue(:double)} #{condition} #{operands[1].clValue(:double)}))"
|
---|
464 | $asm.putc " goto #{operands[2].cLabel};"
|
---|
465 | end
|
---|
466 |
|
---|
467 |
|
---|
468 | def cloopEmitCompareAndSet(operands, type, comparator)
|
---|
469 | # The result is a boolean. Hence, it doesn't need to be based on the type
|
---|
470 | # of the arguments being compared.
|
---|
471 | $asm.putc "#{operands[2].clLValue(type)} = (#{operands[0].clValue(type)} #{comparator} #{operands[1].clValue(type)});"
|
---|
472 | end
|
---|
473 |
|
---|
474 |
|
---|
475 | def cloopEmitCompareAndBranch(operands, type, comparator)
|
---|
476 | $asm.putc "if (#{operands[0].clValue(type)} #{comparator} #{operands[1].clValue(type)})"
|
---|
477 | $asm.putc " goto #{operands[2].cLabel};"
|
---|
478 | end
|
---|
479 |
|
---|
480 |
|
---|
481 | # conditionTest should contain a string that provides a comparator and a RHS
|
---|
482 | # value e.g. "< 0".
|
---|
483 | def cloopGenerateConditionExpression(operands, type, conditionTest)
|
---|
484 | op1 = operands[0].clValue(type)
|
---|
485 |
|
---|
486 | # The operands must consist of 2 or 3 values.
|
---|
487 | case operands.size
|
---|
488 | when 2 # Just test op1 against the conditionTest.
|
---|
489 | lhs = op1
|
---|
490 | when 3 # Mask op1 with op2 before testing against the conditionTest.
|
---|
491 | lhs = "(#{op1} & #{operands[1].clValue(type)})"
|
---|
492 | else
|
---|
493 | raise "Expected 2 or 3 operands but got #{operands.size} at #{codeOriginString}"
|
---|
494 | end
|
---|
495 |
|
---|
496 | "#{lhs} #{conditionTest}"
|
---|
497 | end
|
---|
498 |
|
---|
499 | # conditionTest should contain a string that provides a comparator and a RHS
|
---|
500 | # value e.g. "< 0".
|
---|
501 | def cloopEmitTestAndBranchIf(operands, type, conditionTest, branchTarget)
|
---|
502 | conditionExpr = cloopGenerateConditionExpression(operands, type, conditionTest)
|
---|
503 | $asm.putc "if (#{conditionExpr})"
|
---|
504 | $asm.putc " goto #{branchTarget};"
|
---|
505 | end
|
---|
506 |
|
---|
507 | def cloopEmitTestSet(operands, type, conditionTest)
|
---|
508 | # The result is a boolean condition. Hence, the result type is always an
|
---|
509 | # int. The passed in type is only used for the values being tested in
|
---|
510 | # the condition test.
|
---|
511 | conditionExpr = cloopGenerateConditionExpression(operands, type, conditionTest)
|
---|
512 | $asm.putc "#{operands[-1].clLValue} = (#{conditionExpr});"
|
---|
513 | end
|
---|
514 |
|
---|
515 | def cloopEmitOpAndBranch(operands, operator, type, conditionTest)
|
---|
516 | case type
|
---|
517 | when :intptr; tempType = "intptr_t"
|
---|
518 | when :int32; tempType = "int32_t"
|
---|
519 | when :int64; tempType = "int64_t"
|
---|
520 | else
|
---|
521 | raise "Unimplemented type"
|
---|
522 | end
|
---|
523 |
|
---|
524 | $asm.putc "{"
|
---|
525 | $asm.putc " #{tempType} temp = #{operands[1].clValue(type)} #{operator} #{operands[0].clValue(type)};"
|
---|
526 | $asm.putc " #{operands[1].clLValue(type)} = temp;"
|
---|
527 | $asm.putc " if (temp #{conditionTest})"
|
---|
528 | $asm.putc " goto #{operands[2].cLabel};"
|
---|
529 | $asm.putc "}"
|
---|
530 | end
|
---|
531 |
|
---|
532 | def cloopEmitOpAndBranchIfOverflow(operands, operator, type)
|
---|
533 | case type
|
---|
534 | when :int32
|
---|
535 | tempType = "int32_t"
|
---|
536 | truncationHeader = "(uint32_t)("
|
---|
537 | truncationFooter = ")"
|
---|
538 | else
|
---|
539 | raise "Unimplemented type"
|
---|
540 | end
|
---|
541 |
|
---|
542 | $asm.putc "{"
|
---|
543 |
|
---|
544 | # Emit the overflow test based on the operands and the type:
|
---|
545 | case operator
|
---|
546 | when "+"; operation = "add"
|
---|
547 | when "-"; operation = "sub"
|
---|
548 | when "*"; operation = "multiply"
|
---|
549 | else
|
---|
550 | raise "Unimplemented opeartor"
|
---|
551 | end
|
---|
552 |
|
---|
553 | $asm.putc " #{tempType} result;"
|
---|
554 | $asm.putc " bool success = WTF::ArithmeticOperations<#{tempType}, #{tempType}, #{tempType}>::#{operation}(#{operands[1].clValue(type)}, #{operands[0].clValue(type)}, result);"
|
---|
555 | $asm.putc " #{operands[1].clLValue(type)} = #{truncationHeader}result#{truncationFooter};"
|
---|
556 | $asm.putc " if (!success)"
|
---|
557 | $asm.putc " goto #{operands[2].cLabel};"
|
---|
558 | $asm.putc "}"
|
---|
559 | end
|
---|
560 |
|
---|
561 | # operands: callTarget, currentFrame, currentPC
|
---|
562 | def cloopEmitCallSlowPath(operands)
|
---|
563 | $asm.putc "{"
|
---|
564 | $asm.putc " cloopStack.setCurrentStackPointer(sp.vp());"
|
---|
565 | $asm.putc " SlowPathReturnType result = #{operands[0].cLabel}(#{operands[1].clDump}, #{operands[2].clDump});"
|
---|
566 | $asm.putc " decodeResult(result, t0, t1);"
|
---|
567 | $asm.putc "}"
|
---|
568 | end
|
---|
569 |
|
---|
570 | def cloopEmitCallSlowPathVoid(operands)
|
---|
571 | $asm.putc "cloopStack.setCurrentStackPointer(sp.vp());"
|
---|
572 | $asm.putc "#{operands[0].cLabel}(#{operands[1].clDump}, #{operands[2].clDump});"
|
---|
573 | end
|
---|
574 |
|
---|
575 | def cloopEmitCallSlowPath3(operands)
|
---|
576 | $asm.putc "{"
|
---|
577 | $asm.putc " cloopStack.setCurrentStackPointer(sp.vp());"
|
---|
578 | $asm.putc " SlowPathReturnType result = #{operands[0].cLabel}(#{operands[1].clDump}, #{operands[2].clDump}, #{operands[3].clDump});"
|
---|
579 | $asm.putc " decodeResult(result, t0, t1);"
|
---|
580 | $asm.putc "}"
|
---|
581 | end
|
---|
582 |
|
---|
583 | def cloopEmitCallSlowPath4(operands)
|
---|
584 | $asm.putc "{"
|
---|
585 | $asm.putc " cloopStack.setCurrentStackPointer(sp.vp());"
|
---|
586 | $asm.putc " SlowPathReturnType result = #{operands[0].cLabel}(#{operands[1].clDump}, #{operands[2].clDump}, #{operands[3].clDump}, #{operands[4].clDump});"
|
---|
587 | $asm.putc " decodeResult(result, t0, t1);"
|
---|
588 | $asm.putc "}"
|
---|
589 | end
|
---|
590 |
|
---|
591 | class Instruction
|
---|
592 | def lowerC_LOOP
|
---|
593 | case opcode
|
---|
594 | when "addi"
|
---|
595 | cloopEmitOperation(operands, :int32, "+")
|
---|
596 | when "addq"
|
---|
597 | cloopEmitOperation(operands, :int64, "+")
|
---|
598 | when "addp"
|
---|
599 | cloopEmitOperation(operands, :intptr, "+")
|
---|
600 |
|
---|
601 | when "andi"
|
---|
602 | cloopEmitOperation(operands, :int32, "&")
|
---|
603 | when "andq"
|
---|
604 | cloopEmitOperation(operands, :int64, "&")
|
---|
605 | when "andp"
|
---|
606 | cloopEmitOperation(operands, :intptr, "&")
|
---|
607 |
|
---|
608 | when "ori"
|
---|
609 | cloopEmitOperation(operands, :int32, "|")
|
---|
610 | when "orq"
|
---|
611 | cloopEmitOperation(operands, :int64, "|")
|
---|
612 | when "orp"
|
---|
613 | cloopEmitOperation(operands, :intptr, "|")
|
---|
614 | when "orh"
|
---|
615 | cloopEmitOperation(operands, :int16, "|")
|
---|
616 |
|
---|
617 | when "xori"
|
---|
618 | cloopEmitOperation(operands, :int32, "^")
|
---|
619 | when "xorq"
|
---|
620 | cloopEmitOperation(operands, :int64, "^")
|
---|
621 | when "xorp"
|
---|
622 | cloopEmitOperation(operands, :intptr, "^")
|
---|
623 |
|
---|
624 | when "lshifti"
|
---|
625 | cloopEmitShiftOperation(operands, :int32, "<<")
|
---|
626 | when "lshiftq"
|
---|
627 | cloopEmitShiftOperation(operands, :int64, "<<")
|
---|
628 | when "lshiftp"
|
---|
629 | cloopEmitShiftOperation(operands, :intptr, "<<")
|
---|
630 |
|
---|
631 | when "rshifti"
|
---|
632 | cloopEmitShiftOperation(operands, :int32, ">>")
|
---|
633 | when "rshiftq"
|
---|
634 | cloopEmitShiftOperation(operands, :int64, ">>")
|
---|
635 | when "rshiftp"
|
---|
636 | cloopEmitShiftOperation(operands, :intptr, ">>")
|
---|
637 |
|
---|
638 | when "urshifti"
|
---|
639 | cloopEmitShiftOperation(operands, :uint32, ">>")
|
---|
640 | when "urshiftq"
|
---|
641 | cloopEmitShiftOperation(operands, :uint64, ">>")
|
---|
642 | when "urshiftp"
|
---|
643 | cloopEmitShiftOperation(operands, :uintptr, ">>")
|
---|
644 |
|
---|
645 | when "muli"
|
---|
646 | cloopEmitOperation(operands, :int32, "*")
|
---|
647 | when "mulq"
|
---|
648 | cloopEmitOperation(operands, :int64, "*")
|
---|
649 | when "mulp"
|
---|
650 | cloopEmitOperation(operands, :intptr, "*")
|
---|
651 |
|
---|
652 | when "subi"
|
---|
653 | cloopEmitOperation(operands, :int32, "-")
|
---|
654 | when "subq"
|
---|
655 | cloopEmitOperation(operands, :int64, "-")
|
---|
656 | when "subp"
|
---|
657 | cloopEmitOperation(operands, :intptr, "-")
|
---|
658 |
|
---|
659 | when "negi"
|
---|
660 | cloopEmitUnaryOperation(operands, :int32, "-")
|
---|
661 | when "negq"
|
---|
662 | cloopEmitUnaryOperation(operands, :int64, "-")
|
---|
663 | when "negp"
|
---|
664 | cloopEmitUnaryOperation(operands, :intptr, "-")
|
---|
665 |
|
---|
666 | when "noti"
|
---|
667 | cloopEmitUnaryOperation(operands, :int32, "~")
|
---|
668 |
|
---|
669 | when "loadi"
|
---|
670 | $asm.putc "#{operands[1].clLValue(:uint32)} = #{operands[0].uint32MemRef};"
|
---|
671 | # There's no need to call clearHighWord() here because the above will
|
---|
672 | # automatically take care of 0 extension.
|
---|
673 | when "loadis"
|
---|
674 | $asm.putc "#{operands[1].clLValue(:int32)} = #{operands[0].int32MemRef};"
|
---|
675 | when "loadq"
|
---|
676 | $asm.putc "#{operands[1].clLValue(:int64)} = #{operands[0].int64MemRef};"
|
---|
677 | when "loadp"
|
---|
678 | $asm.putc "#{operands[1].clLValue} = #{operands[0].intptrMemRef};"
|
---|
679 | when "storei"
|
---|
680 | $asm.putc "#{operands[1].int32MemRef} = #{operands[0].clValue(:int32)};"
|
---|
681 | when "storeq"
|
---|
682 | $asm.putc "#{operands[1].int64MemRef} = #{operands[0].clValue(:int64)};"
|
---|
683 | when "storep"
|
---|
684 | $asm.putc "#{operands[1].intptrMemRef} = #{operands[0].clValue(:intptr)};"
|
---|
685 | when "loadb"
|
---|
686 | $asm.putc "#{operands[1].clLValue(:intptr)} = #{operands[0].uint8MemRef};"
|
---|
687 | when "loadbsi"
|
---|
688 | $asm.putc "#{operands[1].clLValue(:uint32)} = (uint32_t)((int32_t)#{operands[0].int8MemRef});"
|
---|
689 | when "loadbsq"
|
---|
690 | $asm.putc "#{operands[1].clLValue(:uint64)} = (int64_t)#{operands[0].int8MemRef};"
|
---|
691 | when "storeb"
|
---|
692 | $asm.putc "#{operands[1].uint8MemRef} = #{operands[0].clValue(:int8)};"
|
---|
693 | when "loadh"
|
---|
694 | $asm.putc "#{operands[1].clLValue(:intptr)} = #{operands[0].uint16MemRef};"
|
---|
695 | when "loadhsi"
|
---|
696 | $asm.putc "#{operands[1].clLValue(:uint32)} = (uint32_t)((int32_t)#{operands[0].int16MemRef});"
|
---|
697 | when "loadhsq"
|
---|
698 | $asm.putc "#{operands[1].clLValue(:uint64)} = (int64_t)#{operands[0].int16MemRef};"
|
---|
699 | when "storeh"
|
---|
700 | $asm.putc "*#{operands[1].uint16MemRef} = #{operands[0].clValue(:int16)};"
|
---|
701 | when "loadd"
|
---|
702 | $asm.putc "#{operands[1].clLValue(:double)} = #{operands[0].dblMemRef};"
|
---|
703 | when "stored"
|
---|
704 | $asm.putc "#{operands[1].dblMemRef} = #{operands[0].clValue(:double)};"
|
---|
705 |
|
---|
706 | when "addd"
|
---|
707 | cloopEmitOperation(operands, :double, "+")
|
---|
708 | when "divd"
|
---|
709 | cloopEmitOperation(operands, :double, "/")
|
---|
710 | when "subd"
|
---|
711 | cloopEmitOperation(operands, :double, "-")
|
---|
712 | when "muld"
|
---|
713 | cloopEmitOperation(operands, :double, "*")
|
---|
714 |
|
---|
715 | # Convert an int value to its double equivalent, and store it in a double register.
|
---|
716 | when "ci2ds"
|
---|
717 | $asm.putc "#{operands[1].clLValue(:double)} = (double)#{operands[0].clValue(:int32)}; // ci2ds"
|
---|
718 |
|
---|
719 | when "bdeq"
|
---|
720 | cloopEmitCompareAndBranch(operands, :double, "==")
|
---|
721 | when "bdneq"
|
---|
722 | cloopEmitCompareAndBranch(operands, :double, "!=")
|
---|
723 | when "bdgt"
|
---|
724 | cloopEmitCompareAndBranch(operands, :double, ">");
|
---|
725 | when "bdgteq"
|
---|
726 | cloopEmitCompareAndBranch(operands, :double, ">=");
|
---|
727 | when "bdlt"
|
---|
728 | cloopEmitCompareAndBranch(operands, :double, "<");
|
---|
729 | when "bdlteq"
|
---|
730 | cloopEmitCompareAndBranch(operands, :double, "<=");
|
---|
731 |
|
---|
732 | when "bdequn"
|
---|
733 | cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "==")
|
---|
734 | when "bdnequn"
|
---|
735 | cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "!=")
|
---|
736 | when "bdgtun"
|
---|
737 | cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, ">")
|
---|
738 | when "bdgtequn"
|
---|
739 | cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, ">=")
|
---|
740 | when "bdltun"
|
---|
741 | cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "<")
|
---|
742 | when "bdltequn"
|
---|
743 | cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "<=")
|
---|
744 |
|
---|
745 | when "td2i"
|
---|
746 | $asm.putc "#{operands[1].clLValue(:intptr)} = (uint32_t)(intptr_t)#{operands[0].clValue(:double)}; // td2i"
|
---|
747 |
|
---|
748 | when "bcd2i" # operands: srcDbl dstInt slowPath
|
---|
749 | $asm.putc "{ // bcd2i"
|
---|
750 | $asm.putc " double d = #{operands[0].clValue(:double)};"
|
---|
751 | $asm.putc " const int32_t asInt32 = int32_t(d);"
|
---|
752 | $asm.putc " if (asInt32 != d || (!asInt32 && std::signbit(d))) // true for -0.0"
|
---|
753 | $asm.putc " goto #{operands[2].cLabel};"
|
---|
754 | $asm.putc " #{operands[1].clLValue} = (uint32_t)asInt32;"
|
---|
755 | $asm.putc "}"
|
---|
756 |
|
---|
757 | when "move"
|
---|
758 | $asm.putc "#{operands[1].clLValue(:intptr)} = #{operands[0].clValue(:intptr)};"
|
---|
759 | when "sxi2q"
|
---|
760 | $asm.putc "#{operands[1].clLValue(:int64)} = #{operands[0].clValue(:int32)};"
|
---|
761 | when "zxi2q"
|
---|
762 | $asm.putc "#{operands[1].clLValue(:uint64)} = #{operands[0].clValue(:uint32)};"
|
---|
763 | when "sxb2i"
|
---|
764 | $asm.putc "#{operands[1].clLValue(:int32)} = #{operands[0].clValue(:int8)};"
|
---|
765 | when "sxh2i"
|
---|
766 | $asm.putc "#{operands[1].clLValue(:int32)} = #{operands[0].clValue(:int16)};"
|
---|
767 | when "sxb2q"
|
---|
768 | $asm.putc "#{operands[1].clLValue(:int64)} = #{operands[0].clValue(:int8)};"
|
---|
769 | when "sxh2q"
|
---|
770 | $asm.putc "#{operands[1].clLValue(:int64)} = #{operands[0].clValue(:int16)};"
|
---|
771 | when "nop"
|
---|
772 | $asm.putc "// nop"
|
---|
773 | when "bbeq"
|
---|
774 | cloopEmitCompareAndBranch(operands, :int8, "==")
|
---|
775 | when "bieq"
|
---|
776 | cloopEmitCompareAndBranch(operands, :int32, "==")
|
---|
777 | when "bqeq"
|
---|
778 | cloopEmitCompareAndBranch(operands, :int64, "==")
|
---|
779 | when "bpeq"
|
---|
780 | cloopEmitCompareAndBranch(operands, :intptr, "==")
|
---|
781 |
|
---|
782 | when "bbneq"
|
---|
783 | cloopEmitCompareAndBranch(operands, :int8, "!=")
|
---|
784 | when "bineq"
|
---|
785 | cloopEmitCompareAndBranch(operands, :int32, "!=")
|
---|
786 | when "bqneq"
|
---|
787 | cloopEmitCompareAndBranch(operands, :int64, "!=")
|
---|
788 | when "bpneq"
|
---|
789 | cloopEmitCompareAndBranch(operands, :intptr, "!=")
|
---|
790 |
|
---|
791 | when "bba"
|
---|
792 | cloopEmitCompareAndBranch(operands, :uint8, ">")
|
---|
793 | when "bia"
|
---|
794 | cloopEmitCompareAndBranch(operands, :uint32, ">")
|
---|
795 | when "bqa"
|
---|
796 | cloopEmitCompareAndBranch(operands, :uint64, ">")
|
---|
797 | when "bpa"
|
---|
798 | cloopEmitCompareAndBranch(operands, :uintptr, ">")
|
---|
799 |
|
---|
800 | when "bbaeq"
|
---|
801 | cloopEmitCompareAndBranch(operands, :uint8, ">=")
|
---|
802 | when "biaeq"
|
---|
803 | cloopEmitCompareAndBranch(operands, :uint32, ">=")
|
---|
804 | when "bqaeq"
|
---|
805 | cloopEmitCompareAndBranch(operands, :uint64, ">=")
|
---|
806 | when "bpaeq"
|
---|
807 | cloopEmitCompareAndBranch(operands, :uintptr, ">=")
|
---|
808 |
|
---|
809 | when "bbb"
|
---|
810 | cloopEmitCompareAndBranch(operands, :uint8, "<")
|
---|
811 | when "bib"
|
---|
812 | cloopEmitCompareAndBranch(operands, :uint32, "<")
|
---|
813 | when "bqb"
|
---|
814 | cloopEmitCompareAndBranch(operands, :uint64, "<")
|
---|
815 | when "bpb"
|
---|
816 | cloopEmitCompareAndBranch(operands, :uintptr, "<")
|
---|
817 |
|
---|
818 | when "bbbeq"
|
---|
819 | cloopEmitCompareAndBranch(operands, :uint8, "<=")
|
---|
820 | when "bibeq"
|
---|
821 | cloopEmitCompareAndBranch(operands, :uint32, "<=")
|
---|
822 | when "bqbeq"
|
---|
823 | cloopEmitCompareAndBranch(operands, :uint64, "<=")
|
---|
824 | when "bpbeq"
|
---|
825 | cloopEmitCompareAndBranch(operands, :uintptr, "<=")
|
---|
826 |
|
---|
827 | when "bbgt"
|
---|
828 | cloopEmitCompareAndBranch(operands, :int8, ">")
|
---|
829 | when "bigt"
|
---|
830 | cloopEmitCompareAndBranch(operands, :int32, ">")
|
---|
831 | when "bqgt"
|
---|
832 | cloopEmitCompareAndBranch(operands, :int64, ">")
|
---|
833 | when "bpgt"
|
---|
834 | cloopEmitCompareAndBranch(operands, :intptr, ">")
|
---|
835 |
|
---|
836 | when "bbgteq"
|
---|
837 | cloopEmitCompareAndBranch(operands, :int8, ">=")
|
---|
838 | when "bigteq"
|
---|
839 | cloopEmitCompareAndBranch(operands, :int32, ">=")
|
---|
840 | when "bqgteq"
|
---|
841 | cloopEmitCompareAndBranch(operands, :int64, ">=")
|
---|
842 | when "bpgteq"
|
---|
843 | cloopEmitCompareAndBranch(operands, :intptr, ">=")
|
---|
844 |
|
---|
845 | when "bblt"
|
---|
846 | cloopEmitCompareAndBranch(operands, :int8, "<")
|
---|
847 | when "bilt"
|
---|
848 | cloopEmitCompareAndBranch(operands, :int32, "<")
|
---|
849 | when "bqlt"
|
---|
850 | cloopEmitCompareAndBranch(operands, :int64, "<")
|
---|
851 | when "bplt"
|
---|
852 | cloopEmitCompareAndBranch(operands, :intptr, "<")
|
---|
853 |
|
---|
854 | when "bblteq"
|
---|
855 | cloopEmitCompareAndBranch(operands, :int8, "<=")
|
---|
856 | when "bilteq"
|
---|
857 | cloopEmitCompareAndBranch(operands, :int32, "<=")
|
---|
858 | when "bqlteq"
|
---|
859 | cloopEmitCompareAndBranch(operands, :int64, "<=")
|
---|
860 | when "bplteq"
|
---|
861 | cloopEmitCompareAndBranch(operands, :intptr, "<=")
|
---|
862 |
|
---|
863 | when "btbz"
|
---|
864 | cloopEmitTestAndBranchIf(operands, :int8, "== 0", operands[-1].cLabel)
|
---|
865 | when "btiz"
|
---|
866 | cloopEmitTestAndBranchIf(operands, :int32, "== 0", operands[-1].cLabel)
|
---|
867 | when "btqz"
|
---|
868 | cloopEmitTestAndBranchIf(operands, :int64, "== 0", operands[-1].cLabel)
|
---|
869 | when "btpz"
|
---|
870 | cloopEmitTestAndBranchIf(operands, :intptr, "== 0", operands[-1].cLabel)
|
---|
871 |
|
---|
872 | when "btbnz"
|
---|
873 | cloopEmitTestAndBranchIf(operands, :int8, "!= 0", operands[-1].cLabel)
|
---|
874 | when "btinz"
|
---|
875 | cloopEmitTestAndBranchIf(operands, :int32, "!= 0", operands[-1].cLabel)
|
---|
876 | when "btqnz"
|
---|
877 | cloopEmitTestAndBranchIf(operands, :int64, "!= 0", operands[-1].cLabel)
|
---|
878 | when "btpnz"
|
---|
879 | cloopEmitTestAndBranchIf(operands, :intptr, "!= 0", operands[-1].cLabel)
|
---|
880 |
|
---|
881 | when "btbs"
|
---|
882 | cloopEmitTestAndBranchIf(operands, :int8, "< 0", operands[-1].cLabel)
|
---|
883 | when "btis"
|
---|
884 | cloopEmitTestAndBranchIf(operands, :int32, "< 0", operands[-1].cLabel)
|
---|
885 | when "btqs"
|
---|
886 | cloopEmitTestAndBranchIf(operands, :int64, "< 0", operands[-1].cLabel)
|
---|
887 | when "btps"
|
---|
888 | cloopEmitTestAndBranchIf(operands, :intptr, "< 0", operands[-1].cLabel)
|
---|
889 |
|
---|
890 | # For jmp, we do not want to assume that we have COMPUTED_GOTO support.
|
---|
891 | # Fortunately, the only times we should ever encounter indirect jmps is
|
---|
892 | # when the jmp target is a CLoop opcode (by design).
|
---|
893 | #
|
---|
894 | # Hence, we check if the jmp target is a known label reference. If so,
|
---|
895 | # we can emit a goto directly. If it is not a known target, then we set
|
---|
896 | # the target in the opcode, and dispatch to it via whatever dispatch
|
---|
897 | # mechanism is in used.
|
---|
898 | when "jmp"
|
---|
899 | if operands[0].is_a? LocalLabelReference or operands[0].is_a? LabelReference
|
---|
900 | # Handles jumps local or global labels.
|
---|
901 | $asm.putc "goto #{operands[0].cLabel};"
|
---|
902 | else
|
---|
903 | # Handles jumps to some computed target.
|
---|
904 | # NOTE: must be an opcode handler or a llint glue helper.
|
---|
905 | $asm.putc "opcode = #{operands[0].clValue(:opcode)};"
|
---|
906 | $asm.putc "DISPATCH_OPCODE();"
|
---|
907 | end
|
---|
908 |
|
---|
909 | when "call"
|
---|
910 | $asm.putc "CRASH(); // generic call instruction not supported by design!"
|
---|
911 | when "break"
|
---|
912 | $asm.putc "CRASH(); // break instruction not implemented."
|
---|
913 | when "ret"
|
---|
914 | $asm.putc "opcode = lr.opcode();"
|
---|
915 | $asm.putc "DISPATCH_OPCODE();"
|
---|
916 |
|
---|
917 | when "cbeq"
|
---|
918 | cloopEmitCompareAndSet(operands, :uint8, "==")
|
---|
919 | when "cieq"
|
---|
920 | cloopEmitCompareAndSet(operands, :uint32, "==")
|
---|
921 | when "cqeq"
|
---|
922 | cloopEmitCompareAndSet(operands, :uint64, "==")
|
---|
923 | when "cpeq"
|
---|
924 | cloopEmitCompareAndSet(operands, :uintptr, "==")
|
---|
925 |
|
---|
926 | when "cbneq"
|
---|
927 | cloopEmitCompareAndSet(operands, :uint8, "!=")
|
---|
928 | when "cineq"
|
---|
929 | cloopEmitCompareAndSet(operands, :uint32, "!=")
|
---|
930 | when "cqneq"
|
---|
931 | cloopEmitCompareAndSet(operands, :uint64, "!=")
|
---|
932 | when "cpneq"
|
---|
933 | cloopEmitCompareAndSet(operands, :uintptr, "!=")
|
---|
934 |
|
---|
935 | when "cba"
|
---|
936 | cloopEmitCompareAndSet(operands, :uint8, ">")
|
---|
937 | when "cia"
|
---|
938 | cloopEmitCompareAndSet(operands, :uint32, ">")
|
---|
939 | when "cqa"
|
---|
940 | cloopEmitCompareAndSet(operands, :uint64, ">")
|
---|
941 | when "cpa"
|
---|
942 | cloopEmitCompareAndSet(operands, :uintptr, ">")
|
---|
943 |
|
---|
944 | when "cbaeq"
|
---|
945 | cloopEmitCompareAndSet(operands, :uint8, ">=")
|
---|
946 | when "ciaeq"
|
---|
947 | cloopEmitCompareAndSet(operands, :uint32, ">=")
|
---|
948 | when "cqaeq"
|
---|
949 | cloopEmitCompareAndSet(operands, :uint64, ">=")
|
---|
950 | when "cpaeq"
|
---|
951 | cloopEmitCompareAndSet(operands, :uintptr, ">=")
|
---|
952 |
|
---|
953 | when "cbb"
|
---|
954 | cloopEmitCompareAndSet(operands, :uint8, "<")
|
---|
955 | when "cib"
|
---|
956 | cloopEmitCompareAndSet(operands, :uint32, "<")
|
---|
957 | when "cqb"
|
---|
958 | cloopEmitCompareAndSet(operands, :uint64, "<")
|
---|
959 | when "cpb"
|
---|
960 | cloopEmitCompareAndSet(operands, :uintptr, "<")
|
---|
961 |
|
---|
962 | when "cbbeq"
|
---|
963 | cloopEmitCompareAndSet(operands, :uint8, "<=")
|
---|
964 | when "cibeq"
|
---|
965 | cloopEmitCompareAndSet(operands, :uint32, "<=")
|
---|
966 | when "cqbeq"
|
---|
967 | cloopEmitCompareAndSet(operands, :uint64, "<=")
|
---|
968 | when "cpbeq"
|
---|
969 | cloopEmitCompareAndSet(operands, :uintptr, "<=")
|
---|
970 |
|
---|
971 | when "cbgt"
|
---|
972 | cloopEmitCompareAndSet(operands, :int8, ">")
|
---|
973 | when "cigt"
|
---|
974 | cloopEmitCompareAndSet(operands, :int32, ">")
|
---|
975 | when "cqgt"
|
---|
976 | cloopEmitCompareAndSet(operands, :int64, ">")
|
---|
977 | when "cpgt"
|
---|
978 | cloopEmitCompareAndSet(operands, :intptr, ">")
|
---|
979 | when "cdgt"
|
---|
980 | cloopEmitCompareAndSet(operands, :double, ">")
|
---|
981 |
|
---|
982 | when "cbgteq"
|
---|
983 | cloopEmitCompareAndSet(operands, :int8, ">=")
|
---|
984 | when "cigteq"
|
---|
985 | cloopEmitCompareAndSet(operands, :int32, ">=")
|
---|
986 | when "cqgteq"
|
---|
987 | cloopEmitCompareAndSet(operands, :int64, ">=")
|
---|
988 | when "cpgteq"
|
---|
989 | cloopEmitCompareAndSet(operands, :intptr, ">=")
|
---|
990 | when "cdgteq"
|
---|
991 | cloopEmitCompareAndSet(operands, :double, ">=")
|
---|
992 |
|
---|
993 | when "cblt"
|
---|
994 | cloopEmitCompareAndSet(operands, :int8, "<")
|
---|
995 | when "cilt"
|
---|
996 | cloopEmitCompareAndSet(operands, :int32, "<")
|
---|
997 | when "cqlt"
|
---|
998 | cloopEmitCompareAndSet(operands, :int64, "<")
|
---|
999 | when "cplt"
|
---|
1000 | cloopEmitCompareAndSet(operands, :intptr, "<")
|
---|
1001 | when "cdlt"
|
---|
1002 | cloopEmitCompareAndSet(operands, :double, "<")
|
---|
1003 |
|
---|
1004 | when "cblteq"
|
---|
1005 | cloopEmitCompareAndSet(operands, :int8, "<=")
|
---|
1006 | when "cilteq"
|
---|
1007 | cloopEmitCompareAndSet(operands, :int32, "<=")
|
---|
1008 | when "cqlteq"
|
---|
1009 | cloopEmitCompareAndSet(operands, :int64, "<=")
|
---|
1010 | when "cplteq"
|
---|
1011 | cloopEmitCompareAndSet(operands, :intptr, "<=")
|
---|
1012 | when "cdlteq"
|
---|
1013 | cloopEmitCompareAndSet(operands, :double, "<=")
|
---|
1014 |
|
---|
1015 | when "tbs"
|
---|
1016 | cloopEmitTestSet(operands, :int8, "< 0")
|
---|
1017 | when "tis"
|
---|
1018 | cloopEmitTestSet(operands, :int32, "< 0")
|
---|
1019 | when "tqs"
|
---|
1020 | cloopEmitTestSet(operands, :int64, "< 0")
|
---|
1021 | when "tps"
|
---|
1022 | cloopEmitTestSet(operands, :intptr, "< 0")
|
---|
1023 |
|
---|
1024 | when "tbz"
|
---|
1025 | cloopEmitTestSet(operands, :int8, "== 0")
|
---|
1026 | when "tiz"
|
---|
1027 | cloopEmitTestSet(operands, :int32, "== 0")
|
---|
1028 | when "tqz"
|
---|
1029 | cloopEmitTestSet(operands, :int64, "== 0")
|
---|
1030 | when "tpz"
|
---|
1031 | cloopEmitTestSet(operands, :intptr, "== 0")
|
---|
1032 |
|
---|
1033 | when "tbnz"
|
---|
1034 | cloopEmitTestSet(operands, :int8, "!= 0")
|
---|
1035 | when "tinz"
|
---|
1036 | cloopEmitTestSet(operands, :int32, "!= 0")
|
---|
1037 | when "tqnz"
|
---|
1038 | cloopEmitTestSet(operands, :int64, "!= 0")
|
---|
1039 | when "tpnz"
|
---|
1040 | cloopEmitTestSet(operands, :intptr, "!= 0")
|
---|
1041 |
|
---|
1042 | # 64-bit instruction: cdqi (based on X64)
|
---|
1043 | # Sign extends the lower 32 bits of t0, but put the sign extension into
|
---|
1044 | # the lower 32 bits of t1. Leave the upper 32 bits of t0 and t1 unchanged.
|
---|
1045 | when "cdqi"
|
---|
1046 | $asm.putc "{ // cdqi"
|
---|
1047 | $asm.putc " int64_t temp = t0.i32(); // sign extend the low 32bit"
|
---|
1048 | $asm.putc " t0 = (uint32_t)temp; // low word"
|
---|
1049 | $asm.putc " t1 = (uint32_t)(temp >> 32); // high word"
|
---|
1050 | $asm.putc "}"
|
---|
1051 |
|
---|
1052 | # 64-bit instruction: idivi op1 (based on X64)
|
---|
1053 | # Divide a 64-bit integer numerator by the specified denominator.
|
---|
1054 | # The numerator is specified in t0 and t1 as follows:
|
---|
1055 | # 1. low 32 bits of the numerator is in the low 32 bits of t0.
|
---|
1056 | # 2. high 32 bits of the numerator is in the low 32 bits of t1.
|
---|
1057 | #
|
---|
1058 | # The resultant quotient is a signed 32-bit int, and is to be stored
|
---|
1059 | # in the lower 32 bits of t0.
|
---|
1060 | # The resultant remainder is a signed 32-bit int, and is to be stored
|
---|
1061 | # in the lower 32 bits of t1.
|
---|
1062 | when "idivi"
|
---|
1063 | # Divide t1,t0 (EDX,EAX) by the specified arg, and store the remainder in t1,
|
---|
1064 | # and quotient in t0:
|
---|
1065 | $asm.putc "{ // idivi"
|
---|
1066 | $asm.putc " int64_t dividend = (int64_t(t1.u32()) << 32) | t0.u32();"
|
---|
1067 | $asm.putc " int64_t divisor = #{operands[0].clValue(:intptr)};"
|
---|
1068 | $asm.putc " t1 = (uint32_t)(dividend % divisor); // remainder"
|
---|
1069 | $asm.putc " t0 = (uint32_t)(dividend / divisor); // quotient"
|
---|
1070 | $asm.putc "}"
|
---|
1071 |
|
---|
1072 | # 32-bit instruction: fii2d int32LoOp int32HiOp dblOp (based on ARMv7)
|
---|
1073 | # Decode 2 32-bit ints (low and high) into a 64-bit double.
|
---|
1074 | when "fii2d"
|
---|
1075 | $asm.putc "#{operands[2].clLValue(:double)} = ints2Double(#{operands[0].clValue(:uint32)}, #{operands[1].clValue(:uint32)}); // fii2d"
|
---|
1076 |
|
---|
1077 | # 32-bit instruction: f2dii dblOp int32LoOp int32HiOp (based on ARMv7)
|
---|
1078 | # Encode a 64-bit double into 2 32-bit ints (low and high).
|
---|
1079 | when "fd2ii"
|
---|
1080 | $asm.putc "double2Ints(#{operands[0].clValue(:double)}, #{operands[1].clDump}, #{operands[2].clDump}); // fd2ii"
|
---|
1081 |
|
---|
1082 | # 64-bit instruction: fq2d int64Op dblOp (based on X64)
|
---|
1083 | # Copy a bit-encoded double in a 64-bit int register to a double register.
|
---|
1084 | when "fq2d"
|
---|
1085 | $asm.putc "#{operands[1].clLValue(:double)} = #{operands[0].clValue(:bitsAsDouble)}; // fq2d"
|
---|
1086 |
|
---|
1087 | # 64-bit instruction: fd2q dblOp int64Op (based on X64 instruction set)
|
---|
1088 | # Copy a double as a bit-encoded double into a 64-bit int register.
|
---|
1089 | when "fd2q"
|
---|
1090 | $asm.putc "#{operands[1].clLValue(:int64)} = #{operands[0].clValue(:bitsAsInt64)}; // fd2q"
|
---|
1091 |
|
---|
1092 | when "leai"
|
---|
1093 | operands[0].cloopEmitLea(operands[1], :int32)
|
---|
1094 | when "leap"
|
---|
1095 | operands[0].cloopEmitLea(operands[1], :intptr)
|
---|
1096 |
|
---|
1097 | when "baddio"
|
---|
1098 | cloopEmitOpAndBranchIfOverflow(operands, "+", :int32)
|
---|
1099 | when "bsubio"
|
---|
1100 | cloopEmitOpAndBranchIfOverflow(operands, "-", :int32)
|
---|
1101 | when "bmulio"
|
---|
1102 | cloopEmitOpAndBranchIfOverflow(operands, "*", :int32)
|
---|
1103 |
|
---|
1104 | when "baddis"
|
---|
1105 | cloopEmitOpAndBranch(operands, "+", :int32, "< 0")
|
---|
1106 | when "baddiz"
|
---|
1107 | cloopEmitOpAndBranch(operands, "+", :int32, "== 0")
|
---|
1108 | when "baddinz"
|
---|
1109 | cloopEmitOpAndBranch(operands, "+", :int32, "!= 0")
|
---|
1110 |
|
---|
1111 | when "baddqs"
|
---|
1112 | cloopEmitOpAndBranch(operands, "+", :int64, "< 0")
|
---|
1113 | when "baddqz"
|
---|
1114 | cloopEmitOpAndBranch(operands, "+", :int64, "== 0")
|
---|
1115 | when "baddqnz"
|
---|
1116 | cloopEmitOpAndBranch(operands, "+", :int64, "!= 0")
|
---|
1117 |
|
---|
1118 | when "baddps"
|
---|
1119 | cloopEmitOpAndBranch(operands, "+", :intptr, "< 0")
|
---|
1120 | when "baddpz"
|
---|
1121 | cloopEmitOpAndBranch(operands, "+", :intptr, "== 0")
|
---|
1122 | when "baddpnz"
|
---|
1123 | cloopEmitOpAndBranch(operands, "+", :intptr, "!= 0")
|
---|
1124 |
|
---|
1125 | when "bsubis"
|
---|
1126 | cloopEmitOpAndBranch(operands, "-", :int32, "< 0")
|
---|
1127 | when "bsubiz"
|
---|
1128 | cloopEmitOpAndBranch(operands, "-", :int32, "== 0")
|
---|
1129 | when "bsubinz"
|
---|
1130 | cloopEmitOpAndBranch(operands, "-", :int32, "!= 0")
|
---|
1131 |
|
---|
1132 | when "borris"
|
---|
1133 | cloopEmitOpAndBranch(operands, "|", :int32, "< 0")
|
---|
1134 | when "borriz"
|
---|
1135 | cloopEmitOpAndBranch(operands, "|", :int32, "== 0")
|
---|
1136 | when "borrinz"
|
---|
1137 | cloopEmitOpAndBranch(operands, "|", :int32, "!= 0")
|
---|
1138 |
|
---|
1139 | when "memfence"
|
---|
1140 |
|
---|
1141 | when "push"
|
---|
1142 | operands.each {
|
---|
1143 | | op |
|
---|
1144 | $asm.putc "PUSH(#{op.clDump});"
|
---|
1145 | }
|
---|
1146 | when "pop"
|
---|
1147 | operands.each {
|
---|
1148 | | op |
|
---|
1149 | $asm.putc "POP(#{op.clDump});"
|
---|
1150 | }
|
---|
1151 |
|
---|
1152 |
|
---|
1153 | # A convenience and compact call to crash because we don't want to use
|
---|
1154 | # the generic llint crash mechanism which relies on the availability
|
---|
1155 | # of the call instruction (which cannot be implemented in a generic
|
---|
1156 | # way, and can be abused if we made it just work for this special case).
|
---|
1157 | # Using a special cloopCrash instruction is cleaner.
|
---|
1158 | when "cloopCrash"
|
---|
1159 | $asm.putc "CRASH();"
|
---|
1160 |
|
---|
1161 | # We can't rely on the llint JS call mechanism which actually makes
|
---|
1162 | # use of the call instruction. Instead, we just implement JS calls
|
---|
1163 | # as an opcode dispatch.
|
---|
1164 | when "cloopCallJSFunction"
|
---|
1165 | uid = $asm.newUID
|
---|
1166 | $asm.putc "lr = getOpcode(llint_cloop_did_return_from_js_#{uid});"
|
---|
1167 | $asm.putc "opcode = #{operands[0].clValue(:opcode)};"
|
---|
1168 | $asm.putc "DISPATCH_OPCODE();"
|
---|
1169 | $asm.putsLabel("llint_cloop_did_return_from_js_#{uid}", false)
|
---|
1170 |
|
---|
1171 | # We can't do generic function calls with an arbitrary set of args, but
|
---|
1172 | # fortunately we don't have to here. All native function calls always
|
---|
1173 | # have a fixed prototype of 2 args: the passed JSGlobalObject* and CallFrame*.
|
---|
1174 | when "cloopCallNative"
|
---|
1175 | $asm.putc "cloopStack.setCurrentStackPointer(sp.vp());"
|
---|
1176 | $asm.putc "nativeFunc = #{operands[0].clValue(:nativeFunc)};"
|
---|
1177 | $asm.putc "functionReturnValue = JSValue::decode(nativeFunc(jsCast<JSGlobalObject*>(t0.cell()), t1.callFrame()));"
|
---|
1178 | $asm.putc "#if USE(JSVALUE32_64)"
|
---|
1179 | $asm.putc " t1 = functionReturnValue.tag();"
|
---|
1180 | $asm.putc " t0 = functionReturnValue.payload();"
|
---|
1181 | $asm.putc "#else // USE_JSVALUE64)"
|
---|
1182 | $asm.putc " t0 = JSValue::encode(functionReturnValue);"
|
---|
1183 | $asm.putc "#endif // USE_JSVALUE64)"
|
---|
1184 |
|
---|
1185 | # We can't do generic function calls with an arbitrary set of args, but
|
---|
1186 | # fortunately we don't have to here. All slow path function calls always
|
---|
1187 | # have a fixed prototype too. See cloopEmitCallSlowPath() for details.
|
---|
1188 | when "cloopCallSlowPath"
|
---|
1189 | cloopEmitCallSlowPath(operands)
|
---|
1190 |
|
---|
1191 | when "cloopCallSlowPathVoid"
|
---|
1192 | cloopEmitCallSlowPathVoid(operands)
|
---|
1193 |
|
---|
1194 | when "cloopCallSlowPath3"
|
---|
1195 | cloopEmitCallSlowPath3(operands)
|
---|
1196 |
|
---|
1197 | when "cloopCallSlowPath4"
|
---|
1198 | cloopEmitCallSlowPath4(operands)
|
---|
1199 |
|
---|
1200 | # For debugging only. This is used to insert instrumentation into the
|
---|
1201 | # generated LLIntAssembly.h during llint development only. Do not use
|
---|
1202 | # for production code.
|
---|
1203 | when "cloopDo"
|
---|
1204 | $asm.putc "#{annotation}"
|
---|
1205 |
|
---|
1206 | else
|
---|
1207 | lowerDefault
|
---|
1208 | end
|
---|
1209 | end
|
---|
1210 |
|
---|
1211 | def lowerC_LOOP_WIN
|
---|
1212 | lowerC_LOOP
|
---|
1213 | end
|
---|
1214 |
|
---|
1215 | def recordMetaDataC_LOOP
|
---|
1216 | $asm.codeOrigin codeOriginString if $enableCodeOriginComments
|
---|
1217 | $asm.annotation annotation if $enableInstrAnnotations && (opcode != "cloopDo")
|
---|
1218 | end
|
---|
1219 | end
|
---|