rubycc 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +61 -0
- data/README.md +26 -14
- data/data/verified_gems.json +85 -63
- data/exe/rubycc-ar +11 -3
- data/include/libc/sys/cdefs.h +12 -0
- data/lib/rubycc/backend/aarch64.rb +705 -117
- data/lib/rubycc/backend/slot_residency.rb +169 -0
- data/lib/rubycc/backend/x86_64.rb +924 -137
- data/lib/rubycc/command_line.rb +339 -0
- data/lib/rubycc/compile_error.rb +6 -3
- data/lib/rubycc/compiler.rb +17 -2
- data/lib/rubycc/diagnostics.rb +105 -0
- data/lib/rubycc/doctor/gemfile.rb +12 -3
- data/lib/rubycc/doctor/verified_gems.rb +5 -1
- data/lib/rubycc/driver.rb +66 -10
- data/lib/rubycc/front/ast.rb +18 -7
- data/lib/rubycc/front/constant_evaluator.rb +12 -0
- data/lib/rubycc/front/lexeme_reader.rb +3 -1
- data/lib/rubycc/front/parser.rb +51 -18
- data/lib/rubycc/ir/analysis.rb +82 -0
- data/lib/rubycc/ir/call_convention.rb +74 -7
- data/lib/rubycc/ir/generator.rb +319 -9
- data/lib/rubycc/ir/ir.rb +39 -1
- data/lib/rubycc/ir/promotion.rb +255 -0
- data/lib/rubycc/ir/simplify.rb +570 -0
- data/lib/rubycc/link/library_resolver.rb +17 -5
- data/lib/rubycc/link/partial_linker.rb +8 -1
- data/lib/rubycc/link/shared_linker.rb +2 -2
- data/lib/rubycc/mkmf_shim.rb +178 -12
- data/lib/rubycc/objfile/ar_archive.rb +13 -2
- data/lib/rubycc/objfile/elf_reader.rb +13 -2
- data/lib/rubycc/pkgconf/parser.rb +4 -0
- data/lib/rubycc/pkgconf/resolver.rb +3 -1
- data/lib/rubycc/pkgconf/system_path_filter.rb +8 -2
- data/lib/rubycc/preprocess/preprocessor.rb +161 -37
- data/lib/rubycc/preprocess/scanner.rb +69 -14
- data/lib/rubycc/preprocess/token_converter.rb +11 -1
- data/lib/rubycc/rmake/cli.rb +32 -4
- data/lib/rubycc/rmake/executor.rb +157 -226
- data/lib/rubycc/rmake/makefile.rb +35 -13
- data/lib/rubycc/rmake/parser.rb +8 -2
- data/lib/rubycc/rmake/rmake.rb +1 -0
- data/lib/rubycc/rmake/tool_command.rb +69 -0
- data/lib/rubycc/shell.rb +510 -0
- data/lib/rubycc/type.rb +23 -7
- data/lib/rubycc/version.rb +1 -1
- data/lib/rubycc.rb +12 -0
- data/lib/rubygems_plugin.rb +31 -3
- metadata +14 -3
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "../ir/ir"
|
|
4
|
+
require_relative "../ir/analysis"
|
|
5
|
+
require_relative "../ir/promotion"
|
|
6
|
+
require_relative "../ir/simplify"
|
|
7
|
+
require_relative "slot_residency"
|
|
4
8
|
|
|
5
9
|
module Rubycc
|
|
6
10
|
module Backend
|
|
7
11
|
# x86_64 code generator using a spill-everything strategy: every virtual
|
|
8
12
|
# register lives in its own 8-byte stack slot at [rbp - 8*(n+1)], and each
|
|
9
13
|
# IR instruction loads its operands into eax/ecx, computes, and stores the
|
|
10
|
-
# result back.
|
|
14
|
+
# result back. Two kinds of value are exempt: a transient, which stays in
|
|
15
|
+
# the register its producer left it in (IR::Simplify#transient_vregs), and a
|
|
16
|
+
# promoted one, which owns a callee-saved register for the whole function
|
|
17
|
+
# and so has no slot at all (IR::Promotion, #promotion_assignment).
|
|
18
|
+
#
|
|
19
|
+
# Arithmetic on a 4-byte-or-narrower type stays 32-bit (using
|
|
11
20
|
# eax/ecx), whose natural wrap-around reproduces C's semantics for free;
|
|
12
21
|
# `long`/`unsigned long`/pointer arithmetic is 64-bit (a REX.W prefix,
|
|
13
22
|
# selected by an IR op's size == 8). Slots are always read and written 64
|
|
@@ -47,6 +56,13 @@ module Rubycc
|
|
|
47
56
|
# argument registers into a 176-byte register-save area so __builtin_va_arg
|
|
48
57
|
# can reach the variable part.
|
|
49
58
|
class X86_64
|
|
59
|
+
# Every slot access goes through #load_reg / #store_reg, which use this to
|
|
60
|
+
# skip a reload of a value the previous instruction has just left in a
|
|
61
|
+
# register. See slot_residency.rb for why "nothing has been emitted since"
|
|
62
|
+
# is a sufficient safety condition, and #emit_instruction's :label case
|
|
63
|
+
# for the one state change it cannot see.
|
|
64
|
+
include SlotResidency
|
|
65
|
+
|
|
50
66
|
# Result of compiling one function: `bytes` is the machine code (an
|
|
51
67
|
# ASCII-8BIT String), `symbols` is an array of
|
|
52
68
|
# { name:, offset:, size: } describing the emitted function symbols, and
|
|
@@ -90,6 +106,32 @@ module Rubycc
|
|
|
90
106
|
# post-alloca rsp as the block's base address.
|
|
91
107
|
RSP = 4
|
|
92
108
|
|
|
109
|
+
# The registers whole-function promotion hands out, in the order it hands
|
|
110
|
+
# them out (see IR::Promotion and #promotion_assignment). All five are
|
|
111
|
+
# callee-saved under System V AMD64 (psABI 3.2.1: rbx, rbp and r12..r15
|
|
112
|
+
# are preserved across a call), which is what lets a promoted value stay
|
|
113
|
+
# put across one — and none of them is used for anything else here, the
|
|
114
|
+
# scratch, argument and return registers all being caller-saved. rbp is
|
|
115
|
+
# excluded, being the frame pointer every slot is addressed from.
|
|
116
|
+
#
|
|
117
|
+
# rbx is register 3 and needs no REX extension; r12..r15 have their high
|
|
118
|
+
# bit carried by REX.R when they land in a ModR/M reg field, by REX.B when
|
|
119
|
+
# they land in an rm field (or a SIB base, or an opcode's low three bits)
|
|
120
|
+
# and by REX.X in a SIB index — every one of which they do land in, since
|
|
121
|
+
# a promoted value is named where it lives rather than moved to a scratch
|
|
122
|
+
# register first. #emit_rex is where all four bits are decided.
|
|
123
|
+
#
|
|
124
|
+
# None of these is a scratch, argument or return register, so no residency
|
|
125
|
+
# the SlotResidency table keeps is ever keyed by one; that is what lets an
|
|
126
|
+
# instruction writing a promoted register leave the table standing (see
|
|
127
|
+
# SlotResidency#note_register_clobbered).
|
|
128
|
+
RBX = 3
|
|
129
|
+
R12 = 12
|
|
130
|
+
R13 = 13
|
|
131
|
+
R14 = 14
|
|
132
|
+
R15 = 15
|
|
133
|
+
PROMOTION_REGISTERS = [RBX, R12, R13, R14, R15].freeze
|
|
134
|
+
|
|
93
135
|
# The two vector (xmm) scratch registers the floating ops use. Their
|
|
94
136
|
# numbers 0/1 double as the ModR/M reg/rm fields, so no REX.R is ever
|
|
95
137
|
# needed to name them. Every floating value round-trips through a GP stack
|
|
@@ -108,6 +150,11 @@ module Rubycc
|
|
|
108
150
|
GP_RETURN_REGISTERS = [EAX, EDX].freeze
|
|
109
151
|
SSE_RETURN_REGISTERS = [XMM0, XMM1].freeze
|
|
110
152
|
|
|
153
|
+
# :scaled_add's element size -> the SIB byte's two-bit scale field. The
|
|
154
|
+
# four sizes are the only ones the encoding can name, which is exactly the
|
|
155
|
+
# set IR::Simplify fuses a subscript for.
|
|
156
|
+
SIB_SCALES = { 1 => 0, 2 => 1, 4 => 2, 8 => 3 }.freeze
|
|
157
|
+
|
|
111
158
|
# IR comparison op -> setcc opcode (second byte of the 0F 9x encoding).
|
|
112
159
|
# The result is materialized into eax as an int 0/1 by movzx. The signed
|
|
113
160
|
# forms (setl/setle/setg/setge) test the sign/overflow flags; the unsigned
|
|
@@ -126,8 +173,28 @@ module Rubycc
|
|
|
126
173
|
uge: 0x93 # setae (above or equal, unsigned >=)
|
|
127
174
|
}.freeze
|
|
128
175
|
|
|
129
|
-
|
|
176
|
+
# `analysis` is the census of `ir_func`'s instruction list (IR::Analysis).
|
|
177
|
+
# The compiler passes the one IR::Simplify already took on its way
|
|
178
|
+
# through; a caller that hands over a function directly gets it taken
|
|
179
|
+
# here.
|
|
180
|
+
def compile(ir_func, analysis = IR::Analysis.of(ir_func))
|
|
130
181
|
@code = +"".b
|
|
182
|
+
reset_slot_residency
|
|
183
|
+
# Slots this function never has to write: an expression temporary whose
|
|
184
|
+
# one reader is the instruction right behind its producer stays in the
|
|
185
|
+
# register it was computed in (see IR::Simplify#transient_flags and
|
|
186
|
+
# #store_reg). The answer is a property of the instruction list, so it
|
|
187
|
+
# is taken once here rather than rediscovered per instruction, and it
|
|
188
|
+
# arrives as an array indexed by vreg number — the numbers are dense and
|
|
189
|
+
# small, and this is asked on every store the backend emits.
|
|
190
|
+
@transient = analysis.transient
|
|
191
|
+
# Slots this function does not have at all: a promoted value lives in
|
|
192
|
+
# one callee-saved register from the prologue to every ret, so its slot
|
|
193
|
+
# is never read, written or named (see #promotion_assignment, #load_reg
|
|
194
|
+
# and #store_reg). Like @transient this is a property of the instruction
|
|
195
|
+
# list, decided once here, and indexed by vreg number for the same
|
|
196
|
+
# reason.
|
|
197
|
+
@promoted = promotion_assignment(ir_func, analysis)
|
|
131
198
|
# Control-flow bookkeeping: `@labels` maps a label id to its resolved
|
|
132
199
|
# code offset; `@fixups` collects [patch_offset, label_id] pairs whose
|
|
133
200
|
# rel32 field is overwritten once every label offset is known.
|
|
@@ -154,12 +221,31 @@ module Rubycc
|
|
|
154
221
|
|
|
155
222
|
private
|
|
156
223
|
|
|
224
|
+
# Binds the best promotion candidates to PROMOTION_REGISTERS in order,
|
|
225
|
+
# returning the vreg -> register table the whole backend consults (an
|
|
226
|
+
# array; a vreg that owns no register indexes nil). Taking the first few
|
|
227
|
+
# of an ordered list is the entire allocation: one register each, held for
|
|
228
|
+
# the function's length, so there is no interference to resolve and
|
|
229
|
+
# nothing to undo when the registers run out — the candidates past the
|
|
230
|
+
# fifth simply keep their slots.
|
|
231
|
+
#
|
|
232
|
+
# @promoted_registers is the same binding in assignment order, which is
|
|
233
|
+
# the order the save slots are laid out in (#emit_prologue).
|
|
234
|
+
def promotion_assignment(ir_func, analysis)
|
|
235
|
+
vregs = IR::Promotion.candidates(ir_func, analysis).first(PROMOTION_REGISTERS.size)
|
|
236
|
+
@promoted_registers = PROMOTION_REGISTERS.first(vregs.size)
|
|
237
|
+
promoted = Array.new(ir_func.vreg_count)
|
|
238
|
+
vregs.each_with_index { |vreg, index| promoted[vreg] = PROMOTION_REGISTERS[index] }
|
|
239
|
+
promoted
|
|
240
|
+
end
|
|
241
|
+
|
|
157
242
|
# Frame layout, from rbp downward: first the virtual-register slots
|
|
158
243
|
# (8 bytes each, rounded up to a 16-byte region), then the stack objects,
|
|
159
|
-
#
|
|
160
|
-
#
|
|
161
|
-
#
|
|
162
|
-
#
|
|
244
|
+
# then one 8-byte save slot per promoted register, and last — for a
|
|
245
|
+
# variadic function — a 176-byte register-save area below everything else.
|
|
246
|
+
# Each object is placed at a 16-byte-aligned size below the previous one,
|
|
247
|
+
# and @object_offsets[id] records the rbp-relative displacement of the
|
|
248
|
+
# object's base (its lowest address, i.e. element 0).
|
|
163
249
|
def emit_prologue(vreg_count, param_count, param_kinds, stack_objects, variadic)
|
|
164
250
|
vreg_region = align16(vreg_count * 8)
|
|
165
251
|
@object_offsets = []
|
|
@@ -168,6 +254,17 @@ module Rubycc
|
|
|
168
254
|
running += align16(object_size)
|
|
169
255
|
@object_offsets << -running
|
|
170
256
|
end
|
|
257
|
+
# One save slot per promoted register. The registers are callee-saved,
|
|
258
|
+
# so a function that uses one has to give it back exactly as it found
|
|
259
|
+
# it; saving them into the frame with mov rather than with push keeps
|
|
260
|
+
# rsp's 16-byte alignment — which every call depends on — a property of
|
|
261
|
+
# the single `sub` below instead of the parity of the register count.
|
|
262
|
+
# They are laid out in assignment order, and their number is a function
|
|
263
|
+
# of the instruction list, so the frame stays deterministic (N4).
|
|
264
|
+
@promoted_saves = @promoted_registers.map do |reg|
|
|
265
|
+
running += 8
|
|
266
|
+
[reg, -running]
|
|
267
|
+
end
|
|
171
268
|
# A variadic function reserves a 176-byte register-save area at the very
|
|
172
269
|
# bottom of the frame; :va_start points reg_save_area here and the
|
|
173
270
|
# prologue spills the six integer argument registers (48 bytes) followed
|
|
@@ -184,6 +281,10 @@ module Rubycc
|
|
|
184
281
|
emit(0x48, 0x89, 0xE5) # mov rbp, rsp
|
|
185
282
|
emit(0x48, 0x81, 0xEC) # sub rsp, imm32
|
|
186
283
|
emit_bytes([frame_size].pack("L<"))
|
|
284
|
+
# Before anything writes a promoted register — which the parameter
|
|
285
|
+
# spilling right below is the first thing to do, a promoted parameter
|
|
286
|
+
# being moved straight from its incoming argument register.
|
|
287
|
+
emit_save_promoted_registers
|
|
187
288
|
spill_parameters(param_kinds)
|
|
188
289
|
if variadic
|
|
189
290
|
emit_save_gp_registers
|
|
@@ -191,6 +292,31 @@ module Rubycc
|
|
|
191
292
|
end
|
|
192
293
|
end
|
|
193
294
|
|
|
295
|
+
# Saves the promoted registers into their frame slots, "mov [rbp+disp],
|
|
296
|
+
# r64" apiece. REX.W widens the move and REX.R extends r12..r15, whose low
|
|
297
|
+
# three bits go into the ModR/M reg field; the rm field is rbp's, so no SIB
|
|
298
|
+
# byte is involved on either side.
|
|
299
|
+
def emit_save_promoted_registers
|
|
300
|
+
@promoted_saves.each do |reg, disp|
|
|
301
|
+
emit(0x48 | (reg >= 8 ? 0x04 : 0)) # REX.W (+ REX.R for r12..r15)
|
|
302
|
+
emit(0x89) # mov [rbp + disp], r64
|
|
303
|
+
emit_modrm_rbp_disp(reg & 7, disp)
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# Puts the caller's values back, the exact inverse of
|
|
308
|
+
# #emit_save_promoted_registers (8B reads memory into the register). Every
|
|
309
|
+
# :ret emits this immediately before its "leave", and a :ret is the only
|
|
310
|
+
# way out of a function, so no path returns with a callee-saved register
|
|
311
|
+
# holding this function's value.
|
|
312
|
+
def emit_restore_promoted_registers
|
|
313
|
+
@promoted_saves.each do |reg, disp|
|
|
314
|
+
emit(0x48 | (reg >= 8 ? 0x04 : 0)) # REX.W (+ REX.R for r12..r15)
|
|
315
|
+
emit(0x8B) # mov r64, [rbp + disp]
|
|
316
|
+
emit_modrm_rbp_disp(reg & 7, disp)
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
|
|
194
320
|
# Brings each incoming argument into its parameter slot (the first
|
|
195
321
|
# `param_count` vregs, one per param_kinds entry) so it reads back like any
|
|
196
322
|
# other vreg. The generator has already fixed where each parameter arrives:
|
|
@@ -269,11 +395,21 @@ module Rubycc
|
|
|
269
395
|
load_reg(EAX, inst.a)
|
|
270
396
|
store_reg(EAX, inst.dst)
|
|
271
397
|
when :add
|
|
272
|
-
|
|
398
|
+
# 03 /r is "add r32, r/m32" — the same addition as 01 /r's "add
|
|
399
|
+
# r/m32, r32" with the operands the other way round, which is what
|
|
400
|
+
# lets the second one be a slot. Every entry below pairs the two
|
|
401
|
+
# directions the same way (the group's low opcode plus two).
|
|
402
|
+
emit_binary(inst.dst, inst.a, inst.b, [0x01, 0xC8], inst.size,
|
|
403
|
+
memory_bytes: [0x03], commutative: true)
|
|
404
|
+
when :scaled_add
|
|
405
|
+
emit_scaled_add(inst.dst, inst.a, inst.b, inst.size)
|
|
273
406
|
when :sub
|
|
274
|
-
emit_binary(inst.dst, inst.a, inst.b, [0x29, 0xC8], inst.size
|
|
407
|
+
emit_binary(inst.dst, inst.a, inst.b, [0x29, 0xC8], inst.size, memory_bytes: [0x2B])
|
|
275
408
|
when :mul
|
|
276
|
-
|
|
409
|
+
# imul (0F AF /r) is already a "r32, r/m32" form, so its register and
|
|
410
|
+
# memory encodings share the same opcode.
|
|
411
|
+
emit_binary(inst.dst, inst.a, inst.b, [0x0F, 0xAF, 0xC1], inst.size,
|
|
412
|
+
memory_bytes: [0x0F, 0xAF], commutative: true)
|
|
277
413
|
when :mulhi
|
|
278
414
|
emit_mulhi(inst.dst, inst.a, inst.b) # high 64 bits of an unsigned 64x64 product
|
|
279
415
|
when :div
|
|
@@ -285,11 +421,14 @@ module Rubycc
|
|
|
285
421
|
when :umod
|
|
286
422
|
emit_udivmod(inst.dst, inst.a, inst.b, EDX, inst.size) # remainder in edx
|
|
287
423
|
when :and
|
|
288
|
-
emit_binary(inst.dst, inst.a, inst.b, [0x21, 0xC8], inst.size
|
|
424
|
+
emit_binary(inst.dst, inst.a, inst.b, [0x21, 0xC8], inst.size,
|
|
425
|
+
memory_bytes: [0x23], commutative: true)
|
|
289
426
|
when :or
|
|
290
|
-
emit_binary(inst.dst, inst.a, inst.b, [0x09, 0xC8], inst.size
|
|
427
|
+
emit_binary(inst.dst, inst.a, inst.b, [0x09, 0xC8], inst.size,
|
|
428
|
+
memory_bytes: [0x0B], commutative: true)
|
|
291
429
|
when :xor
|
|
292
|
-
emit_binary(inst.dst, inst.a, inst.b, [0x31, 0xC8], inst.size
|
|
430
|
+
emit_binary(inst.dst, inst.a, inst.b, [0x31, 0xC8], inst.size,
|
|
431
|
+
memory_bytes: [0x33], commutative: true)
|
|
293
432
|
when :shl
|
|
294
433
|
# shl eax, cl (D3 /4): the count comes from cl, which #emit_binary
|
|
295
434
|
# loads into ecx alongside the value in eax. A size-8 operand takes a
|
|
@@ -306,7 +445,8 @@ module Rubycc
|
|
|
306
445
|
# unsigned counterpart of :sar.
|
|
307
446
|
emit_binary(inst.dst, inst.a, inst.b, [0xD3, 0xE8], inst.size)
|
|
308
447
|
when :eq, :ne, :lt, :le, :gt, :ge, :ult, :ule, :ugt, :uge
|
|
309
|
-
emit_comparison(inst.dst, inst.a, inst.b, SETCC_OPCODES.fetch(inst.op), inst.size
|
|
448
|
+
emit_comparison(inst.dst, inst.a, inst.b, SETCC_OPCODES.fetch(inst.op), inst.size,
|
|
449
|
+
commutative: inst.op == :eq || inst.op == :ne)
|
|
310
450
|
when :fadd
|
|
311
451
|
emit_float_binary(inst.dst, inst.a, inst.b, inst.size, 0x58) # addss/addsd
|
|
312
452
|
when :fsub
|
|
@@ -339,6 +479,11 @@ module Rubycc
|
|
|
339
479
|
when :got_addr
|
|
340
480
|
emit_got_addr(inst.dst, inst.a)
|
|
341
481
|
when :label
|
|
482
|
+
# The one place a register's meaning changes without an instruction
|
|
483
|
+
# being emitted: control may arrive here from a branch whose registers
|
|
484
|
+
# hold something else entirely, so nothing may be assumed resident
|
|
485
|
+
# past a label (see SlotResidency).
|
|
486
|
+
forget_slot_residency
|
|
342
487
|
@labels[inst.a] = @code.bytesize
|
|
343
488
|
when :jump
|
|
344
489
|
emit_jump(inst.a)
|
|
@@ -368,6 +513,8 @@ module Rubycc
|
|
|
368
513
|
emit_alloca(inst.dst, inst.a)
|
|
369
514
|
when :bit_scan
|
|
370
515
|
emit_bit_scan(inst.dst, inst.a, inst.b, inst.size)
|
|
516
|
+
when :popcount
|
|
517
|
+
emit_popcount(inst.dst, inst.a, inst.size)
|
|
371
518
|
when :atomic_load
|
|
372
519
|
emit_atomic_load(inst.dst, inst.a, inst.size)
|
|
373
520
|
when :atomic_store
|
|
@@ -591,6 +738,9 @@ module Rubycc
|
|
|
591
738
|
else
|
|
592
739
|
load_reg(EAX, value_vreg)
|
|
593
740
|
end
|
|
741
|
+
# After the value is loaded, since it may itself come out of a promoted
|
|
742
|
+
# register, and before "leave" while rbp still addresses the frame.
|
|
743
|
+
emit_restore_promoted_registers
|
|
594
744
|
emit(0xC9) # leave
|
|
595
745
|
emit(0xC3) # ret
|
|
596
746
|
end
|
|
@@ -683,39 +833,53 @@ module Rubycc
|
|
|
683
833
|
end
|
|
684
834
|
|
|
685
835
|
# :sext — sign-extend a's low `size` bytes to the full 64-bit register.
|
|
686
|
-
# size 4 is a movsxd
|
|
687
|
-
#
|
|
688
|
-
#
|
|
689
|
-
# short/char value from just its stored low bytes.
|
|
690
|
-
#
|
|
836
|
+
# size 4 is a movsxd (the classic int -> long widening, so pointer-offset
|
|
837
|
+
# scaling sees a correct, possibly negative index); size 2 a movsx r64,
|
|
838
|
+
# r/m16 and size 1 a movsx r64, r/m8, which re-derive a signed
|
|
839
|
+
# short/char value from just its stored low bytes.
|
|
840
|
+
#
|
|
841
|
+
# Both halves of the instruction are free of a fixed register: the source
|
|
842
|
+
# is an r/m field, so a promoted operand is read in place, and the
|
|
843
|
+
# destination a reg field, so a promoted result is written in place
|
|
844
|
+
# (#widen_in_registers).
|
|
691
845
|
def emit_sext(dst, src_vreg, size)
|
|
692
|
-
load_reg(EAX, src_vreg) # rax = value
|
|
693
846
|
case size
|
|
694
|
-
when 1
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
emit(0x48, 0x0F, 0xBF, 0xC0) # REX.W movsx rax, ax
|
|
698
|
-
else # 4
|
|
699
|
-
emit(0x48, 0x63, 0xC0) # REX.W movsxd rax, eax
|
|
847
|
+
when 1 then widen_in_registers(dst, src_vreg, [0x0F, 0xBE], rex_w: true) # movsx r64, r/m8
|
|
848
|
+
when 2 then widen_in_registers(dst, src_vreg, [0x0F, 0xBF], rex_w: true) # movsx r64, r/m16
|
|
849
|
+
else widen_in_registers(dst, src_vreg, [0x63], rex_w: true) # movsxd r64, r/m32
|
|
700
850
|
end
|
|
701
|
-
store_reg(EAX, dst)
|
|
702
851
|
end
|
|
703
852
|
|
|
704
853
|
# :zext — zero-extend a's low `size` bytes to the full 64-bit register.
|
|
705
|
-
# size 1/2 are a movzx
|
|
706
|
-
#
|
|
707
|
-
#
|
|
854
|
+
# size 1/2 are a movzx r32, r/m8 / movzx r32, r/m16; size 4 a plain 32-bit
|
|
855
|
+
# mov. Each writes a 32-bit register, which x86-64 defines to clear the
|
|
856
|
+
# upper 32 bits of its 64-bit whole, so all three leave a clean
|
|
857
|
+
# zero-extended value.
|
|
708
858
|
def emit_zext(dst, src_vreg, size)
|
|
709
|
-
load_reg(EAX, src_vreg) # rax = value
|
|
710
859
|
case size
|
|
711
|
-
when 1
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
emit(0x0F, 0xB7, 0xC0) # movzx eax, ax
|
|
715
|
-
else # 4
|
|
716
|
-
emit(0x89, 0xC0) # mov eax, eax
|
|
860
|
+
when 1 then widen_in_registers(dst, src_vreg, [0x0F, 0xB6]) # movzx r32, r/m8
|
|
861
|
+
when 2 then widen_in_registers(dst, src_vreg, [0x0F, 0xB7]) # movzx r32, r/m16
|
|
862
|
+
else widen_in_registers(dst, src_vreg, [0x8B]) # mov r32, r/m32
|
|
717
863
|
end
|
|
718
|
-
|
|
864
|
+
end
|
|
865
|
+
|
|
866
|
+
# The shared shape of :sext and :zext: one "reg, r/m" instruction from
|
|
867
|
+
# wherever the source lives to wherever the destination lives. A promoted
|
|
868
|
+
# source is the r/m operand outright; any other source goes through eax
|
|
869
|
+
# first, as before, since a slot holds eight bytes and these opcodes'
|
|
870
|
+
# 1/2-byte forms would read the wrong count of them. A promoted
|
|
871
|
+
# destination is the reg field, so no move follows either.
|
|
872
|
+
def widen_in_registers(dst, src_vreg, opcode_bytes, rex_w: false)
|
|
873
|
+
refresh_slot_residency
|
|
874
|
+
source = @promoted[src_vreg]
|
|
875
|
+
unless source
|
|
876
|
+
load_reg(EAX, src_vreg) # rax = value
|
|
877
|
+
source = EAX
|
|
878
|
+
end
|
|
879
|
+
target = result_register(dst)
|
|
880
|
+
emit_register_rm(opcode_bytes, source, reg: target, rex_w: rex_w)
|
|
881
|
+
# One "reg, r/m" instruction: its reg field is the only thing written.
|
|
882
|
+
store_result(target, dst, only_wrote: target)
|
|
719
883
|
end
|
|
720
884
|
|
|
721
885
|
# :bit_scan — count the zero bits of a's value (__builtin_ctz/clz). The
|
|
@@ -740,6 +904,141 @@ module Rubycc
|
|
|
740
904
|
store_reg(EAX, dst)
|
|
741
905
|
end
|
|
742
906
|
|
|
907
|
+
# The bit-field patterns :popcount folds over, in their 8-byte form; a
|
|
908
|
+
# 4-byte count uses the low half of each. The first three keep the partial
|
|
909
|
+
# counts of one width from spilling into their neighbours, and the last is
|
|
910
|
+
# the one-per-byte multiplier that sums the eight byte counts at once.
|
|
911
|
+
POPCOUNT_PAIR_MASK = 0x5555_5555_5555_5555
|
|
912
|
+
POPCOUNT_NIBBLE_MASK = 0x3333_3333_3333_3333
|
|
913
|
+
POPCOUNT_BYTE_MASK = 0x0F0F_0F0F_0F0F_0F0F
|
|
914
|
+
POPCOUNT_BYTE_ONES = 0x0101_0101_0101_0101
|
|
915
|
+
|
|
916
|
+
# :popcount — how many bits of a's value are set (__builtin_popcount and
|
|
917
|
+
# its "l"/"ll" forms). x86-64 does have an instruction for exactly this,
|
|
918
|
+
# `popcnt`, but it arrived with SSE4.2 and is not part of the baseline
|
|
919
|
+
# architecture rubycc emits for: using it would make the output fault on
|
|
920
|
+
# an older CPU, and make it depend on the CPU that happened to build it.
|
|
921
|
+
# The count is expanded instead, in the same shape the aarch64 backend
|
|
922
|
+
# uses (whose `cnt` is an extension too — an AdvSIMD one, reached only
|
|
923
|
+
# through a vector register).
|
|
924
|
+
#
|
|
925
|
+
# The expansion is a divide-and-conquer sum over the register's own bits
|
|
926
|
+
# ("SWAR"): a register is read as many independent counts side by side,
|
|
927
|
+
# which are added pairwise until one of them spans it. Start from 2-bit
|
|
928
|
+
# fields, where the count is already there to be read — a field holding
|
|
929
|
+
# hi:lo has hi + lo bits set — and each step halves the number of fields
|
|
930
|
+
# while doubling their width: 32 counts become 16, then 8, 4, 2 and 1 in a
|
|
931
|
+
# 64-bit register, half that in a 32-bit one. What every step needs is a
|
|
932
|
+
# shift to bring one field's partner onto it, an add, and enough masking
|
|
933
|
+
# that no field's sum reaches its neighbour. Three steps are written out
|
|
934
|
+
# below and the remaining ones — three of them at 64 bits, two at 32 —
|
|
935
|
+
# are what the closing multiply performs in a single instruction:
|
|
936
|
+
#
|
|
937
|
+
# pairs x -= (x >> 1) & 0x5555... each 2-bit field v = 2*hi + lo
|
|
938
|
+
# becomes v - hi = hi + lo. The
|
|
939
|
+
# subtraction never borrows across
|
|
940
|
+
# a field (the result is at most
|
|
941
|
+
# the field's own value), so the
|
|
942
|
+
# one mask on the shift is all it
|
|
943
|
+
# takes
|
|
944
|
+
# nibbles x = (x & 0x3333...) + ((x >> 2) & 0x3333...)
|
|
945
|
+
# two counts of at most 2 sum to 4,
|
|
946
|
+
# which no longer fits a 2-bit
|
|
947
|
+
# field: both sides are masked
|
|
948
|
+
# before adding, into the 4-bit
|
|
949
|
+
# fields that do hold it
|
|
950
|
+
# bytes x = (x + (x >> 4)) & 0x0F0F...
|
|
951
|
+
# two counts of at most 4 sum to 8,
|
|
952
|
+
# which still fits a nibble, so the
|
|
953
|
+
# add can run unmasked and one mask
|
|
954
|
+
# afterwards clears the odd nibbles
|
|
955
|
+
# it dirtied
|
|
956
|
+
# total (x * 0x0101...) >> (bits - 8)
|
|
957
|
+
# every byte now holds its own
|
|
958
|
+
# count. Multiplying by one-per-byte
|
|
959
|
+
# adds each byte into every byte
|
|
960
|
+
# above it, so the top byte receives
|
|
961
|
+
# all of them; the column sums are
|
|
962
|
+
# at most 64 and never carry out of
|
|
963
|
+
# a byte, and the shift brings that
|
|
964
|
+
# top byte down
|
|
965
|
+
#
|
|
966
|
+
# rcx carries the running value, rax the copy each stage shifts and adds
|
|
967
|
+
# back in (and, from the third stage on, the result), and rdx a mask —
|
|
968
|
+
# which only the 8-byte form needs, x86-64 having no 64-bit immediate for
|
|
969
|
+
# a logical op. The 4-byte form is the same sequence in 32-bit registers,
|
|
970
|
+
# whose writes zero the upper half, so the indeterminate high bits of a
|
|
971
|
+
# slot that was moved 64 bits at a time never enter the count.
|
|
972
|
+
def emit_popcount(dst, src_vreg, size)
|
|
973
|
+
load_reg(ECX, src_vreg) # rcx = value to count
|
|
974
|
+
emit_popcount_reg(0x89, EAX, ECX, size) # mov rax, rcx
|
|
975
|
+
emit_popcount_shr(EAX, 1, size) # rax = x >> 1
|
|
976
|
+
emit_popcount_mask([EAX], POPCOUNT_PAIR_MASK, size)
|
|
977
|
+
emit_popcount_reg(0x29, ECX, EAX, size) # sub rcx, rax (pair counts)
|
|
978
|
+
emit_popcount_reg(0x89, EAX, ECX, size) # mov rax, rcx
|
|
979
|
+
emit_popcount_shr(ECX, 2, size) # rcx = x >> 2
|
|
980
|
+
emit_popcount_mask([EAX, ECX], POPCOUNT_NIBBLE_MASK, size)
|
|
981
|
+
emit_popcount_reg(0x01, ECX, EAX, size) # add rcx, rax (nibble counts)
|
|
982
|
+
emit_popcount_reg(0x89, EAX, ECX, size) # mov rax, rcx
|
|
983
|
+
emit_popcount_shr(EAX, 4, size) # rax = x >> 4
|
|
984
|
+
emit_popcount_reg(0x01, EAX, ECX, size) # add rax, rcx
|
|
985
|
+
emit_popcount_mask([EAX], POPCOUNT_BYTE_MASK, size) # byte counts
|
|
986
|
+
emit_popcount_byte_sum(size) # rax = sum of the bytes
|
|
987
|
+
store_reg(EAX, dst)
|
|
988
|
+
end
|
|
989
|
+
|
|
990
|
+
# One two-register instruction of the expansion, in the "r/m, reg"
|
|
991
|
+
# direction: `opcode` applies `reg` to `rm`. An 8-byte count takes a REX.W
|
|
992
|
+
# prefix and a 4-byte one no prefix at all — every register here is one of
|
|
993
|
+
# rax/rcx/rdx, so no REX bit is needed to name them.
|
|
994
|
+
def emit_popcount_reg(opcode, rm, reg, size)
|
|
995
|
+
emit(0x48) if size == 8 # REX.W: the 64-bit form
|
|
996
|
+
emit(opcode, 0xC0 | (reg << 3) | rm)
|
|
997
|
+
end
|
|
998
|
+
|
|
999
|
+
# `shr rm, count` (C1 /5 ib) at the count's width.
|
|
1000
|
+
def emit_popcount_shr(rm, count, size)
|
|
1001
|
+
emit(0x48) if size == 8 # REX.W: a 64-bit shift
|
|
1002
|
+
emit(0xC1, 0xE8 | rm, count)
|
|
1003
|
+
end
|
|
1004
|
+
|
|
1005
|
+
# Masks each of `regs` with one of the expansion's field patterns. A
|
|
1006
|
+
# 4-byte count names it as an immediate ("and r/m32, imm32", 81 /4 id); an
|
|
1007
|
+
# 8-byte one cannot, x86-64's logical ops taking at most a sign-extended
|
|
1008
|
+
# imm32, so the mask is materialized in rdx once (movabs) and applied from
|
|
1009
|
+
# there ("and r/m64, r64", 21 /r) — which is why the registers to mask
|
|
1010
|
+
# arrive together rather than one call at a time: the nibble stage masks
|
|
1011
|
+
# two of them with the same pattern.
|
|
1012
|
+
def emit_popcount_mask(regs, mask, size)
|
|
1013
|
+
if size == 8
|
|
1014
|
+
emit(0x48, 0xBA) # movabs rdx, imm64
|
|
1015
|
+
emit_bytes([mask].pack("Q<"))
|
|
1016
|
+
regs.each { |reg| emit_popcount_reg(0x21, reg, EDX, size) } # and reg, rdx
|
|
1017
|
+
else
|
|
1018
|
+
regs.each do |reg|
|
|
1019
|
+
emit(0x81, 0xE0 | reg) # and r/m32, imm32
|
|
1020
|
+
emit_bytes([mask & 0xFFFFFFFF].pack("L<"))
|
|
1021
|
+
end
|
|
1022
|
+
end
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
# The expansion's last stage: rax holds one count per byte, and the
|
|
1026
|
+
# multiply by one-per-byte gathers them into the top byte, which the shift
|
|
1027
|
+
# brings down. The 4-byte form takes its multiplier as an immediate
|
|
1028
|
+
# ("imul r32, r/m32, imm32", 69 /r id); the 8-byte one has no imm64 form
|
|
1029
|
+
# either, so the multiplier goes through rdx ("imul r64, r/m64", 0F AF /r).
|
|
1030
|
+
def emit_popcount_byte_sum(size)
|
|
1031
|
+
if size == 8
|
|
1032
|
+
emit(0x48, 0xBA) # movabs rdx, 0x0101010101010101
|
|
1033
|
+
emit_bytes([POPCOUNT_BYTE_ONES].pack("Q<"))
|
|
1034
|
+
emit(0x48, 0x0F, 0xAF, 0xC2) # imul rax, rdx
|
|
1035
|
+
else
|
|
1036
|
+
emit(0x69, 0xC0) # imul eax, eax, imm32
|
|
1037
|
+
emit_bytes([POPCOUNT_BYTE_ONES & 0xFFFFFFFF].pack("L<"))
|
|
1038
|
+
end
|
|
1039
|
+
emit_popcount_shr(EAX, size * 8 - 8, size) # rax = the top byte
|
|
1040
|
+
end
|
|
1041
|
+
|
|
743
1042
|
# --- atomics -----------------------------------------------------------
|
|
744
1043
|
#
|
|
745
1044
|
# The four atomic ops all lower at sequential consistency, the strongest
|
|
@@ -782,8 +1081,7 @@ module Rubycc
|
|
|
782
1081
|
# implicitly locked, is also the full barrier a seq_cst store needs; a mov
|
|
783
1082
|
# followed by an mfence would be equivalent and longer.
|
|
784
1083
|
def emit_atomic_store(ptr_vreg, value_vreg, size)
|
|
785
|
-
|
|
786
|
-
load_reg(ECX, value_vreg) # rcx = value
|
|
1084
|
+
load_binary_operands(ptr_vreg, value_vreg) # rax = destination address, rcx = value
|
|
787
1085
|
emit(0x48) if size == 8 # REX.W
|
|
788
1086
|
emit(0x87, 0x08) # xchg [rax], ecx/rcx
|
|
789
1087
|
end
|
|
@@ -805,8 +1103,7 @@ module Rubycc
|
|
|
805
1103
|
def emit_atomic_rmw(dst, ptr_vreg, value_vreg, kind, size)
|
|
806
1104
|
return emit_atomic_or_fetch(dst, ptr_vreg, value_vreg, size) if kind == :or_fetch
|
|
807
1105
|
|
|
808
|
-
|
|
809
|
-
load_reg(ECX, value_vreg) # rcx = operand
|
|
1106
|
+
load_binary_operands(ptr_vreg, value_vreg) # rax = address, rcx = operand
|
|
810
1107
|
negate = kind == :fetch_sub || kind == :sub_fetch
|
|
811
1108
|
keep = kind == :add_fetch || kind == :sub_fetch
|
|
812
1109
|
if negate
|
|
@@ -906,24 +1203,21 @@ module Rubycc
|
|
|
906
1203
|
store_reg(EAX, dst)
|
|
907
1204
|
end
|
|
908
1205
|
|
|
909
|
-
# "*p" read, sign-extending: load the pointer
|
|
910
|
-
#
|
|
911
|
-
#
|
|
912
|
-
#
|
|
913
|
-
#
|
|
1206
|
+
# "*p" read, sign-extending: load the pointer into rax, then read through
|
|
1207
|
+
# it. An 8-byte load moves a full pointer/long (mov r64, [rax]); a 4-byte
|
|
1208
|
+
# load reads an int (mov r32, [rax]), whose upper bits the 32-bit write
|
|
1209
|
+
# zeroes; a 2/1-byte load reads a short/char and sign-extends it to the
|
|
1210
|
+
# register (movsx), so the slot holds a promoted signed value.
|
|
1211
|
+
#
|
|
1212
|
+
# The destination is a reg field in every one of the four, so a promoted
|
|
1213
|
+
# one is written directly (#emit_deref).
|
|
914
1214
|
def emit_load(dst, ptr_vreg, size)
|
|
915
|
-
load_reg(EAX, ptr_vreg) # rax = pointer value
|
|
916
1215
|
case size
|
|
917
|
-
when 8
|
|
918
|
-
|
|
919
|
-
when
|
|
920
|
-
|
|
921
|
-
when 1
|
|
922
|
-
emit(0x0F, 0xBE, 0x00) # movsx eax, byte [rax]
|
|
923
|
-
else # 4
|
|
924
|
-
emit(0x8B, 0x00) # mov eax, [rax]
|
|
1216
|
+
when 8 then emit_deref(dst, ptr_vreg, [0x8B], rex_w: true) # mov r64, [rax]
|
|
1217
|
+
when 2 then emit_deref(dst, ptr_vreg, [0x0F, 0xBF]) # movsx r32, word [rax]
|
|
1218
|
+
when 1 then emit_deref(dst, ptr_vreg, [0x0F, 0xBE]) # movsx r32, byte [rax]
|
|
1219
|
+
else emit_deref(dst, ptr_vreg, [0x8B]) # mov r32, [rax]
|
|
925
1220
|
end
|
|
926
|
-
store_reg(EAX, dst)
|
|
927
1221
|
end
|
|
928
1222
|
|
|
929
1223
|
# "*p" read, zero-extending: the unsigned counterpart of #emit_load for an
|
|
@@ -931,18 +1225,28 @@ module Rubycc
|
|
|
931
1225
|
# forms are identical to a signed load (a plain mov already zero-extends a
|
|
932
1226
|
# 32-bit read, and an 8-byte value has no spare bits).
|
|
933
1227
|
def emit_uload(dst, ptr_vreg, size)
|
|
934
|
-
load_reg(EAX, ptr_vreg) # rax = pointer value
|
|
935
1228
|
case size
|
|
936
|
-
when 8
|
|
937
|
-
|
|
938
|
-
when
|
|
939
|
-
|
|
940
|
-
when 1
|
|
941
|
-
emit(0x0F, 0xB6, 0x00) # movzx eax, byte [rax]
|
|
942
|
-
else # 4
|
|
943
|
-
emit(0x8B, 0x00) # mov eax, [rax]
|
|
1229
|
+
when 8 then emit_deref(dst, ptr_vreg, [0x8B], rex_w: true) # mov r64, [rax]
|
|
1230
|
+
when 2 then emit_deref(dst, ptr_vreg, [0x0F, 0xB7]) # movzx r32, word [rax]
|
|
1231
|
+
when 1 then emit_deref(dst, ptr_vreg, [0x0F, 0xB6]) # movzx r32, byte [rax]
|
|
1232
|
+
else emit_deref(dst, ptr_vreg, [0x8B]) # mov r32, [rax]
|
|
944
1233
|
end
|
|
945
|
-
|
|
1234
|
+
end
|
|
1235
|
+
|
|
1236
|
+
# The shared shape of :load and :uload: the pointer into rax and one read
|
|
1237
|
+
# through [rax] into wherever the destination lives. The ModR/M is mod =
|
|
1238
|
+
# 00 with rm = 000, the plain "[rax]" form — no SIB byte and no
|
|
1239
|
+
# displacement — so only the reg field varies, and REX.R is all a promoted
|
|
1240
|
+
# destination costs.
|
|
1241
|
+
def emit_deref(dst, ptr_vreg, opcode_bytes, rex_w: false)
|
|
1242
|
+
load_reg(EAX, ptr_vreg) # rax = pointer value
|
|
1243
|
+
target = result_register(dst)
|
|
1244
|
+
emit_rex(rex_w: rex_w, reg: target)
|
|
1245
|
+
opcode_bytes.each { |byte| emit(byte) }
|
|
1246
|
+
emit((target & 7) << 3) # mod=00, rm=000: [rax]
|
|
1247
|
+
# The read through [rax] writes its reg field and nothing else; rax
|
|
1248
|
+
# itself was written by the load above, which accounted for itself.
|
|
1249
|
+
store_result(target, dst, only_wrote: target)
|
|
946
1250
|
end
|
|
947
1251
|
|
|
948
1252
|
# "*p = v": rax holds the destination address, rcx the value, then rcx is
|
|
@@ -952,8 +1256,7 @@ module Rubycc
|
|
|
952
1256
|
# a 1-byte store writes just the low byte (mov [rax], cl). The narrower
|
|
953
1257
|
# writes are exactly the truncation a narrow lvalue needs.
|
|
954
1258
|
def emit_store(ptr_vreg, value_vreg, size)
|
|
955
|
-
|
|
956
|
-
load_reg(ECX, value_vreg) # rcx = value
|
|
1259
|
+
load_binary_operands(ptr_vreg, value_vreg) # rax = destination address, rcx = value
|
|
957
1260
|
case size
|
|
958
1261
|
when 8
|
|
959
1262
|
emit(0x48, 0x89, 0x08) # mov [rax], rcx
|
|
@@ -1038,33 +1341,83 @@ module Rubycc
|
|
|
1038
1341
|
store_reg(RSP, dst) # dst = rsp (block base address)
|
|
1039
1342
|
end
|
|
1040
1343
|
|
|
1041
|
-
# A size of 8 compares full 64-bit pointer values (REX.W
|
|
1042
|
-
#
|
|
1043
|
-
#
|
|
1044
|
-
#
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1344
|
+
# A size of 8 compares full 64-bit pointer values (REX.W); otherwise the
|
|
1345
|
+
# 32-bit int compare is used. The signed setcc still suits pointer
|
|
1346
|
+
# ordering here, since stack addresses stay within the positive half of
|
|
1347
|
+
# the 64-bit range. The second operand is named where it lives (3B /r,
|
|
1348
|
+
# "cmp r32, r/m32") wherever it can be, as in #emit_binary.
|
|
1349
|
+
#
|
|
1350
|
+
# `cmp` reads both of its operands and writes neither, which the first one
|
|
1351
|
+
# takes advantage of too: a promoted `a` is named in the reg field
|
|
1352
|
+
# directly rather than moved into eax to be looked at. The result still
|
|
1353
|
+
# goes through eax, `setcc` writing al and nothing else — one of the fixed
|
|
1354
|
+
# registers this file does not try to talk out of its choice.
|
|
1355
|
+
#
|
|
1356
|
+
# An equality test is the one comparison whose operands may be exchanged
|
|
1357
|
+
# without changing its setcc: "a == b" and "b == a" leave the same ZF,
|
|
1358
|
+
# while every ordering test would need its condition mirrored as well.
|
|
1359
|
+
def emit_comparison(dst, a, b, setcc_opcode, size = nil, commutative: false)
|
|
1360
|
+
refresh_slot_residency
|
|
1361
|
+
a, b = b, a if commutative && prefer_swapped_operands?(a, b)
|
|
1362
|
+
if rm_operand?(b)
|
|
1363
|
+
left = @promoted[a]
|
|
1364
|
+
unless left
|
|
1365
|
+
load_reg(EAX, a)
|
|
1366
|
+
left = EAX
|
|
1367
|
+
end
|
|
1368
|
+
emit_vreg_rm([0x3B], b, reg: left, rex_w: size == 8) # cmp r32, r/m32
|
|
1369
|
+
else
|
|
1370
|
+
load_binary_operands(a, b, commutative: commutative)
|
|
1371
|
+
emit(0x48) if size == 8 # REX.W widens the following cmp
|
|
1372
|
+
emit(0x39, 0xC8) # cmp eax, ecx (rax, rcx when REX.W)
|
|
1373
|
+
end
|
|
1050
1374
|
emit(0x0F, setcc_opcode, 0xC0) # setcc al
|
|
1051
1375
|
emit(0x0F, 0xB6, 0xC0) # movzx eax, al
|
|
1052
1376
|
store_reg(EAX, dst)
|
|
1053
1377
|
end
|
|
1054
1378
|
|
|
1055
|
-
# A floating binary op (:fadd/:fsub/:fmul/:fdiv). The
|
|
1056
|
-
# into xmm0
|
|
1057
|
-
# mandatory prefix selects the scalar-single (F3,
|
|
1058
|
-
# (F2, size 8) form of the shared 0F <opcode>
|
|
1379
|
+
# A floating binary op (:fadd/:fsub/:fmul/:fdiv). The first operand is
|
|
1380
|
+
# loaded into xmm0, the second read straight out of its slot, and the
|
|
1381
|
+
# result stored back. The mandatory prefix selects the scalar-single (F3,
|
|
1382
|
+
# size 4) or scalar-double (F2, size 8) form of the shared 0F <opcode>
|
|
1383
|
+
# encoding, and all four take an "xmm, xmm/m" operand pair — so the memory
|
|
1384
|
+
# form is the same instruction with a different ModR/M, one shorter than
|
|
1385
|
+
# staging the operand through xmm1 would be.
|
|
1386
|
+
#
|
|
1387
|
+
# The operands are never exchanged the way a commutative integer op's are:
|
|
1388
|
+
# SSE arithmetic takes a NaN result's payload from a particular source
|
|
1389
|
+
# operand, so the two orders are not interchangeable even where the
|
|
1390
|
+
# arithmetic itself is.
|
|
1059
1391
|
def emit_float_binary(dst, a, b, size, opcode)
|
|
1060
|
-
|
|
1061
|
-
load_xmm(XMM1, b, size)
|
|
1392
|
+
load_float_operands(a, b, size)
|
|
1062
1393
|
emit(size == 8 ? 0xF2 : 0xF3)
|
|
1063
1394
|
emit(0x0F, opcode)
|
|
1064
|
-
|
|
1395
|
+
emit_float_rm(b)
|
|
1065
1396
|
store_xmm(XMM0, dst, size)
|
|
1066
1397
|
end
|
|
1067
1398
|
|
|
1399
|
+
# Stages a floating instruction's operands: the first into xmm0, and the
|
|
1400
|
+
# second into xmm1 only when its slot was never written (a transient left
|
|
1401
|
+
# in a register, which no memory operand can name). The rescue happens
|
|
1402
|
+
# *before* xmm0 is filled, because the value being rescued is the one
|
|
1403
|
+
# sitting in xmm0 — this is the vector-file version of the ordering rule
|
|
1404
|
+
# #load_binary_operands follows.
|
|
1405
|
+
def load_float_operands(a, b, size)
|
|
1406
|
+
refresh_slot_residency
|
|
1407
|
+
load_xmm(XMM1, b, size) unless slot_written?(b)
|
|
1408
|
+
load_xmm(XMM0, a, size)
|
|
1409
|
+
end
|
|
1410
|
+
|
|
1411
|
+
# The r/m half of a floating instruction whose reg half is xmm0: b's slot
|
|
1412
|
+
# when it was written, xmm1 when #load_float_operands had to stage it.
|
|
1413
|
+
def emit_float_rm(b)
|
|
1414
|
+
if slot_written?(b)
|
|
1415
|
+
emit_modrm_rbp_disp(XMM0, slot_disp(b))
|
|
1416
|
+
else
|
|
1417
|
+
emit(modrm_reg(XMM0, XMM1))
|
|
1418
|
+
end
|
|
1419
|
+
end
|
|
1420
|
+
|
|
1068
1421
|
# A floating comparison (:feq..:fge), materialized into eax as an int 0/1
|
|
1069
1422
|
# like an integer comparison but through ucomiss/ucomisd, whose result is
|
|
1070
1423
|
# read from the flags with NaN awareness. The ordering ops reduce to a
|
|
@@ -1109,15 +1462,15 @@ module Rubycc
|
|
|
1109
1462
|
store_reg(EAX, dst)
|
|
1110
1463
|
end
|
|
1111
1464
|
|
|
1112
|
-
# ucomiss xmm0,
|
|
1113
|
-
# scalar compare that sets ZF/PF/CF for the setcc that follows.
|
|
1114
|
-
#
|
|
1465
|
+
# ucomiss xmm0, xmm/m32 (size 4) / ucomisd (size 8, a 66 prefix), the
|
|
1466
|
+
# ordered scalar compare that sets ZF/PF/CF for the setcc that follows.
|
|
1467
|
+
# The first operand is loaded into xmm0 and the second named where it
|
|
1468
|
+
# lives, exactly as #emit_float_binary does.
|
|
1115
1469
|
def emit_ucomis(a, b, size)
|
|
1116
|
-
|
|
1117
|
-
load_xmm(XMM1, b, size)
|
|
1470
|
+
load_float_operands(a, b, size)
|
|
1118
1471
|
emit(0x66) if size == 8 # ucomisd operand-size prefix
|
|
1119
1472
|
emit(0x0F, 0x2E) # ucomiss/ucomisd
|
|
1120
|
-
|
|
1473
|
+
emit_float_rm(b)
|
|
1121
1474
|
end
|
|
1122
1475
|
|
|
1123
1476
|
# :itof — cvtsi2ss/cvtsi2sd converts a signed integer in a GP register to
|
|
@@ -1177,18 +1530,41 @@ module Rubycc
|
|
|
1177
1530
|
# single/double form; the rbp-relative ModR/M reuses the integer helper,
|
|
1178
1531
|
# the xmm number sitting in its reg field (0..7 for the scratch pair and the
|
|
1179
1532
|
# eight argument registers alike, all within the 3-bit field, so no REX.R).
|
|
1533
|
+
#
|
|
1534
|
+
# As with #load_reg, the move disappears when `xmm` already holds this
|
|
1535
|
+
# slot at this width and becomes a register-to-register move when another
|
|
1536
|
+
# vector register does. The register form is `movaps` (0F 28 /r), which
|
|
1537
|
+
# copies all 128 bits: that is exactly what a reload would have produced,
|
|
1538
|
+
# since a movss/movsd *from memory* zeroes the bits above the value it
|
|
1539
|
+
# loads, so the source register's upper half is already what the
|
|
1540
|
+
# destination's would be.
|
|
1180
1541
|
def load_xmm(xmm, vreg, size)
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1542
|
+
refresh_slot_residency
|
|
1543
|
+
return if slot_resident_in_vector?(xmm, vreg, size)
|
|
1544
|
+
|
|
1545
|
+
source = vector_register_holding_slot(vreg, size)
|
|
1546
|
+
if source
|
|
1547
|
+
emit(0x0F, 0x28, modrm_reg(xmm, source)) # movaps xmm, xmm_source
|
|
1548
|
+
else
|
|
1549
|
+
emit(size == 8 ? 0xF2 : 0xF3)
|
|
1550
|
+
emit(0x0F, 0x10)
|
|
1551
|
+
emit_modrm_rbp_disp(xmm, slot_disp(vreg))
|
|
1552
|
+
end
|
|
1553
|
+
note_slot_loaded_to_vector(xmm, vreg, size)
|
|
1184
1554
|
end
|
|
1185
1555
|
|
|
1186
1556
|
# movss/movsd [rbp + disp], xmm: stores an xmm register into a slot, the
|
|
1187
1557
|
# counterpart of #load_xmm (opcode 0x11 writes memory from the register).
|
|
1188
1558
|
def store_xmm(xmm, vreg, size)
|
|
1559
|
+
refresh_slot_residency
|
|
1560
|
+
if @transient[vreg]
|
|
1561
|
+
note_slot_loaded_to_vector(xmm, vreg, size)
|
|
1562
|
+
return
|
|
1563
|
+
end
|
|
1189
1564
|
emit(size == 8 ? 0xF2 : 0xF3)
|
|
1190
1565
|
emit(0x0F, 0x11)
|
|
1191
1566
|
emit_modrm_rbp_disp(xmm, slot_disp(vreg))
|
|
1567
|
+
note_slot_stored_from_vector(xmm, vreg, size)
|
|
1192
1568
|
end
|
|
1193
1569
|
|
|
1194
1570
|
# Emits "jmp rel32" with a zero placeholder and records a fixup so the
|
|
@@ -1198,9 +1574,20 @@ module Rubycc
|
|
|
1198
1574
|
record_fixup(label_id)
|
|
1199
1575
|
end
|
|
1200
1576
|
|
|
1577
|
+
# The condition is tested where it lives unless it is already in eax: a
|
|
1578
|
+
# "cmp dword [rbp+disp], 0" — or "cmp r32, 0" for a promoted condition —
|
|
1579
|
+
# reads the same low four bytes "test eax, eax" would have, and saves the
|
|
1580
|
+
# load. (The 83 /7 form takes a sign-extended imm8, which is all a
|
|
1581
|
+
# comparison against zero needs.)
|
|
1201
1582
|
def emit_jump_if_zero(cond, label_id)
|
|
1202
|
-
|
|
1203
|
-
|
|
1583
|
+
refresh_slot_residency
|
|
1584
|
+
if rm_operand?(cond) && !slot_resident_in?(EAX, cond)
|
|
1585
|
+
emit_vreg_rm([0x83], cond, reg: 7)
|
|
1586
|
+
emit(0x00) # cmp r/m32, 0
|
|
1587
|
+
else
|
|
1588
|
+
load_reg(EAX, cond)
|
|
1589
|
+
emit(0x85, 0xC0) # test eax, eax
|
|
1590
|
+
end
|
|
1204
1591
|
emit(0x0F, 0x84) # je rel32
|
|
1205
1592
|
record_fixup(label_id)
|
|
1206
1593
|
end
|
|
@@ -1227,74 +1614,345 @@ module Rubycc
|
|
|
1227
1614
|
# A size of 8 materializes a full 64-bit immediate (movabs rax, imm64),
|
|
1228
1615
|
# needed for a `long`/`unsigned long` constant that does not fit — or
|
|
1229
1616
|
# would not sign-extend correctly — in 32 bits. Otherwise a 32-bit
|
|
1230
|
-
# "mov
|
|
1231
|
-
# a 4-byte-or-narrower type) and zeroes the upper half
|
|
1617
|
+
# "mov r32, imm32" suffices: it fills the low 32 bits (the whole value of
|
|
1618
|
+
# a 4-byte-or-narrower type) and zeroes the register's upper half.
|
|
1619
|
+
#
|
|
1620
|
+
# "mov r64/r32, imm" (B8+rd) names its destination in the opcode's low
|
|
1621
|
+
# three bits, extended by REX.B, so a promoted destination is written
|
|
1622
|
+
# directly and no move follows (#result_register).
|
|
1232
1623
|
def emit_const(dst, value, size = nil)
|
|
1624
|
+
refresh_slot_residency
|
|
1625
|
+
target = result_register(dst)
|
|
1233
1626
|
if size == 8
|
|
1234
|
-
|
|
1627
|
+
emit_rex(rex_w: true, rm: target) # REX.W (+ REX.B)
|
|
1628
|
+
emit(0xB8 | (target & 7)) # movabs r64, imm64
|
|
1235
1629
|
emit_bytes([value & 0xFFFFFFFFFFFFFFFF].pack("Q<"))
|
|
1236
1630
|
else
|
|
1237
|
-
|
|
1631
|
+
emit_rex(rm: target) # REX.B for r12..r15
|
|
1632
|
+
emit(0xB8 | (target & 7)) # mov r32, imm32
|
|
1238
1633
|
emit_bytes([value & 0xFFFFFFFF].pack("L<"))
|
|
1239
1634
|
end
|
|
1240
|
-
|
|
1635
|
+
# Either form is one "mov r, imm" writing the opcode's own register.
|
|
1636
|
+
store_result(target, dst, only_wrote: target)
|
|
1241
1637
|
end
|
|
1242
1638
|
|
|
1243
1639
|
# A size of 8 prefixes REX.W so the operation runs on the full 64-bit
|
|
1244
|
-
# rax
|
|
1245
|
-
#
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1640
|
+
# rax (pointer arithmetic and index scaling); otherwise it stays a 32-bit
|
|
1641
|
+
# int operation. The opcode bytes are identical either way.
|
|
1642
|
+
#
|
|
1643
|
+
# `memory_bytes`, when the op has such a form, is the opcode of its
|
|
1644
|
+
# "register, r/m" direction, which #emit_vreg_rm then points at b's own
|
|
1645
|
+
# slot or promoted register — so only `a` is ever loaded and the whole
|
|
1646
|
+
# instruction costs one load plus itself. `opcode_bytes` is the fallback
|
|
1647
|
+
# "eax, ecx" encoding, used by the shifts, whose count has to reach cl and
|
|
1648
|
+
# cannot be a memory operand at all. `commutative` lets the two be
|
|
1649
|
+
# exchanged, which is worth doing when it makes the one remaining load
|
|
1650
|
+
# free — or when it puts a promoted destination on the left, where the
|
|
1651
|
+
# result can be accumulated in place (#emit_promoted_binary).
|
|
1652
|
+
def emit_binary(dst, a, b, opcode_bytes, size = nil, memory_bytes: nil, commutative: false)
|
|
1653
|
+
refresh_slot_residency
|
|
1654
|
+
a, b = b, a if commutative && swap_binary_operands?(dst, a, b)
|
|
1655
|
+
if memory_bytes && @promoted[dst] && (dst == a || dst != b)
|
|
1656
|
+
emit_promoted_binary(dst, a, b, memory_bytes, size)
|
|
1657
|
+
elsif memory_bytes && rm_operand?(b)
|
|
1658
|
+
load_reg(EAX, a)
|
|
1659
|
+
emit_vreg_rm(memory_bytes, b, rex_w: size == 8)
|
|
1660
|
+
store_reg(EAX, dst)
|
|
1661
|
+
else
|
|
1662
|
+
load_binary_operands(a, b, commutative: commutative)
|
|
1663
|
+
emit(0x48) if size == 8
|
|
1664
|
+
opcode_bytes.each { |byte| emit(byte) }
|
|
1665
|
+
store_reg(EAX, dst)
|
|
1666
|
+
end
|
|
1667
|
+
end
|
|
1668
|
+
|
|
1669
|
+
# The "register, r/m" direction of a binary op with its reg field aimed
|
|
1670
|
+
# straight at the callee-saved register `dst` was promoted into, so the
|
|
1671
|
+
# result is written where it lives and no move follows.
|
|
1672
|
+
#
|
|
1673
|
+
# `a` is brought into that register first, a move that disappears when
|
|
1674
|
+
# `dst` and `a` are the same value — the shape "i = i + 1" and "sum += x"
|
|
1675
|
+
# take once the single-use copies are forwarded, and the reason this path
|
|
1676
|
+
# exists. The caller has ruled out the one arrangement the move would
|
|
1677
|
+
# break: dst == b with dst != a, whose b it would overwrite before the
|
|
1678
|
+
# arithmetic could read it.
|
|
1679
|
+
#
|
|
1680
|
+
# Only the promoted register is written, and the residency table can name
|
|
1681
|
+
# none of them (PROMOTION_REGISTERS is disjoint from the scratch,
|
|
1682
|
+
# argument and return registers every entry is keyed by), so every
|
|
1683
|
+
# residency in flight survives; #note_register_clobbered still drops the
|
|
1684
|
+
# one the `load_reg` above may have recorded against the target itself.
|
|
1685
|
+
def emit_promoted_binary(dst, a, b, memory_bytes, size)
|
|
1686
|
+
target = @promoted[dst]
|
|
1687
|
+
load_reg(target, a) unless dst == a
|
|
1688
|
+
if rm_operand?(b)
|
|
1689
|
+
emit_vreg_rm(memory_bytes, b, reg: target, rex_w: size == 8)
|
|
1690
|
+
else
|
|
1691
|
+
# A transient has neither slot nor register of its own; it is still
|
|
1692
|
+
# in whichever scratch register its producer computed it in.
|
|
1693
|
+
source = register_holding_slot(b)
|
|
1694
|
+
unless source
|
|
1695
|
+
load_reg(ECX, b)
|
|
1696
|
+
source = ECX
|
|
1697
|
+
end
|
|
1698
|
+
emit_register_rm(memory_bytes, source, reg: target, rex_w: size == 8)
|
|
1699
|
+
end
|
|
1700
|
+
note_register_clobbered(target)
|
|
1701
|
+
end
|
|
1702
|
+
|
|
1703
|
+
# Whether `vreg` may be named as an instruction's r/m operand, and so
|
|
1704
|
+
# read without being loaded first. A value in a slot is named [rbp +
|
|
1705
|
+
# disp] and a promoted one register-direct; only a transient is neither,
|
|
1706
|
+
# its value never having reached a slot and its register being whichever
|
|
1707
|
+
# one its producer happened to use.
|
|
1708
|
+
def rm_operand?(vreg)
|
|
1709
|
+
!@transient[vreg]
|
|
1710
|
+
end
|
|
1711
|
+
|
|
1712
|
+
# Emits an instruction whose r/m operand is wherever `vreg` lives: its
|
|
1713
|
+
# stack slot, or — for a promoted value, which has no slot at all — the
|
|
1714
|
+
# callee-saved register it owns, named register-direct (mod = 11). `reg`
|
|
1715
|
+
# is the ModR/M reg field, a register number in a two-operand form and an
|
|
1716
|
+
# opcode extension in a group instruction. The caller must have asked
|
|
1717
|
+
# #rm_operand? first.
|
|
1718
|
+
def emit_vreg_rm(opcode_bytes, vreg, reg: EAX, rex_w: false)
|
|
1719
|
+
promoted = @promoted[vreg]
|
|
1720
|
+
if promoted
|
|
1721
|
+
emit_register_rm(opcode_bytes, promoted, reg: reg, rex_w: rex_w)
|
|
1722
|
+
else
|
|
1723
|
+
emit_slot_rm(opcode_bytes, vreg, reg: reg, rex_w: rex_w)
|
|
1724
|
+
end
|
|
1725
|
+
end
|
|
1726
|
+
|
|
1727
|
+
# Emits an instruction whose r/m operand is `vreg`'s stack slot: the REX
|
|
1728
|
+
# prefix the operand width and register numbers call for, the opcode
|
|
1729
|
+
# bytes, then a ModR/M whose reg field is `reg` and whose r/m field
|
|
1730
|
+
# addresses [rbp + slot].
|
|
1731
|
+
#
|
|
1732
|
+
# Reading an operand straight out of its slot is as correct as loading it
|
|
1733
|
+
# into a register first and is one instruction shorter. The slot is where
|
|
1734
|
+
# the spill-everything discipline keeps the value; nothing is emitted
|
|
1735
|
+
# between the load of the first operand and this that could write memory;
|
|
1736
|
+
# and the width the instruction reads (4 bytes, or 8 under REX.W) is
|
|
1737
|
+
# exactly the width the register form's arithmetic would have used, so the
|
|
1738
|
+
# value representation is honored unchanged — a narrow value's
|
|
1739
|
+
# indeterminate high half is never looked at either way.
|
|
1740
|
+
def emit_slot_rm(opcode_bytes, vreg, reg: EAX, rex_w: false)
|
|
1741
|
+
emit_rex(rex_w: rex_w, reg: reg)
|
|
1250
1742
|
opcode_bytes.each { |byte| emit(byte) }
|
|
1251
|
-
|
|
1743
|
+
emit_modrm_rbp_disp(reg & 7, slot_disp(vreg))
|
|
1744
|
+
end
|
|
1745
|
+
|
|
1746
|
+
# The register-direct counterpart of #emit_slot_rm: the same reg field
|
|
1747
|
+
# against an rm field that names register `rm` (mod = 11) rather than a
|
|
1748
|
+
# memory operand. This is how a promoted value is read in place. Two
|
|
1749
|
+
# encoding traps a memory operand has do not exist here — an rm of 100
|
|
1750
|
+
# names r12/rsp instead of introducing a SIB byte, and an rm of 101 names
|
|
1751
|
+
# r13/rbp instead of meaning "no base" — so REX.B is all r12..r15 need.
|
|
1752
|
+
def emit_register_rm(opcode_bytes, rm, reg: EAX, rex_w: false)
|
|
1753
|
+
emit_rex(rex_w: rex_w, reg: reg, rm: rm)
|
|
1754
|
+
opcode_bytes.each { |byte| emit(byte) }
|
|
1755
|
+
emit(0xC0 | ((reg & 7) << 3) | (rm & 7))
|
|
1756
|
+
end
|
|
1757
|
+
|
|
1758
|
+
# The REX prefix an instruction needs, emitted only when some field asks
|
|
1759
|
+
# for one. W widens the operation to 64 bits; R extends the ModR/M reg
|
|
1760
|
+
# field, X the SIB index field and B the ModR/M r/m (or SIB base, or
|
|
1761
|
+
# opcode-embedded) register — each supplying the high bit of a register
|
|
1762
|
+
# number 8..15 whose low three bits stay in the field itself.
|
|
1763
|
+
def emit_rex(rex_w: false, reg: 0, rm: 0, index: 0)
|
|
1764
|
+
rex = 0x40 | (rex_w ? 0x08 : 0) | (reg >= 8 ? 0x04 : 0) |
|
|
1765
|
+
(index >= 8 ? 0x02 : 0) | (rm >= 8 ? 0x01 : 0)
|
|
1766
|
+
emit(rex) unless rex == 0x40
|
|
1767
|
+
end
|
|
1768
|
+
|
|
1769
|
+
# Where an instruction that computes a general-register result should put
|
|
1770
|
+
# it: the callee-saved register `dst` was promoted into, so the value is
|
|
1771
|
+
# written home directly, or eax for a value that lives in a slot.
|
|
1772
|
+
def result_register(dst)
|
|
1773
|
+
@promoted[dst] || EAX
|
|
1774
|
+
end
|
|
1775
|
+
|
|
1776
|
+
# Completes such an instruction. A destination that lives in a slot still
|
|
1777
|
+
# needs the store; a promoted `dst` *is* `reg`, so the value is already
|
|
1778
|
+
# home and all that is left is telling the residency table what the bytes
|
|
1779
|
+
# just emitted did to it.
|
|
1780
|
+
#
|
|
1781
|
+
# **The default answer is to throw the table away.** Bytes have been
|
|
1782
|
+
# emitted since it was last known true — the caller's own instruction —
|
|
1783
|
+
# and nothing here can see which registers they wrote. Keeping the table
|
|
1784
|
+
# alive across them is #note_register_clobbered's exception, sound only
|
|
1785
|
+
# when those bytes wrote `reg` and nothing else the table can name; that
|
|
1786
|
+
# is a fact about one lowering's encoding, so the lowering is what states
|
|
1787
|
+
# it, by passing `only_wrote: reg`. Anything that says nothing gets the
|
|
1788
|
+
# safe reading, which costs an optimization and never correctness — and a
|
|
1789
|
+
# lowering that later grows a second scratch write has to come back to its
|
|
1790
|
+
# own claim rather than silently reviving a stale residency. All four
|
|
1791
|
+
# callers here claim the fast path today; the aarch64 backend, whose
|
|
1792
|
+
# #emit_alloca rounds its size in rax's counterpart and whose remainder
|
|
1793
|
+
# takes a scratch for the quotient, has two that cannot.
|
|
1794
|
+
#
|
|
1795
|
+
# "Nothing else the table can name" means none of rax, rcx, rdx, rsi, rdi,
|
|
1796
|
+
# r10, the argument registers or a promoted one — the registers #load_reg
|
|
1797
|
+
# is ever asked to fill, and so the only ones an entry can be keyed by.
|
|
1798
|
+
def store_result(reg, dst, only_wrote: nil)
|
|
1799
|
+
unless @promoted[dst]
|
|
1800
|
+
store_reg(reg, dst) # which discards a stale table itself, before anything else
|
|
1801
|
+
return
|
|
1802
|
+
end
|
|
1803
|
+
|
|
1804
|
+
if only_wrote == reg
|
|
1805
|
+
note_register_clobbered(reg)
|
|
1806
|
+
else
|
|
1807
|
+
refresh_slot_residency
|
|
1808
|
+
end
|
|
1809
|
+
end
|
|
1810
|
+
|
|
1811
|
+
# :scaled_add — dst <- base + index * element_size, the address a
|
|
1812
|
+
# subscript forms. `lea` (8D /r) computes an address rather than loading
|
|
1813
|
+
# from it, and its SIB byte carries the scale as a two-bit shift, so the
|
|
1814
|
+
# element-size multiply and the add to the base become one instruction
|
|
1815
|
+
# that touches no flags. REX.W makes it a 64-bit computation, which is
|
|
1816
|
+
# what a pointer needs.
|
|
1817
|
+
#
|
|
1818
|
+
# All three of the instruction's registers are free — base and index are
|
|
1819
|
+
# named independently in the SIB byte and the destination in the ModR/M
|
|
1820
|
+
# reg field — so a promoted value may be any of them and the whole address
|
|
1821
|
+
# is formed without a move. That freedom is what brings the three encoding
|
|
1822
|
+
# traps of the SIB byte into reach, none of which a pair of scratch
|
|
1823
|
+
# registers could ever have hit (Intel SDM Vol. 2A, Tables 2-5 and 2-3;
|
|
1824
|
+
# REX.B extends the base, REX.X the index and REX.R the destination):
|
|
1825
|
+
#
|
|
1826
|
+
# * a SIB **base** field of 101 with mod = 00 does not name rbp/r13 but
|
|
1827
|
+
# "no base register, disp32 follows", so those two take mod = 01 with
|
|
1828
|
+
# a zero disp8 instead — one byte for the register the encoding's
|
|
1829
|
+
# shorter form has spent on something else;
|
|
1830
|
+
# * a SIB base field of 100 does name rsp/r12 (it is the *ModR/M* rm
|
|
1831
|
+
# field where 100 means "a SIB byte follows"), so r12 as a base needs
|
|
1832
|
+
# nothing beyond its REX.B;
|
|
1833
|
+
# * a SIB **index** field of 100 means "no index" — but only at REX.X =
|
|
1834
|
+
# 0. With REX.X set it is r12, which is why r12 works as an index and
|
|
1835
|
+
# rsp, whose REX.X is 0 by construction, is the register that cannot.
|
|
1836
|
+
def emit_scaled_add(dst, base_vreg, index_vreg, element_size)
|
|
1837
|
+
base, index = address_operands(base_vreg, index_vreg)
|
|
1838
|
+
target = result_register(dst)
|
|
1839
|
+
emit_rex(rex_w: true, reg: target, index: index, rm: base)
|
|
1840
|
+
emit(0x8D) # lea r64, [base + index*scale]
|
|
1841
|
+
sib = (SIB_SCALES.fetch(element_size) << 6) | ((index & 7) << 3) | (base & 7)
|
|
1842
|
+
if (base & 7) == 5
|
|
1843
|
+
emit(0x44 | ((target & 7) << 3), sib, 0x00) # mod=01, rm=100 (SIB), disp8 = 0
|
|
1844
|
+
else
|
|
1845
|
+
emit(0x04 | ((target & 7) << 3), sib) # mod=00, rm=100 (SIB follows)
|
|
1846
|
+
end
|
|
1847
|
+
# `lea` writes its reg field; base and index are read (#address_operands
|
|
1848
|
+
# loaded them and accounted for that itself).
|
|
1849
|
+
store_result(target, dst, only_wrote: target)
|
|
1850
|
+
end
|
|
1851
|
+
|
|
1852
|
+
# Reports which register holds a scaled address's base and which its
|
|
1853
|
+
# index. A promoted operand is used where it already is; anything else is
|
|
1854
|
+
# loaded into a scratch register. Unlike an arithmetic opcode, `lea` names
|
|
1855
|
+
# its base and index independently, so either assignment encodes — which
|
|
1856
|
+
# also lets whichever operand is already resident keep the register it is
|
|
1857
|
+
# in when neither is promoted.
|
|
1858
|
+
def address_operands(base_vreg, index_vreg)
|
|
1859
|
+
refresh_slot_residency
|
|
1860
|
+
base = @promoted[base_vreg]
|
|
1861
|
+
index = @promoted[index_vreg]
|
|
1862
|
+
if base && index
|
|
1863
|
+
[base, index]
|
|
1864
|
+
elsif base
|
|
1865
|
+
load_reg(EAX, index_vreg)
|
|
1866
|
+
[base, EAX]
|
|
1867
|
+
elsif index
|
|
1868
|
+
load_reg(EAX, base_vreg)
|
|
1869
|
+
[EAX, index]
|
|
1870
|
+
elsif slot_resident_in?(EAX, index_vreg) && !slot_resident_in?(EAX, base_vreg)
|
|
1871
|
+
load_reg(ECX, base_vreg)
|
|
1872
|
+
load_reg(EAX, index_vreg)
|
|
1873
|
+
[ECX, EAX]
|
|
1874
|
+
else
|
|
1875
|
+
load_reg(EAX, base_vreg)
|
|
1876
|
+
load_reg(ECX, index_vreg)
|
|
1877
|
+
[EAX, ECX]
|
|
1878
|
+
end
|
|
1252
1879
|
end
|
|
1253
1880
|
|
|
1254
1881
|
# :mulhi — the unsigned high 64 bits of a 64x64 product, the piece a
|
|
1255
1882
|
# synthesized __int128 multiply needs beyond the low 64 that :mul gives.
|
|
1256
|
-
# `mul
|
|
1257
|
-
#
|
|
1258
|
-
#
|
|
1259
|
-
#
|
|
1260
|
-
#
|
|
1883
|
+
# `mul` (REX.W F7 /4) multiplies rax by its one operand — b's slot or
|
|
1884
|
+
# promoted register, or rcx when it has neither — into rdx:rax; the high
|
|
1885
|
+
# half lands in rdx, which is stored to the destination. The one-operand
|
|
1886
|
+
# `mul` is the unsigned multiply, so this is the unsigned high product
|
|
1887
|
+
# regardless of the operands' declared signedness (the low 64 bits, and
|
|
1888
|
+
# hence a full 128-bit low result, are identical for signed and unsigned).
|
|
1261
1889
|
def emit_mulhi(dst, a, b)
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1890
|
+
refresh_slot_residency
|
|
1891
|
+
a, b = b, a if prefer_swapped_operands?(a, b)
|
|
1892
|
+
if rm_operand?(b)
|
|
1893
|
+
load_reg(EAX, a)
|
|
1894
|
+
emit_vreg_rm([0xF7], b, reg: 4, rex_w: true) # mul qword r/m64 (/4)
|
|
1895
|
+
else
|
|
1896
|
+
load_binary_operands(a, b, commutative: true)
|
|
1897
|
+
emit(0x48, 0xF7, 0xE1) # mul rcx -> rdx:rax = rax * rcx
|
|
1898
|
+
end
|
|
1265
1899
|
store_reg(EDX, dst) # dst = high 64 bits
|
|
1266
1900
|
end
|
|
1267
1901
|
|
|
1268
|
-
# A size of 8 does a 64-bit signed division (REX.W cqo + REX.W idiv
|
|
1269
|
-
#
|
|
1902
|
+
# A size of 8 does a 64-bit signed division (REX.W cqo + REX.W idiv), used
|
|
1903
|
+
# for pointer differences; otherwise the 32-bit int division. The divisor
|
|
1904
|
+
# is the one-operand `idiv`'s r/m, which is b's slot wherever it can be.
|
|
1270
1905
|
def emit_divmod(dst, a, b, result_reg, size = nil)
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
emit(0x48, 0xF7, 0xF9) # idiv rcx
|
|
1276
|
-
else
|
|
1277
|
-
emit(0x99) # cdq: sign-extend eax into edx:eax
|
|
1278
|
-
emit(0xF7, 0xF9) # idiv ecx
|
|
1279
|
-
end
|
|
1906
|
+
divisor_in_register = load_dividend_and_divisor(a, b)
|
|
1907
|
+
emit(0x48) if size == 8 # REX.W turns cdq into cqo
|
|
1908
|
+
emit(0x99) # cdq/cqo: sign-extend eax/rax into edx:eax / rdx:rax
|
|
1909
|
+
emit_divisor_operand(divisor_in_register, b, 7, size) # idiv (/7)
|
|
1280
1910
|
store_reg(result_reg, dst)
|
|
1281
1911
|
end
|
|
1282
1912
|
|
|
1283
1913
|
# Unsigned division/remainder. Unlike the signed form, the high half of
|
|
1284
1914
|
# the dividend is zeroed (xor edx, edx, which also clears the upper 32
|
|
1285
1915
|
# bits of rdx for the 64-bit case) rather than sign-extended, and the
|
|
1286
|
-
# unsigned `div` opcode is used. size 8 divides the full 64-bit rax by
|
|
1287
|
-
#
|
|
1916
|
+
# unsigned `div` opcode is used. size 8 divides the full 64-bit rax by the
|
|
1917
|
+
# divisor; otherwise the 32-bit division. Quotient in eax, remainder in edx.
|
|
1288
1918
|
def emit_udivmod(dst, a, b, result_reg, size = nil)
|
|
1289
|
-
|
|
1290
|
-
load_reg(ECX, b)
|
|
1919
|
+
divisor_in_register = load_dividend_and_divisor(a, b)
|
|
1291
1920
|
emit(0x31, 0xD2) # xor edx, edx
|
|
1292
|
-
|
|
1293
|
-
|
|
1921
|
+
emit_divisor_operand(divisor_in_register, b, 6, size) # div (/6)
|
|
1922
|
+
store_reg(result_reg, dst)
|
|
1923
|
+
end
|
|
1924
|
+
|
|
1925
|
+
# Stages a division's operands: the dividend always into eax, the divisor
|
|
1926
|
+
# into ecx only when it is a transient, which the one-operand `div`/`idiv`
|
|
1927
|
+
# can name no other way. Returns true when the divisor is in ecx. Both
|
|
1928
|
+
# loads happen before the sign-extension step that follows, which writes
|
|
1929
|
+
# edx and must not be undone.
|
|
1930
|
+
#
|
|
1931
|
+
# The dividend and the quotient/remainder pair are fixed at rax and
|
|
1932
|
+
# rdx:rax by the instruction itself, so this is one of the places a
|
|
1933
|
+
# promoted destination changes nothing; a promoted *divisor*, though, is
|
|
1934
|
+
# named in place like any other r/m operand, and rdx cannot collide with
|
|
1935
|
+
# it (PROMOTION_REGISTERS holds none of the scratch registers).
|
|
1936
|
+
def load_dividend_and_divisor(a, b)
|
|
1937
|
+
if rm_operand?(b)
|
|
1938
|
+
load_reg(EAX, a)
|
|
1939
|
+
false
|
|
1294
1940
|
else
|
|
1295
|
-
|
|
1941
|
+
load_binary_operands(a, b)
|
|
1942
|
+
true
|
|
1943
|
+
end
|
|
1944
|
+
end
|
|
1945
|
+
|
|
1946
|
+
# The r/m operand of the one-operand `div`/`idiv` group (F7 /6 unsigned,
|
|
1947
|
+
# /7 signed): ecx when #load_dividend_and_divisor put it there, and b's
|
|
1948
|
+
# slot or promoted register otherwise.
|
|
1949
|
+
def emit_divisor_operand(in_register, b, extension, size)
|
|
1950
|
+
if in_register
|
|
1951
|
+
emit(0x48) if size == 8
|
|
1952
|
+
emit(0xF7, 0xC0 | (extension << 3) | ECX)
|
|
1953
|
+
else
|
|
1954
|
+
emit_vreg_rm([0xF7], b, reg: extension, rex_w: size == 8)
|
|
1296
1955
|
end
|
|
1297
|
-
store_reg(result_reg, dst)
|
|
1298
1956
|
end
|
|
1299
1957
|
|
|
1300
1958
|
# mov r64, [rbp + disp]: slots are always moved 64 bits at a time so a
|
|
@@ -1303,17 +1961,146 @@ module Rubycc
|
|
|
1303
1961
|
# zero the upper 32 bits of rax, so the slot's high half is already zero.
|
|
1304
1962
|
# The REX prefix carries W (64-bit operand) plus R for r8/r9 (>= 8), whose
|
|
1305
1963
|
# low 3 bits go into the ModR/M reg field.
|
|
1964
|
+
#
|
|
1965
|
+
# The load disappears when `reg` already holds this slot's value and
|
|
1966
|
+
# becomes a register-to-register move when another scratch register does
|
|
1967
|
+
# (SlotResidency decides both). Either way `reg` ends up with the same 64
|
|
1968
|
+
# bits the memory form would have fetched — the slot was written 64 bits
|
|
1969
|
+
# at a time and it is those bits being reused — so the value
|
|
1970
|
+
# representation above is untouched, and a narrow value's high half is as
|
|
1971
|
+
# indeterminate (or as zero) as it was before.
|
|
1306
1972
|
def load_reg(reg, vreg)
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1973
|
+
refresh_slot_residency
|
|
1974
|
+
promoted = @promoted[vreg]
|
|
1975
|
+
if promoted
|
|
1976
|
+
# There is no slot to read: this value has been in `promoted` since
|
|
1977
|
+
# the prologue and stays there until the function returns, so the
|
|
1978
|
+
# load is a register-to-register move — or nothing at all when the
|
|
1979
|
+
# caller happens to want it where it already is. The move writes
|
|
1980
|
+
# `reg` and touches no memory, which is exactly what the residency
|
|
1981
|
+
# table has to be told (see SlotResidency#note_register_clobbered).
|
|
1982
|
+
emit_reg_move(reg, promoted) unless reg == promoted
|
|
1983
|
+
note_register_clobbered(reg)
|
|
1984
|
+
return
|
|
1985
|
+
end
|
|
1986
|
+
return if slot_resident_in?(reg, vreg)
|
|
1987
|
+
|
|
1988
|
+
source = register_holding_slot(vreg)
|
|
1989
|
+
if source
|
|
1990
|
+
emit_reg_move(reg, source)
|
|
1991
|
+
else
|
|
1992
|
+
emit(0x48 | (reg >= 8 ? 0x04 : 0)) # REX.W (+ REX.R for r8/r9)
|
|
1993
|
+
emit(0x8B)
|
|
1994
|
+
emit_modrm_rbp_disp(reg & 7, slot_disp(vreg))
|
|
1995
|
+
end
|
|
1996
|
+
note_slot_loaded(reg, vreg)
|
|
1310
1997
|
end
|
|
1311
1998
|
|
|
1312
1999
|
# mov [rbp + disp], r64. See load_reg for the 64-bit and REX rationale.
|
|
2000
|
+
# The store itself is never skipped: the slot is the value's home, and
|
|
2001
|
+
# nothing here knows whether a later branch reaches a reader by a path
|
|
2002
|
+
# that goes nowhere near this register.
|
|
1313
2003
|
def store_reg(reg, vreg)
|
|
2004
|
+
refresh_slot_residency
|
|
2005
|
+
promoted = @promoted[vreg]
|
|
2006
|
+
if promoted
|
|
2007
|
+
# The value's home is a register, so the store is a move into it. No
|
|
2008
|
+
# slot is written and no scratch register can be describing one (a
|
|
2009
|
+
# promoted vreg is never recorded), so every residency in flight is
|
|
2010
|
+
# still true — it is only the emitted bytes that have to be accounted
|
|
2011
|
+
# for (SlotResidency#note_slots_undisturbed).
|
|
2012
|
+
emit_reg_move(promoted, reg) unless reg == promoted
|
|
2013
|
+
note_slots_undisturbed
|
|
2014
|
+
return
|
|
2015
|
+
end
|
|
2016
|
+
if @transient[vreg]
|
|
2017
|
+
# The value's only reader is the next instruction, which will find it
|
|
2018
|
+
# here; the slot itself is never named again, so nothing is written.
|
|
2019
|
+
note_slot_loaded(reg, vreg)
|
|
2020
|
+
return
|
|
2021
|
+
end
|
|
1314
2022
|
emit(0x48 | (reg >= 8 ? 0x04 : 0)) # REX.W (+ REX.R for r8/r9)
|
|
1315
2023
|
emit(0x89)
|
|
1316
2024
|
emit_modrm_rbp_disp(reg & 7, slot_disp(vreg))
|
|
2025
|
+
note_slot_stored(reg, vreg)
|
|
2026
|
+
end
|
|
2027
|
+
|
|
2028
|
+
# Whether `vreg`'s slot may be named as an instruction's memory operand.
|
|
2029
|
+
# It may not when the value never reached it: a transient is left in the
|
|
2030
|
+
# register its producer computed it in, and a promoted value lives in a
|
|
2031
|
+
# register of its own for the whole function, so in both cases the slot
|
|
2032
|
+
# holds nothing. The test is on the two sets, not on what happens to be
|
|
2033
|
+
# resident, so it does not depend on how far into an instruction it is
|
|
2034
|
+
# asked.
|
|
2035
|
+
#
|
|
2036
|
+
# Only the floating ops ask any more; the integer ones ask #rm_operand?
|
|
2037
|
+
# instead, a promoted value being nameable there as a register even though
|
|
2038
|
+
# its slot is not. The difference does not arise in practice — a value the
|
|
2039
|
+
# vector register file touches is refused promotion outright
|
|
2040
|
+
# (IR::Promotion::VECTOR_OPS), so a floating operand is only ever a slot or
|
|
2041
|
+
# a transient — and the stricter test is the one to ask on a path that has
|
|
2042
|
+
# no register form to fall back to but xmm1.
|
|
2043
|
+
def slot_written?(vreg)
|
|
2044
|
+
!@transient[vreg] && !@promoted[vreg]
|
|
2045
|
+
end
|
|
2046
|
+
|
|
2047
|
+
# mov r64, r64 — the register-to-register form of #load_reg's mov, for a
|
|
2048
|
+
# value that is already in another scratch register or that lives in a
|
|
2049
|
+
# promoted one. REX.W widens it, REX.R extends the source (the ModR/M reg
|
|
2050
|
+
# field) and REX.B the destination (the rm field), so r8/r9 and r12..r15
|
|
2051
|
+
# work on either side. The ModR/M is register-direct (mod = 11), where an
|
|
2052
|
+
# rm of 100 names r12 rather than selecting a SIB byte, so no promoted
|
|
2053
|
+
# register needs a special case the way a memory operand's base would.
|
|
2054
|
+
def emit_reg_move(dst, src)
|
|
2055
|
+
emit(0x48 | (src >= 8 ? 0x04 : 0) | (dst >= 8 ? 0x01 : 0))
|
|
2056
|
+
emit(0x89, 0xC0 | ((src & 7) << 3) | (dst & 7))
|
|
2057
|
+
end
|
|
2058
|
+
|
|
2059
|
+
# Loads a two-operand instruction's operands into eax and ecx.
|
|
2060
|
+
#
|
|
2061
|
+
# Which one is fetched first stops being arbitrary once #load_reg can
|
|
2062
|
+
# reuse a resident value: if `b` is the value sitting in eax, loading `a`
|
|
2063
|
+
# there first would throw it away and force `b` to be re-read from memory.
|
|
2064
|
+
# Fetching ecx first instead keeps it, as a register move. A `commutative`
|
|
2065
|
+
# op can do better still — swapping the two makes the resident operand
|
|
2066
|
+
# eax's, so nothing is moved at all — and is safe to swap precisely
|
|
2067
|
+
# because the opcode's two operands are interchangeable (this is not true
|
|
2068
|
+
# of :sub or of the shifts, whose count must reach cl).
|
|
2069
|
+
def load_binary_operands(a, b, commutative: false)
|
|
2070
|
+
refresh_slot_residency
|
|
2071
|
+
if commutative && prefer_swapped_operands?(a, b)
|
|
2072
|
+
a, b = b, a
|
|
2073
|
+
elsif slot_resident_in?(EAX, b) && !slot_resident_in?(EAX, a)
|
|
2074
|
+
# Fetch ecx first: eax is where b is, and loading a would lose it —
|
|
2075
|
+
# which for a transient b would lose it for good, its slot never
|
|
2076
|
+
# having been written.
|
|
2077
|
+
load_reg(ECX, b)
|
|
2078
|
+
end
|
|
2079
|
+
load_reg(EAX, a)
|
|
2080
|
+
load_reg(ECX, b)
|
|
2081
|
+
end
|
|
2082
|
+
|
|
2083
|
+
# Whether a commutative op should exchange its operands. A promoted
|
|
2084
|
+
# destination outranks everything else: "sum = x + sum" is the same
|
|
2085
|
+
# addition as "sum = sum + x", and only the second can be accumulated in
|
|
2086
|
+
# place (#emit_promoted_binary), which saves a move whatever the operands
|
|
2087
|
+
# cost. With that settled either way, the older question stands alone.
|
|
2088
|
+
def swap_binary_operands?(dst, a, b)
|
|
2089
|
+
return dst == b && dst != a if @promoted[dst]
|
|
2090
|
+
|
|
2091
|
+
prefer_swapped_operands?(a, b)
|
|
2092
|
+
end
|
|
2093
|
+
|
|
2094
|
+
# Whether a commutative op is better off with its operands exchanged.
|
|
2095
|
+
# Two cases want it, and they are one case seen twice: whichever operand
|
|
2096
|
+
# is already in eax should be the one taken from a register, leaving the
|
|
2097
|
+
# other free to be read where it lives. An operand that can be named
|
|
2098
|
+
# neither in a slot nor in a promoted register (a transient) has to be
|
|
2099
|
+
# that one, since no r/m field can reach it.
|
|
2100
|
+
def prefer_swapped_operands?(a, b)
|
|
2101
|
+
return false unless rm_operand?(a)
|
|
2102
|
+
|
|
2103
|
+
!rm_operand?(b) || (slot_resident_in?(EAX, b) && !slot_resident_in?(EAX, a))
|
|
1317
2104
|
end
|
|
1318
2105
|
|
|
1319
2106
|
def slot_disp(vreg)
|