-
Notifications
You must be signed in to change notification settings - Fork 64
/
CogInLineLiteralsX64Compiler.class.st
290 lines (266 loc) · 11.2 KB
/
CogInLineLiteralsX64Compiler.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
Class {
#name : #CogInLineLiteralsX64Compiler,
#superclass : #CogX64Compiler,
#category : #'VMMaker-JIT'
}
{ #category : #'class initialization' }
CogInLineLiteralsX64Compiler class >> initializeAbstractRegistersSysV [
"Assign the abstract registers with the identities/indices of the relevant concrete registers."
super initializeAbstractRegistersSysV.
RISCTempReg := R8
]
{ #category : #'class initialization' }
CogInLineLiteralsX64Compiler class >> initializeAbstractRegistersWin64 [
"Assign the abstract registers with the identities/indices of the relevant concrete registers."
super initializeAbstractRegistersWin64.
RISCTempReg := R11
]
{ #category : #testing }
CogInLineLiteralsX64Compiler class >> isRISCTempRegister: reg [
"For tests to filter-out bogus values left in the RISCTempRegister, if any."
^reg = RISCTempReg
]
{ #category : #'generate machine code' }
CogInLineLiteralsX64Compiler >> computeSizeOfArithCqR [
"With CqR we assume constants are 32-bits or less."
<inline: true>
(self isQuick: (operands at: 0)) ifTrue:
[^4].
(self is32BitSignedImmediate: (operands at: 0)) ifTrue:
[^(operands at: 1) = RAX ifTrue: [6] ifFalse: [7]].
^10 "movabsq" + 3 "r op r"
]
{ #category : #'generate machine code' }
CogInLineLiteralsX64Compiler >> computeSizeOfArithCwR [
<inline: true>
^10 "MoveCwR" + 3 "ArithRR"
]
{ #category : #'generate machine code' }
CogInLineLiteralsX64Compiler >> concretizeArithCwR: x64opcode [
| value reg reverse |
value := operands at: 0.
reg := operands at: 1.
reverse := x64opcode = 16r85 or: [x64opcode = 16r39]. "Tst & Cmp; backwards"
machineCode
at: 0 put: (self rexR: RISCTempReg x: 0 b: RISCTempReg);
at: 1 put: 16rB8 + (RISCTempReg bitAnd: 7);
at: 2 put: (value bitAnd: 16rFF);
at: 3 put: (value >> 8 bitAnd: 16rFF);
at: 4 put: (value >> 16 bitAnd: 16rFF);
at: 5 put: (value >> 24 bitAnd: 16rFF);
at: 6 put: (value >> 32 bitAnd: 16rFF);
at: 7 put: (value >> 40 bitAnd: 16rFF);
at: 8 put: (value >> 48 bitAnd: 16rFF);
at: 9 put: (value >> 56 bitAnd: 16rFF);
at: 10 put: (reverse
ifTrue: [self rexR: RISCTempReg x: 0 b: reg]
ifFalse: [self rexR: reg x: 0 b: RISCTempReg]);
at: 11 put: x64opcode;
at: 12 put: (reverse
ifTrue: [self mod: ModReg RM: reg RO: RISCTempReg]
ifFalse: [self mod: ModReg RM: RISCTempReg RO: reg]).
self assert: (machineCode at: 12) > 16r90. "See literalBeforeFollowingAddress:"
^machineCodeSize := 13
]
{ #category : #'generate machine code' }
CogInLineLiteralsX64Compiler >> concretizeMoveCwR [
"Will get inlined into concretizeAt: switch."
<inline: true>
| value reg offset |
value := operands at: 0.
reg := operands at: 1.
(self isAnInstruction: (cogit cCoerceSimple: value to: #'AbstractInstruction *')) ifTrue:
[value := (cogit cCoerceSimple: value to: #'AbstractInstruction *') address].
(cogit addressIsInCurrentCompilation: value) ifTrue:
[offset := value - (address + 7).
machineCode
at: 0 put: (self rexR: reg x: 0 b: 0);
at: 1 put: 16r8D; "LoadEffectiveAddress"
at: 2 put: (self mod: ModRegInd RM: 5 RO: reg);
at: 3 put: (offset bitAnd: 16rFF);
at: 4 put: (offset >> 8 bitAnd: 16rFF);
at: 5 put: (offset >> 16 bitAnd: 16rFF);
at: 6 put: (offset >> 24 bitAnd: 16rFF).
^machineCodeSize := 7].
machineCode
at: 0 put: (self rexR: 0 x: 0 b: reg);
at: 1 put: 16rB8 + (reg bitAnd: 7);
at: 2 put: (value bitAnd: 16rFF);
at: 3 put: (value >> 8 bitAnd: 16rFF);
at: 4 put: (value >> 16 bitAnd: 16rFF);
at: 5 put: (value >> 24 bitAnd: 16rFF);
at: 6 put: (value >> 32 bitAnd: 16rFF);
at: 7 put: (value >> 40 bitAnd: 16rFF);
at: 8 put: (value >> 48 bitAnd: 16rFF);
at: 9 put: (value >> 56 bitAnd: 16rFF).
"Add a nop to disambiguate between MoveCwR/PushCw and ArithCwR, which ends with a (self mod: ModReg RM: 0 RO: 0)"
machineCode at: 10 put: 16r90.
^machineCodeSize := 11
]
{ #category : #'as yet unclassified' }
CogInLineLiteralsX64Compiler >> concretizeMovePatcheableC32R [
^ self concretizeMoveC32R
]
{ #category : #'generate machine code' }
CogInLineLiteralsX64Compiler >> concretizePushCw [
"Will get inlined into concretizeAt: switch."
<inline: true>
| value offset |
value := operands at: 0.
(self isAnInstruction: (cogit cCoerceSimple: value to: #'AbstractInstruction *')) ifTrue:
[value := (cogit cCoerceSimple: value to: #'AbstractInstruction *') address].
(cogit addressIsInCurrentCompilation: value) ifTrue:
[offset := value - (address + 7).
machineCode
at: 0 put: (self rexR: RISCTempReg x: 0 b: 0);
at: 1 put: 16r8D; "LoadEffectiveAddress"
at: 2 put: (self mod: ModRegInd RM: 5 RO: RISCTempReg);
at: 3 put: (offset bitAnd: 16rFF);
at: 4 put: (offset >> 8 bitAnd: 16rFF);
at: 5 put: (offset >> 16 bitAnd: 16rFF);
at: 6 put: (offset >> 24 bitAnd: 16rFF);
at: 7 put: 16r41;
at: 8 put: 16r48 + RISCTempReg.
^machineCodeSize := 9].
machineCode
at: 0 put: (self rexR: RISCTempReg x: 0 b: RISCTempReg);
at: 1 put: 16rB8 + (RISCTempReg bitAnd: 7);
at: 2 put: (value bitAnd: 16rFF);
at: 3 put: (value >> 8 bitAnd: 16rFF);
at: 4 put: (value >> 16 bitAnd: 16rFF);
at: 5 put: (value >> 24 bitAnd: 16rFF);
at: 6 put: (value >> 32 bitAnd: 16rFF);
at: 7 put: (value >> 40 bitAnd: 16rFF);
at: 8 put: (value >> 48 bitAnd: 16rFF);
at: 9 put: (value >> 56 bitAnd: 16rFF);
at: 10 put: 16r41;
at: 11 put: 16r48 + RISCTempReg. "The 48 will disambiguate between MoveCwR, PushCw and ArithCwR, which ends with a (self mod: ModReg RM: 0 RO: 0)"
self assert: (machineCode at: 11) < 16r90. "see literalBeforeFollowingAddress:"
^machineCodeSize := 12
]
{ #category : #accessing }
CogInLineLiteralsX64Compiler >> getDefaultCogCodeSize [
"Answer 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 * 1400
]
{ #category : #'inline cacheing' }
CogInLineLiteralsX64Compiler >> inlineCacheTagAt: callSiteReturnAddress [
"Answer the inline cache tag for the return address of a send."
^self literal32BeforeFollowingAddress: callSiteReturnAddress - 5
]
{ #category : #testing }
CogInLineLiteralsX64Compiler >> isPCDependent [
"Answer if the receiver is a pc-dependent instruction."
^self isJump or: [opcode = AlignmentNops]
]
{ #category : #'inline cacheing' }
CogInLineLiteralsX64Compiler >> literal32BeforeFollowingAddress: followingAddress [
"Answer the 32-bit literal embedded in the instruction immediately preceding followingAddress."
^cogit
cCoerceSimple: (self unalignedLong32At: followingAddress - 4)
to: #'unsigned int'
]
{ #category : #'inline cacheing' }
CogInLineLiteralsX64Compiler >> literalBeforeFollowingAddress: followingAddress [
"Answer the literal embedded in the instruction immediately preceding followingAddress.
This is used in the MoveCwR, PushCw and ArithCwR cases; these are distinguished by a
nop following the literal load in MoveCwR, a 16r48 + reg ending the PushCw sequence, and
a (self mod: ModReg RM: rX RO: rY) ending the ArithCwR sequence, which is at least 16rC0."
| lastByte base |
lastByte := objectMemory byteAt: followingAddress - 1.
base := followingAddress - (lastByte = 16r90
ifTrue: [9] "MoveCwR"
ifFalse:
[lastByte < 16r90
ifTrue: [10] "PushCw"
ifFalse: [11]]). "ArithCwR"
^objectMemory unalignedLongAt: base
"(Symbol allSymbols select: [:s| '*Cw:R:' match: s]), {#PushCw:} collect: [:s| {s. (self systemNavigation allCallsOn: s localToPackage: #VMMaker) size}]"
]
{ #category : #accessing }
CogInLineLiteralsX64Compiler >> loadLiteralByteSize [
<inline: true>
^self moveCwRByteSize
]
{ #category : #accessing }
CogInLineLiteralsX64Compiler >> moveCwRByteSize [
"With in-line literals we use an 11 byte sequence for loading a 64-bit immediate,
which is one more than strictly necessary. We plant a nop at the end of the
sequence to allow us to distinguish between this and the
(self mod: ModReg RM: rX RO: rY) at the end of an ArithCwR sequence."
<inline: true>
^11
]
{ #category : #accessing }
CogInLineLiteralsX64Compiler >> pushCwByteSize [
"With in-line literals we use a 12 byte sequence for loading a 64-bit immediate, which
is one more than strictly necessary. The sequence ends with a 16r50 + reg opcode
(PushR) to allow us to distinguish between this and the (self mod: ModReg RM: rX RO: rY)
at the end of an ArithCwR sequence."
<inline: true>
^12
]
{ #category : #'generate machine code' }
CogInLineLiteralsX64Compiler >> 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."
| target maximumSpan abstractInstruction |
<var: #abstractInstruction type: #'AbstractInstruction *'>
opcode = AlignmentNops ifTrue:
[| alignment |
address := eventualAbsoluteAddress.
alignment := operands at: 0.
^machineCodeSize := (eventualAbsoluteAddress + (alignment - 1) bitAnd: alignment negated)
- eventualAbsoluteAddress].
self assert: self isJump.
target := operands at: 0.
abstractInstruction := cogit cCoerceSimple: target to: #'AbstractInstruction *'.
(self isAnInstruction: abstractInstruction)
ifTrue:
[maximumSpan := abstractInstruction address
- (((cogit abstractInstruction: self follows: abstractInstruction)
ifTrue: [eventualAbsoluteAddress]
ifFalse: [address]) + 2)]
ifFalse:
[maximumSpan := target - (eventualAbsoluteAddress + 2)].
address := eventualAbsoluteAddress.
opcode >= FirstShortJump
ifTrue:
[machineCodeSize := (self isQuick: maximumSpan)
ifTrue: [2]
ifFalse: [opcode = Jump
ifTrue: [5]
ifFalse: [6]]]
ifFalse:
[machineCodeSize := opcode caseOf:
{ [JumpLong] -> [5].
[JumpFull] -> [12].
[JumpLongZero] -> [6].
[JumpLongNonZero] -> [6] }].
^machineCodeSize "Slang can't inline the switch into the ifTrue:ifFalse: correctly"
]
{ #category : #'inline cacheing' }
CogInLineLiteralsX64Compiler >> storeLiteral: literal beforeFollowingAddress: followingAddress [
"Rewrite the literal in the instruction immediately preceding followingAddress.
This is used in the MoveCwR, PushCw and CmpCwR cases; these are distinguished by a
nop following the literal load in MoveCwR, a 16r50 + reg ending the PushCw sequence, and
a (self mod: ModReg RM: rX RO: rY) ending the CmpCwR sequence, which is at least 16rC0."
| lastByte base |
lastByte := objectMemory byteAt: followingAddress - 1.
base := followingAddress - (lastByte <= 16r90
ifTrue:
[lastByte = 16r90
ifTrue: [9] "MoveCwR"
ifFalse: [10]] "PushCw"
ifFalse: [11]). "ArithCwR"
objectMemory unalignedLongAt: base put: literal
]