-
Notifications
You must be signed in to change notification settings - Fork 65
/
CogOutOfLineLiteralsARMv8Compiler.class.st
670 lines (608 loc) · 23.8 KB
/
CogOutOfLineLiteralsARMv8Compiler.class.st
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
Class {
#name : #CogOutOfLineLiteralsARMv8Compiler,
#superclass : #CogARMv8Compiler,
#category : #'VMMaker-JIT'
}
{ #category : #'accessing class hierarchy' }
CogOutOfLineLiteralsARMv8Compiler class >> literalsManagerClass [
^OutOfLineLiteralsManager
]
{ #category : #accessing }
CogOutOfLineLiteralsARMv8Compiler >> cmpC32RTempByteSize [
^8
]
{ #category : #'generate machine code - concretize' }
CogOutOfLineLiteralsARMv8Compiler >> concretizeLiteral [
"Generate an out-of-line literal. Copy the value and any annotation from the stand-in in the literals manager."
| literalAsInstruction literal twoComplement |
literalAsInstruction := cogit cCoerceSimple: (operands at: 0) to: #'AbstractInstruction *'.
literal := (self isAnInstruction: literalAsInstruction)
ifTrue: [literalAsInstruction address]
ifFalse: [self cCode: [literalAsInstruction asUnsignedInteger]
inSmalltalk: [literalAsInstruction]].
self assert: (dependent notNil and: [dependent opcode = Literal]).
dependent annotation ifNotNil:
[self assert: annotation isNil.
annotation := dependent annotation].
dependent address ifNotNil: [self assert: dependent address = address].
dependent address: address.
twoComplement := literal < 0
ifTrue: [ 16rFFFFFFFFFFFFFFFF - literal abs + 1 ]
ifFalse: [ literal ].
self machineCodeAt: 0 put: (twoComplement bitAnd: 16rFFFFFFFF).
self machineCodeAt: 4 put: (twoComplement >> 32).
machineCodeSize := 8
]
{ #category : #'generate machine code - concretize' }
CogOutOfLineLiteralsARMv8Compiler >> concretizeMoveC32R [
"Will get inlined into concretizeAt: switch."
<var: #quickConstant type: #sqInt>
<returnTypeC: #void>
<inline: true>
| quickConstant |
quickConstant := operands at: 0.
quickConstant < 0 ifTrue: [
self shiftable16bitImmediate: quickConstant negated - 1
ifTrue: [ :shift :value |
self machineCodeAt: 0 put: (self
movSize: 1
destinationRegister: (operands at: 1)
negatedImm: value
shift: shift).
^ machineCodeSize := 4 ]
ifFalse: [
self loadCwInto: (operands at: 1).
^ machineCodeSize := 4 ]].
self shiftable16bitImmediate: quickConstant
ifTrue: [ :shift :value |
self machineCodeAt: 0 put: (self
movSize: 1
destinationRegister: (operands at: 1)
imm: value
shift: shift).
^ machineCodeSize := 4 ]
ifFalse: [
self loadCwInto: (operands at: 1).
^ machineCodeSize := 4 ]
]
{ #category : #'generate machine code - concretize' }
CogOutOfLineLiteralsARMv8Compiler >> concretizeMoveMbrR [
"Will get inlined into concretizeAt: switch."
<var: #offset type: #sqInt>
<inline: true>
| srcReg offset destReg |
offset := operands at: 0.
srcReg := operands at: 1.
destReg := operands at: 2.
self
is9BitValue: offset
ifTrue: [ :immediate9bitTwoComplementValue |
self
machineCodeAt: 0
put: (self movSize: 1 destinationRegister: destReg imm: 0 shift: 0).
self
machineCodeAt: 4
put: (self ldurbSize: 1 baseRegister: srcReg signedOffset: immediate9bitTwoComplementValue destinationRegister: destReg).
^ machineCodeSize := 8 ]
ifFalse: [
self loadRelativeLiteralIn: ConcreteIPReg.
self
machineCodeAt: 4
put: (self ldrbSourceRegister: srcReg offsetRegister: ConcreteIPReg destinationRegister: destReg).
^ machineCodeSize := 8 ].
^ 0 "to keep Slang happy"
]
{ #category : #'as yet unclassified' }
CogOutOfLineLiteralsARMv8Compiler >> concretizeMovePatcheableC32R [
self loadRelativeLiteralIn: (operands at: 1).
^ machineCodeSize := 4
]
{ #category : #'generate machine code - concretize' }
CogOutOfLineLiteralsARMv8Compiler >> concretizeMoveRM32r [
"Will get inlined into concretizeAt: switch."
<var: #offset type: #sqInt>
<inline: true>
| srcReg offset baseReg |
srcReg := operands at: 0.
offset := operands at: 1.
baseReg := operands at: 2.
self
is9BitValue: offset
ifTrue: [ :value |
self
machineCodeAt: 0
put:(self
sturSize: 0 "32 bits"
baseRegister: baseReg
signedOffset: offset
destinationRegister: srcReg).
^ machineCodeSize := 4 ]
ifFalse: [
self
shiftable16bitImmediate: offset
ifTrue: [ :shift :value |
self assert: shift = 0.
self
machineCodeAt: 0
put: (self movSize: 1 destinationRegister: ConcreteIPReg imm: value shift: shift).
self
machineCodeAt: 4
put: (self strSize: 0 "32 bits" baseRegister: baseReg offsetRegister: ConcreteIPReg extension: 2r011 "LSL" shift: 0 "no LSL" storedRegister: srcReg).
^ machineCodeSize := 8 ]
ifFalse: [
self loadRelativeLiteralIn: ConcreteIPReg.
self
machineCodeAt: 4
put: (self strSize: 0 "32 bits" baseRegister: baseReg offsetRegister: ConcreteIPReg extension: 2r011 "LSL" shift: 0 "no LSL" storedRegister: srcReg).
^ machineCodeSize := 8 ]].
^ 0 "to keep Slang happy"
]
{ #category : #'generate machine code - concretize' }
CogOutOfLineLiteralsARMv8Compiler >> concretizeMoveRMwr [
"Will get inlined into concretizeAt: switch."
<var: #offset type: #sqInt>
<inline: true>
| srcReg offset baseReg |
srcReg := operands at: 0.
offset := operands at: 1.
baseReg := operands at: 2.
self
is9BitValue: offset
ifTrue: [ :value |
self
machineCodeAt: 0
put:(self
sturSize: 1
baseRegister: baseReg
signedOffset: offset
destinationRegister: srcReg).
^ machineCodeSize := 4 ]
ifFalse: [
self
shiftable16bitImmediate: offset
ifTrue: [ :shift :value |
self assert: shift = 0.
self
machineCodeAt: 0
put: (self movSize: 1 destinationRegister: ConcreteIPReg imm: value shift: shift).
self
machineCodeAt: 4
put: (self strSize: 1 baseRegister: baseReg offsetRegister: ConcreteIPReg extension: 2r011 "LSL" shift: 0 "no LSL" storedRegister: srcReg).
^ machineCodeSize := 8 ]
ifFalse: [
self loadRelativeLiteralIn: ConcreteIPReg.
self
machineCodeAt: 4
put: (self strSize: 1 baseRegister: baseReg offsetRegister: ConcreteIPReg extension: 2r011 "LSL" shift: 0 "no LSL" storedRegister: srcReg).
^ machineCodeSize := 8 ]].
^ 0 "to keep Slang happy"
]
{ #category : #accessing }
CogOutOfLineLiteralsARMv8Compiler >> getDefaultCogCodeSize [
"Return the default number of bytes to allocate for native code at startup.
The actual value can be set via vmParameterAt: and/or a preference in the ini file."
<inline: true>
^1024 * 1280
]
{ #category : #'inline cacheing' }
CogOutOfLineLiteralsARMv8Compiler >> inlineCacheTagAt: callSiteReturnAddress [
<inline: true>
^objectMemory unsignedLongAt: (self pcRelativeAddressAt: (callSiteReturnAddress - 8) asUnsignedInteger)
]
{ #category : #testing }
CogOutOfLineLiteralsARMv8Compiler >> isPCDependent [
"Answer if the receiver is a pc-dependent instruction. With out-of-line literals any instruction
that refers to a literal depends on the address of the literal, so add them in addition to the jumps."
^self isJump
or: [opcode = AlignmentNops
or: [opcode ~= Literal and: [dependent notNil and: [dependent opcode = Literal]]]]
]
{ #category : #'generate machine code - support' }
CogOutOfLineLiteralsARMv8Compiler >> isSharable [
"Hack: To know if a literal should be unique (not shared) mark the second operand."
<inline: true>
self assert: opcode = Literal.
^operands at: 1
]
{ #category : #'inline cacheing' }
CogOutOfLineLiteralsARMv8Compiler >> literalBeforeFollowingAddress: followingAddress [
"Return the literal referenced by the instruction immediately preceding followingAddress."
^objectMemory unsignedLong64At: (self pcRelativeAddressAt:
((self instructionIsLDR: (self instructionBeforeAddress: followingAddress))
ifTrue: [self instructionAddressBefore: followingAddress]
ifFalse: [ self instructionAddressBefore: followingAddress - 4]))
]
{ #category : #accessing }
CogOutOfLineLiteralsARMv8Compiler >> literalLoadInstructionBytes [
"Answer the size of a literal load instruction (which does not include the size of the literal).
With out-of-line literals this is always a single LDR instruction that refers to the literal."
<inline: true>
^4
]
{ #category : #'generate machine code - support' }
CogOutOfLineLiteralsARMv8Compiler >> literalOpcodeIndex [
"Hack: To know how far away a literal is from its referencing instruction we store
its opcodeIndex, or -1, if as yet unassigned, in the second operand of the literal."
<inline: true>
self assert: opcode = Literal.
^(operands at: 2) asInteger
]
{ #category : #accessing }
CogOutOfLineLiteralsARMv8Compiler >> loadLiteralByteSize [
"Answer the byte size of a MoveCwR opcode's corresponding machine code. On ARM this is a single instruction pc-relative register load - unless we have made a mistake and not turned on the out of line literals manager"
^4
]
{ #category : #literals }
CogOutOfLineLiteralsARMv8Compiler >> loadRelativeLiteralIn: destReg [
<inline: true>
self assert: dependent opcode = Literal.
self assert: (cogit addressIsInCurrentCompilation: dependent address).
self assert: (dependent address - (address + 8)) abs < (1 << 12).
self machineCodeAt: 0 put: (self
ldrSize: 1
programCounterRelativeOffset: dependent address - address
destinationRegister: destReg) "64 bits"
]
{ #category : #'generate machine code - support' }
CogOutOfLineLiteralsARMv8Compiler >> mapEntryAddress [
"Typically map entries apply to the end of an instruction, for two reasons:
a) to cope with literals embedded in variable-length instructions, since, e.g.
on x86, the literal typically comes at the end of the instruction.
b) in-line cache detection is based on return addresses, which are typically
to the instruction following a call.
But with out-of-line literals it is more convenient to annotate the literal itself."
<inline: true>
^opcode = Literal
ifTrue: [address]
ifFalse: [address + machineCodeSize]
]
{ #category : #'generate machine code - support' }
CogOutOfLineLiteralsARMv8Compiler >> moveCw: constant intoR: destReg [
"Emit a load of aWord into destReg. Answer the number of bytes of machine code generated.
Literals are stored out-of-line; emit a LDR with the relevant offset."
<var: 'constant' type: #usqInt>
<inline: true>
self loadRelativeLiteralIn: destReg.
^machineCodeSize := 4
]
{ #category : #'compile abstract instructions' }
CogOutOfLineLiteralsARMv8Compiler >> outOfLineLiteralOpcodeLimit [
"The maximum offset in a LDR is (1<<12)-1, or (1<<10)-1 instructions.
Be conservative. The issue is that one abstract instruction can emit
multiple hardware instructions so we assume a 2 to 1 worst case of
hardware instructions to abstract opcodes.."
^1 << (12 "12-bit offset field"
- 3 "8 bytes per literal, so 2^3?"
- 1 "2 hardware instructions to 1 abstract opcode") - 1
]
{ #category : #'inline cacheing' }
CogOutOfLineLiteralsARMv8Compiler >> pcRelativeAddressAt: instrAddress [
"Extract the address of the LDR (literal) instruction at address
c.f. C6.2.132
"
| inst offset |
inst := objectMemory uint32AtPointer: instrAddress.
offset := inst >> 5 bitAnd: 16r7ffff.
^instrAddress + (((offset allMask: (1 << 18))
ifTrue: [offset negated]
ifFalse: [offset]) * 4 "because LDR includes the imm / 4")
]
{ #category : #'inline cacheing' }
CogOutOfLineLiteralsARMv8Compiler >> relocateMethodReferenceBeforeAddress: pc by: delta [
"If possible we generate the method address using pc-relative addressing.
If so we don't need to relocate it in code. So check if pc-relative code was
generated, and if not, adjust a load literal. There are two cases, a push
or a register load. If a push, then there is a register load, but in the instruction
before."
| pcPrecedingLoad reference litAddr |
pcPrecedingLoad := (self instructionIsPush: (self instructionBeforeAddress: pc))
ifTrue: [pc - 4]
ifFalse: [pc].
"If the load is not done via pc-relative addressing we have to relocate."
(self isPCRelativeValueLoad: (self instructionBeforeAddress: pcPrecedingLoad)) ifFalse:
[litAddr := self pcRelativeAddressAt: pcPrecedingLoad.
reference := objectMemory long64At: litAddr.
objectMemory long64At: litAddr put: reference + delta - 4]
]
{ #category : #'inline cacheing' }
CogOutOfLineLiteralsARMv8Compiler >> rewriteFullTransferAt: callSiteReturnAddress target: callTargetAddress expectedInstruction: expectedInstruction [
"Rewrite a CallFull or JumpFull instruction to transfer to a different target.
This variant is used to rewrite cached primitive calls where we load the target address into ip
and use the 'bx ip' or 'blx ip' instruction for the actual jump or call.
Answer the extent
of the code change which is used to compute the range of the icache to flush."
<var: #callSiteReturnAddress type: #usqInt>
<var: #callTargetAddress type: #usqInt>
self assert: (self instructionBeforeAddress: callSiteReturnAddress) = expectedInstruction.
objectMemory longAt: (self pcRelativeAddressAt: callSiteReturnAddress - 8) put: callTargetAddress.
"self cCode: ''
inSmalltalk: [cogit disassembleFrom: callSiteReturnAddress - 8 to: (self pcRelativeAddressAt: callSiteReturnAddress - 8)]."
^0
]
{ #category : #'inline cacheing' }
CogOutOfLineLiteralsARMv8Compiler >> rewriteInlineCacheAt: callSiteReturnAddress tag: cacheTag target: callTargetAddress [
"Rewrite an inline cache to call a different target for a new tag. This variant is used
to link unlinked sends in ceSend:to:numArgs: et al. Answer the extent of the code
change which is used to compute the range of the icache to flush."
<var: #callSiteReturnAddress type: #usqInt>
<var: #callTargetAddress type: #usqInt>
| call callDistance |
callTargetAddress >= cogit minCallAddress ifFalse:
[self error: 'linking callsite to invalid address'].
callDistance := (callTargetAddress - (callSiteReturnAddress - 4 "return offset")).
self assert: (self isInImmediateJumpRange: callDistance). "we don't support long call updates here"
call := self bl: callDistance.
objectMemory
uint32AtPointer: (self instructionAddressBefore: callSiteReturnAddress ) put: call;
unsignedLong64At: (self pcRelativeAddressAt: callSiteReturnAddress - 8) put: cacheTag signedIntToLong64.
self assert: (self inlineCacheTagAt: callSiteReturnAddress) = cacheTag signedIntToLong64.
"self cCode: ''
inSmalltalk: [cogit disassembleFrom: callSiteReturnAddress - 8 to: (self pcRelativeAddressAt: callSiteReturnAddress - 8)]."
^4
]
{ #category : #'inline cacheing' }
CogOutOfLineLiteralsARMv8Compiler >> rewriteInlineCacheTag: cacheTag at: callSiteReturnAddress [
"Rewrite an inline cache with a new tag. This variant is used
by the garbage collector."
<inline: true>
objectMemory longAt: (self pcRelativeAddressAt: callSiteReturnAddress - 8) put: cacheTag
]
{ #category : #'generate machine code - support' }
CogOutOfLineLiteralsARMv8Compiler >> setLiteralOpcodeIndex: index [
"Hack: To know how far away a literal is from its referencing instruction we store
its opcodeIndex, or -1, if as yet unassigned, in the second operand of the literal."
<inline: true>
self assert: opcode = Literal.
operands at: 2 put: index
]
{ #category : #'generate machine code - support' }
CogOutOfLineLiteralsARMv8Compiler >> sizePCDependentInstructionAt: eventualAbsoluteAddress [
"Size a jump and set its address. The target may be another instruction
or an absolute address. On entry the address inst var holds our virtual
address. On exit address is set to eventualAbsoluteAddress, which is
where this instruction will be output. The span of a jump to a following
instruction is therefore between that instruction's address and this
instruction's address ((which are both still their virtual addresses), but the
span of a jump to a preceding instruction or to an absolute address is
between that instruction's address (which by now is its eventual absolute
address) or absolute address and eventualAbsoluteAddress.
ARM is simple; the 26-bit call/jump range means no short jumps. This
routine only has to determine the targets of jumps, not determine sizes.
This version also deals with out-of-line literals. If this is the real literal,
update the stand-in in literalsManager with the address (because instructions
referring to the literal are referring to the stand-in). If this is annotated with
IsObjectReference transfer the annotation to the stand-in, whence it will be
transferred to the real literal, simplifying update of literals."
opcode = AlignmentNops ifTrue:
[| alignment |
address := eventualAbsoluteAddress.
alignment := operands at: 0.
^machineCodeSize := (eventualAbsoluteAddress + (alignment - 1) bitAnd: alignment negated)
- eventualAbsoluteAddress].
self assert: (self isJump or: [opcode = Call or: [opcode = CallFull
or: [dependent notNil and: [dependent opcode = Literal]]]]).
self isJump ifTrue: [self resolveJumpTarget].
address := eventualAbsoluteAddress.
(dependent notNil and: [dependent opcode = Literal]) ifTrue:
[opcode = Literal ifTrue:
[dependent address: address].
annotation = cogit getIsObjectReference ifTrue:
[dependent annotation: annotation.
annotation := nil]].
^machineCodeSize := maxSize
]
{ #category : #'inline cacheing' }
CogOutOfLineLiteralsARMv8Compiler >> storeLiteral: literal beforeFollowingAddress: followingAddress [
"Rewrite the literal in the instruction immediately preceding followingAddress."
objectMemory
unsignedLongAt: (self pcRelativeAddressAt:
((self instructionIsLDR: (self instructionBeforeAddress: followingAddress))
ifTrue: [self instructionAddressBefore: followingAddress]
ifFalse: [self instructionAddressBefore: followingAddress - 4]))
put: literal
]
{ #category : #'generate machine code - support' }
CogOutOfLineLiteralsARMv8Compiler >> updateLabel: labelInstruction [
opcode ~= Literal ifTrue:
[super updateLabel: labelInstruction]
]
{ #category : #testing }
CogOutOfLineLiteralsARMv8Compiler >> usesOutOfLineLiteral [
"Answer if the receiver uses an out-of-line literal. Needs only
to work for the opcodes created with gen:literal:operand: et al."
<var: #offset type: 'sqInt'>
| offset |
opcode
caseOf: {
([ CallFull ] -> [ ^ true ]).
([ JumpFull ] -> [ ^ true ]).
"Arithmetic"
([ AddCqR ] -> [
| constant |
constant := operands at: 0.
^ (constant abs bitAnd: 16rfff) ~= constant abs ]).
([ AndCqR ] -> [
^ self
encodeLogicalImmediate: (operands at: 0)
registerSize: 64
ifPossible: [ :value | false ]
ifNotPossible: [ true ] ]).
([ AndCqRR ] -> [
^ self
encodeLogicalImmediate: (operands at: 0)
registerSize: 64
ifPossible: [ :value | false ]
ifNotPossible: [ true ] ]).
([ CmpCqR ] -> [
((operands at: 0) abs bitAnd: 16rFFF) = (operands at: 0) abs
ifTrue: [ ^ false ].
((operands at: 0) abs << 12 >> 12 bitAnd: 16rFFF)
= (operands at: 0) abs ifTrue: [ ^ false ].
^ true ]).
([ CmpC32R ] -> [
^ self
rotateable8bitSignedImmediate: (operands at: 0)
ifTrue: [ :r :i :n | false ]
ifFalse: [ true ] ]).
([ OrCqR ] -> [
^ self
encodeLogicalImmediate: (operands at: 0)
registerSize: 64
ifPossible: [ :v | false ]
ifNotPossible: [ true ] ]).
([ SubCqR ] -> [
| constant |
constant := operands at: 0.
^ (constant bitAnd: 16rfff) ~= constant ]).
([ TstCqR ] -> [
^ self
encodeLogicalImmediate: (operands at: 0)
registerSize: 64
ifPossible: [ :v | false ]
ifNotPossible: [ true ] ]).
([ XorCqR ] -> [
^ self
rotateable8bitBitwiseImmediate: (operands at: 0)
ifTrue: [ :r :i :n | false ]
ifFalse: [ true ] ]).
([ AddCwR ] -> [ ^ true ]).
([ AndCwR ] -> [ ^ true ]).
([ CmpCwR ] -> [ ^ true ]).
([ OrCwR ] -> [ ^ true ]).
([ SubCwR ] -> [ ^ true ]).
([ XorCwR ] -> [ ^ true ]).
([ LoadEffectiveAddressMwrR ] -> [
^ self
rotateable8bitImmediate: (operands at: 0)
ifTrue: [ :r :i | false ]
ifFalse: [ true ] ]).
"Data Movement"
([ MoveCqR ] -> [
| quickConstant |
quickConstant := operands at: 0.
^ (quickConstant < 0 and: [
(self isShiftable16bitImmediate: quickConstant negated - 1)
not ]) or: [
(self isShiftable16bitImmediate: quickConstant) not ] ]).
([ MoveC32R ] -> [
| quickConstant |
quickConstant := operands at: 0.
^ (quickConstant < 0 and: [
(self isShiftable16bitImmediate: quickConstant negated - 1)
not ]) or: [
(self isShiftable16bitImmediate: quickConstant) not ] ]).
([ MoveCwR ]
-> [ ^ (self inCurrentCompilation: (operands at: 0)) not ]).
([ MoveAwR ] -> [
^ (self isAddressRelativeToVarBase: (operands at: 0))
ifTrue: [ false ]
ifFalse: [ true ] ]).
([ MoveRAw ] -> [
^ (self isAddressRelativeToVarBase: (operands at: 1))
ifTrue: [ false ]
ifFalse: [ true ] ]).
([ MoveAbR ] -> [
^ (self isAddressRelativeToVarBase: (operands at: 0))
ifTrue: [ false ]
ifFalse: [ true ] ]).
([ MoveRAb ] -> [
^ (self isAddressRelativeToVarBase: (operands at: 1))
ifTrue: [ false ]
ifFalse: [ true ] ]).
([ MoveRM32r ] -> [
self
is9BitValue: (operands at: 1)
ifTrue: [ :value | ^ false ]
ifFalse: [
self
shiftable16bitImmediate: (operands at: 1)
ifTrue: [ :value :shift | ^ false ]
ifFalse: [ ^ true ] ] ]).
([ MoveRMwr ] -> [
self
is9BitValue: (operands at: 1)
ifTrue: [ :value | ^ false ]
ifFalse: [
self
shiftable16bitImmediate: (operands at: 1)
ifTrue: [ :value :shift | ^ false ]
ifFalse: [ ^ true ] ] ]).
([ MoveRsM32r ] -> [
^ self
is12BitValue: (operands at: 1)
ifTrue: [ :s :v | false ]
ifFalse: [ true ] ]).
([ MoveRdM64r ] -> [
^ self
is12BitValue: (operands at: 1)
ifTrue: [ :s :v | false ]
ifFalse: [ true ] ]).
([ MoveMbrR ] -> [
^ self
is9BitValue: (operands at: 0)
ifTrue: [ :v | false ]
ifFalse: [ true ] ]).
([ MoveRMbr ] -> [
^ self
is12BitValue: (operands at: 1)
ifTrue: [ :s :v | false ]
ifFalse: [ true ] ]).
([ MoveRM8r ] -> [
^ self
is12BitValue: (operands at: 1)
ifTrue: [ :s :v | false ]
ifFalse: [ true ] ]).
([ MoveM16rR ] -> [
^ self
rotateable8bitImmediate: (operands at: 0)
ifTrue: [ :r :i | false ]
ifFalse: [ true ] ]).
([ MoveRM16r ] -> [
^ self
is12BitValue: (operands at: 1)
ifTrue: [ :s :v | false ]
ifFalse: [ true ] ]).
([ MoveM32rRs ] -> [
^ self
is12BitValue: (operands at: 0)
ifTrue: [ :s :v | false ]
ifFalse: [ true ] ]).
([ MoveM64rRd ] -> [
^ self
is12BitValue: (operands at: 0)
ifTrue: [ :s :v | false ]
ifFalse: [ true ] ]).
([ MoveM32rR ] -> [
offset := operands at: 0.
(offset >= 0 and: [ (offset bitAnd: 16rFFF) = offset ])
ifTrue: [ ^ false ]
ifFalse: [
self
is9BitValue: offset
ifTrue: [ :v | ^ false ]
ifFalse: [ ^ true ] ] ]).
([ MoveMwrR ] -> [
offset := operands at: 0.
(offset >= 0 and: [ (offset bitAnd: 16rFFF) = offset ])
ifTrue: [ ^ false ]
ifFalse: [
self
is9BitValue: offset
ifTrue: [ :v | ^ false ]
ifFalse: [ ^ true ] ] ]).
([ PushCw ]
-> [ ^ (self inCurrentCompilation: (operands at: 0)) not ]).
([ PushCq ] -> [
^ self
shiftable16bitImmediate: (operands at: 0)
ifTrue: [ :r :i | false ]
ifFalse: [ true ] ]).
([ PrefetchAw ] -> [
^ (self isAddressRelativeToVarBase: (operands at: 0))
ifTrue: [ false ]
ifFalse: [ true ] ]).
"Patcheable instruction. Moves a literal. Uses out of line literal."
([ MovePatcheableC32R ] -> [ ^ true ]) }
otherwise: [ self error: 'We should not be here!!!' ].
^ false "to keep C compiler quiet"
]