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
data/lib/rubycc/ir/generator.rb
CHANGED
|
@@ -2092,6 +2092,8 @@ module Rubycc
|
|
|
2092
2092
|
gen_builtin_constant_p(node)
|
|
2093
2093
|
when Front::AST::BuiltinBitScan
|
|
2094
2094
|
gen_builtin_bit_scan(node)
|
|
2095
|
+
when Front::AST::BuiltinPopcount
|
|
2096
|
+
gen_builtin_popcount(node)
|
|
2095
2097
|
when Front::AST::BuiltinOverflow
|
|
2096
2098
|
gen_builtin_overflow(node)
|
|
2097
2099
|
when Front::AST::BuiltinAtomic
|
|
@@ -2418,11 +2420,12 @@ module Rubycc
|
|
|
2418
2420
|
[dst, Type::Int]
|
|
2419
2421
|
end
|
|
2420
2422
|
|
|
2421
|
-
# "__builtin_ctz/
|
|
2422
|
-
# (clz) zero bits, as an int. The operand is converted to the
|
|
2423
|
-
# integer of the builtin's width (4 or 8 bytes), then a single
|
|
2424
|
-
# lowers to bsf (forward/ctz) or bsr-based (reverse/clz)
|
|
2425
|
-
# zero operand is undefined behavior (gcc), so no zero
|
|
2423
|
+
# "__builtin_ctz/clz(x)", in any spelling: counts x's trailing (ctz) or
|
|
2424
|
+
# leading (clz) zero bits, as an int. The operand is converted to the
|
|
2425
|
+
# unsigned integer of the builtin's width (4 or 8 bytes), then a single
|
|
2426
|
+
# :bit_scan op lowers to bsf (forward/ctz) or bsr-based (reverse/clz)
|
|
2427
|
+
# hardware. A zero operand is undefined behavior (gcc), so no zero
|
|
2428
|
+
# handling is emitted.
|
|
2426
2429
|
def gen_builtin_bit_scan(node)
|
|
2427
2430
|
value, type = gen_value(node.operand)
|
|
2428
2431
|
unless type.integer?
|
|
@@ -2435,6 +2438,24 @@ module Rubycc
|
|
|
2435
2438
|
[dst, Type::Int]
|
|
2436
2439
|
end
|
|
2437
2440
|
|
|
2441
|
+
# "__builtin_popcount/popcountl/popcountll(x)": counts x's set bits, as an
|
|
2442
|
+
# int. The operand travels the same path a bit scan's does — converted to
|
|
2443
|
+
# the unsigned integer of the builtin's width, so a narrower or signed
|
|
2444
|
+
# argument is widened exactly once and the count runs over that width and
|
|
2445
|
+
# no other — and then one :popcount op, which each backend expands.
|
|
2446
|
+
# Every operand value is defined here, zero included (it counts 0).
|
|
2447
|
+
def gen_builtin_popcount(node)
|
|
2448
|
+
value, type = gen_value(node.operand)
|
|
2449
|
+
unless type.integer?
|
|
2450
|
+
error_at(node.operand.token, "argument to a bit-count builtin is not of integer type")
|
|
2451
|
+
end
|
|
2452
|
+
value = convert(value, from: type, to: node.width == 8 ? Type::ULong : Type::UInt,
|
|
2453
|
+
token: node.token)
|
|
2454
|
+
dst = new_vreg
|
|
2455
|
+
emit(:popcount, dst: dst, a: value, size: node.width)
|
|
2456
|
+
[dst, Type::Int]
|
|
2457
|
+
end
|
|
2458
|
+
|
|
2438
2459
|
# "__builtin_add/sub/mul_overflow(a, b, res)": computes "a op b" with
|
|
2439
2460
|
# infinite precision, stores that result converted to *res (wrapping or
|
|
2440
2461
|
# truncating exactly as an assignment to that type would, overflow or not),
|
|
@@ -2838,6 +2859,15 @@ module Rubycc
|
|
|
2838
2859
|
if type.float? && type.size == 4
|
|
2839
2860
|
error_at(token, "second argument to 'va_arg' is of promotable type '#{type}'")
|
|
2840
2861
|
end
|
|
2862
|
+
# A `long double` argument is passed in the target's own long-double
|
|
2863
|
+
# format, in a 16-byte slot (see #lower_variadic_long_double). Reading
|
|
2864
|
+
# it back would mean the reverse conversion and a walk that steps over
|
|
2865
|
+
# sixteen bytes rather than eight; until that exists, fetching one is
|
|
2866
|
+
# refused rather than silently read as the `double` this type shares its
|
|
2867
|
+
# width with.
|
|
2868
|
+
if type == Type::LongDouble
|
|
2869
|
+
error_at(token, "fetching a 'long double' with 'va_arg' is not supported yet")
|
|
2870
|
+
end
|
|
2841
2871
|
return if (type.integer? && type.size >= 4) || type.pointer? || (type.float? && type.size == 8)
|
|
2842
2872
|
|
|
2843
2873
|
error_at(token, "second argument to 'va_arg' has type '#{type}', which va_arg cannot yield")
|
|
@@ -4179,7 +4209,7 @@ module Rubycc
|
|
|
4179
4209
|
if i < fixed
|
|
4180
4210
|
lower_fixed_argument(node, i, arg, vreg, arg_type, param_types[i], name, placer)
|
|
4181
4211
|
else
|
|
4182
|
-
|
|
4212
|
+
lower_variadic_argument(vreg, arg_type, placer, node.token)
|
|
4183
4213
|
end
|
|
4184
4214
|
)
|
|
4185
4215
|
end
|
|
@@ -4258,6 +4288,17 @@ module Rubycc
|
|
|
4258
4288
|
end
|
|
4259
4289
|
end
|
|
4260
4290
|
|
|
4291
|
+
# Lowers one argument in a variadic call's variable part to its [vreg,
|
|
4292
|
+
# kind] ABI slot pairs. Every type but `long double` takes the default
|
|
4293
|
+
# argument promotions and lands in a single slot; a `long double` is the
|
|
4294
|
+
# one argument whose value has to change shape on the way out, so it takes
|
|
4295
|
+
# a path of its own and may occupy more than one slot.
|
|
4296
|
+
def lower_variadic_argument(vreg, arg_type, placer, token)
|
|
4297
|
+
return lower_variadic_long_double(vreg, placer) if arg_type == Type::LongDouble
|
|
4298
|
+
|
|
4299
|
+
[place_scalar_argument(*promote_variadic_argument(vreg, arg_type, token), placer)]
|
|
4300
|
+
end
|
|
4301
|
+
|
|
4261
4302
|
# The default argument promotions applied to an argument in a variadic
|
|
4262
4303
|
# call's variable part (6.5.2.2p6), returning the [vreg, kind] pair the
|
|
4263
4304
|
# call lowering wants: an integer narrower than int (char, short and their
|
|
@@ -4284,6 +4325,256 @@ module Rubycc
|
|
|
4284
4325
|
[convert(vreg, from: arg_type, to: integer_promote(arg_type)), :gp]
|
|
4285
4326
|
end
|
|
4286
4327
|
|
|
4328
|
+
# --- variadic `long double` --------------------------------------------
|
|
4329
|
+
#
|
|
4330
|
+
# rubycc computes in `long double` at a double's width and precision (see
|
|
4331
|
+
# Type::LongDouble), which every part of a translation unit it compiles
|
|
4332
|
+
# agrees on. A variadic callee does not: printf and its kin were built by
|
|
4333
|
+
# the platform's compiler and read the argument in the target's own
|
|
4334
|
+
# long-double format, from the position that format's ABI class puts it
|
|
4335
|
+
# in. Converting at that boundary is what this section does, and it is the
|
|
4336
|
+
# only place a `long double` differs from a `double` at all.
|
|
4337
|
+
#
|
|
4338
|
+
# The conversion is exact in this direction. binary64 is a subset of both
|
|
4339
|
+
# x87's 80-bit extended format and IEEE binary128: each has a strictly
|
|
4340
|
+
# wider exponent range (15 bits against 11) and a strictly wider
|
|
4341
|
+
# significand (64 and 113 bits against 53), so every finite double —
|
|
4342
|
+
# subnormal ones included, which the wider exponent range makes normal —
|
|
4343
|
+
# has an exact image, and the infinities and NaNs map across by
|
|
4344
|
+
# construction. That is why the values can be rebuilt from the bits rather
|
|
4345
|
+
# than converted by a floating instruction: there is no rounding to get
|
|
4346
|
+
# right, and no x87 encoder to write.
|
|
4347
|
+
|
|
4348
|
+
# The byte width of every target's `long double` argument image. Both the
|
|
4349
|
+
# x87 80-bit format (which occupies the low ten bytes of it) and binary128
|
|
4350
|
+
# (which fills it) travel in sixteen bytes.
|
|
4351
|
+
LONG_DOUBLE_IMAGE_SIZE = 16
|
|
4352
|
+
|
|
4353
|
+
# binary64's fraction field is 52 bits wide, with the leading significand
|
|
4354
|
+
# bit implicit; 6.2.5 leaves the format to the implementation, but both
|
|
4355
|
+
# targets are IEEE 754 binary64 (measured through <float.h> against gcc).
|
|
4356
|
+
DOUBLE_FRACTION_BITS = 52
|
|
4357
|
+
|
|
4358
|
+
# binary64's all-ones 11-bit exponent, which names an infinity or a NaN.
|
|
4359
|
+
DOUBLE_EXPONENT_MAX = 0x7FF
|
|
4360
|
+
|
|
4361
|
+
# Both wide formats bias a 15-bit exponent by 16383 where binary64 biases
|
|
4362
|
+
# an 11-bit one by 1023, so a normal double's stored exponent shifts by
|
|
4363
|
+
# exactly this much and needs no unbiasing.
|
|
4364
|
+
LONG_DOUBLE_EXPONENT_BIAS_DELTA = 16383 - 1023
|
|
4365
|
+
|
|
4366
|
+
# The all-ones 15-bit exponent, which names an infinity or a NaN in both
|
|
4367
|
+
# wide formats just as an all-ones 11-bit one does in binary64.
|
|
4368
|
+
LONG_DOUBLE_EXPONENT_MAX = 0x7FFF
|
|
4369
|
+
|
|
4370
|
+
# The biased exponent a subnormal double takes once normalized, before the
|
|
4371
|
+
# normalization shift is subtracted. A subnormal is fraction * 2^-1074;
|
|
4372
|
+
# shifting its fraction left by z = clz64(fraction) puts the leading one
|
|
4373
|
+
# in bit 63, so the value is (fraction << z) * 2^(-1074 - z), which is the
|
|
4374
|
+
# significand-times-2^(e-63) form the wide formats use with an unbiased
|
|
4375
|
+
# exponent of -1011 - z. Biased by 16383 that is 15372 - z.
|
|
4376
|
+
SUBNORMAL_EXPONENT_BASE = 16383 - 1011
|
|
4377
|
+
|
|
4378
|
+
# Lowers a `long double` in a variadic call's variable part: builds the
|
|
4379
|
+
# target's 16-byte image of the value and returns the [vreg, kind] slot
|
|
4380
|
+
# pairs that carry it, in the place the target's convention gives it
|
|
4381
|
+
# (see CallConvention#long_double_plan).
|
|
4382
|
+
#
|
|
4383
|
+
# An :sse16 slot carries the image's *address*, not its value — a whole
|
|
4384
|
+
# 16-byte quad has no 8-byte virtual-register slot it could live in, so
|
|
4385
|
+
# the backend loads it from memory into the vector register. Every other
|
|
4386
|
+
# slot is an ordinary eightbyte read out of the image.
|
|
4387
|
+
def lower_variadic_long_double(vreg, placer)
|
|
4388
|
+
base = emit_long_double_image(vreg)
|
|
4389
|
+
plan = @convention.long_double_plan
|
|
4390
|
+
eightbytes = LONG_DOUBLE_IMAGE_SIZE / 8
|
|
4391
|
+
placement = placer.place(ArgumentRequest.new(kinds: plan.pieces.map(&:kind),
|
|
4392
|
+
align16: plan.align16,
|
|
4393
|
+
mem_eightbytes: eightbytes))
|
|
4394
|
+
pieces = placement == :stack ? CallConvention.memory_pieces(LONG_DOUBLE_IMAGE_SIZE) : plan.pieces
|
|
4395
|
+
pieces = [PAD_STACK_PIECE] + pieces if placer.pad_stack.positive?
|
|
4396
|
+
pieces.map do |piece|
|
|
4397
|
+
next [nil, piece.kind] if pad_piece?(piece.kind)
|
|
4398
|
+
next [base, piece.kind] if piece.kind == :sse16
|
|
4399
|
+
|
|
4400
|
+
value = new_vreg
|
|
4401
|
+
emit(:load, dst: value, a: piece_address(base, piece.offset), size: piece.size)
|
|
4402
|
+
[value, piece.kind]
|
|
4403
|
+
end
|
|
4404
|
+
end
|
|
4405
|
+
|
|
4406
|
+
# Builds the target's 16-byte `long double` image of the double in `vreg`
|
|
4407
|
+
# in a fresh stack object and returns a vreg holding its address.
|
|
4408
|
+
def emit_long_double_image(vreg)
|
|
4409
|
+
sign, exponent, significand = decompose_double(vreg)
|
|
4410
|
+
base = new_vreg
|
|
4411
|
+
emit(:object_addr, dst: base, a: new_object(LONG_DOUBLE_IMAGE_SIZE))
|
|
4412
|
+
case @convention.long_double_format
|
|
4413
|
+
when :x87_extended80 then store_x87_extended80(base, sign, exponent, significand)
|
|
4414
|
+
when :binary128 then store_binary128(base, sign, exponent, significand)
|
|
4415
|
+
else raise "unknown long double format #{@convention.long_double_format.inspect}"
|
|
4416
|
+
end
|
|
4417
|
+
base
|
|
4418
|
+
end
|
|
4419
|
+
|
|
4420
|
+
# Takes the double in `vreg` apart into the three fields both wide formats
|
|
4421
|
+
# are then assembled from: its sign bit, its biased 15-bit exponent, and a
|
|
4422
|
+
# 64-bit significand whose leading bit is explicit (bit 63 set for every
|
|
4423
|
+
# value but a zero) — the x87 layout, which binary128 reaches by dropping
|
|
4424
|
+
# that leading bit again.
|
|
4425
|
+
#
|
|
4426
|
+
# The four cases are the four a binary64 encoding distinguishes, and each
|
|
4427
|
+
# needs its own arm:
|
|
4428
|
+
#
|
|
4429
|
+
# * an all-ones exponent is an infinity (fraction zero) or a NaN, and
|
|
4430
|
+
# stays one: the exponent saturates to all-ones in the wider field too,
|
|
4431
|
+
# and the fraction is shifted up so that binary64's quiet bit — its
|
|
4432
|
+
# most significant fraction bit — lands on the wide format's, carrying
|
|
4433
|
+
# the payload with it (see #quieted_significand for the one bit a
|
|
4434
|
+
# format conversion is required to change);
|
|
4435
|
+
# * a normal value only re-biases its exponent and restores the implicit
|
|
4436
|
+
# leading one;
|
|
4437
|
+
# * a subnormal has no implicit one, and no counterpart in the wide
|
|
4438
|
+
# formats, whose exponent range is large enough to hold every one of
|
|
4439
|
+
# them as a *normal* value: the fraction is shifted left until its
|
|
4440
|
+
# leading one reaches bit 63 and the exponent is lowered to match;
|
|
4441
|
+
# * a zero (of either sign) has an all-zero significand and exponent,
|
|
4442
|
+
# which the normal arm's implicit leading one would wrongly supply.
|
|
4443
|
+
#
|
|
4444
|
+
# The sign rides along untouched throughout, so a negative zero stays one.
|
|
4445
|
+
def decompose_double(vreg)
|
|
4446
|
+
bits = double_bit_pattern(vreg)
|
|
4447
|
+
sign = wide_op(:shr, bits, wide_const(63))
|
|
4448
|
+
biased = wide_op(:and, wide_op(:shr, bits, wide_const(DOUBLE_FRACTION_BITS)),
|
|
4449
|
+
wide_const(DOUBLE_EXPONENT_MAX))
|
|
4450
|
+
fraction = wide_op(:and, bits, wide_const((1 << DOUBLE_FRACTION_BITS) - 1))
|
|
4451
|
+
|
|
4452
|
+
exponent = new_vreg
|
|
4453
|
+
significand = new_vreg
|
|
4454
|
+
finite_label = new_label
|
|
4455
|
+
small_label = new_label
|
|
4456
|
+
zero_label = new_label
|
|
4457
|
+
end_label = new_label
|
|
4458
|
+
|
|
4459
|
+
# Infinity or NaN.
|
|
4460
|
+
emit(:jump_if_zero, a: wide_op(:eq, biased, wide_const(DOUBLE_EXPONENT_MAX)), b: finite_label)
|
|
4461
|
+
emit_const_copy(exponent, LONG_DOUBLE_EXPONENT_MAX)
|
|
4462
|
+
emit(:copy, dst: significand, a: quieted_significand(fraction))
|
|
4463
|
+
emit(:jump, a: end_label)
|
|
4464
|
+
|
|
4465
|
+
# A normal value.
|
|
4466
|
+
emit(:label, a: finite_label)
|
|
4467
|
+
emit(:jump_if_zero, a: wide_op(:ne, biased, wide_const(0)), b: small_label)
|
|
4468
|
+
emit(:copy, dst: exponent, a: wide_op(:add, biased, wide_const(LONG_DOUBLE_EXPONENT_BIAS_DELTA)))
|
|
4469
|
+
emit(:copy, dst: significand, a: explicit_significand(fraction))
|
|
4470
|
+
emit(:jump, a: end_label)
|
|
4471
|
+
|
|
4472
|
+
# A subnormal value: normalize it into the wider exponent range.
|
|
4473
|
+
emit(:label, a: small_label)
|
|
4474
|
+
emit(:jump_if_zero, a: wide_op(:ne, fraction, wide_const(0)), b: zero_label)
|
|
4475
|
+
shift = new_vreg
|
|
4476
|
+
emit(:bit_scan, dst: shift, a: fraction, b: :reverse, size: 8)
|
|
4477
|
+
emit(:copy, dst: exponent, a: wide_op(:sub, wide_const(SUBNORMAL_EXPONENT_BASE), shift))
|
|
4478
|
+
emit(:copy, dst: significand, a: wide_op(:shl, fraction, shift))
|
|
4479
|
+
emit(:jump, a: end_label)
|
|
4480
|
+
|
|
4481
|
+
# A zero, positive or negative.
|
|
4482
|
+
emit(:label, a: zero_label)
|
|
4483
|
+
emit_const_copy(exponent, 0)
|
|
4484
|
+
emit_const_copy(significand, 0)
|
|
4485
|
+
|
|
4486
|
+
emit(:label, a: end_label)
|
|
4487
|
+
[sign, exponent, significand]
|
|
4488
|
+
end
|
|
4489
|
+
|
|
4490
|
+
# The 64-bit explicit-leading-bit significand of a double whose exponent
|
|
4491
|
+
# field is not zero: its implicit leading one restored at bit 52 and the
|
|
4492
|
+
# whole moved up to bit 63. An infinity and a NaN take the same expression
|
|
4493
|
+
# (through #quieted_significand), their leading bit being set in the wide
|
|
4494
|
+
# formats too — x87 reads a cleared one as an unsupported encoding rather
|
|
4495
|
+
# than as an infinity, and binary128 drops the bit again on the way in.
|
|
4496
|
+
def explicit_significand(fraction)
|
|
4497
|
+
with_leading_one = wide_op(:or, fraction, wide_const(1 << DOUBLE_FRACTION_BITS))
|
|
4498
|
+
wide_op(:shl, with_leading_one, wide_const(63 - DOUBLE_FRACTION_BITS))
|
|
4499
|
+
end
|
|
4500
|
+
|
|
4501
|
+
# The significand of an infinity or a NaN, which is #explicit_significand
|
|
4502
|
+
# plus one correction: a *signalling* NaN becomes quiet. IEEE 754-2019
|
|
4503
|
+
# 6.2 has a conversion to another format raise the invalid operation
|
|
4504
|
+
# exception and deliver a quiet NaN, leaving the payload alone, and both
|
|
4505
|
+
# targets' hardware conversions do exactly that (measured: gcc's x86-64
|
|
4506
|
+
# `fldl` and its aarch64 `fcvt` both come back with the quiet bit set from
|
|
4507
|
+
# a signalling double, payload intact). The quiet bit is the significand's
|
|
4508
|
+
# bit 62 — the most significant *fraction* bit, just under the explicit
|
|
4509
|
+
# leading one — in the x87 layout, and the shift into binary128 carries it
|
|
4510
|
+
# to that format's own quiet bit at 111. Only a NaN gets it: an infinity's
|
|
4511
|
+
# fraction is zero, and setting the bit there would make one a NaN.
|
|
4512
|
+
def quieted_significand(fraction)
|
|
4513
|
+
is_nan = wide_op(:ne, fraction, wide_const(0))
|
|
4514
|
+
wide_op(:or, explicit_significand(fraction), wide_op(:shl, is_nan, wide_const(62)))
|
|
4515
|
+
end
|
|
4516
|
+
|
|
4517
|
+
# The x87 80-bit extended image, whose sixteen bytes are what the psABI's
|
|
4518
|
+
# scalar table (3.1.2) gives `long double`: the 64-bit significand in
|
|
4519
|
+
# bytes 0..7, then the sign in bit 15 of the halfword at byte 8 with the
|
|
4520
|
+
# biased exponent below it. The remaining six bytes are
|
|
4521
|
+
# padding the psABI leaves unspecified — gcc pushes whatever the stack
|
|
4522
|
+
# held there — and are written as zero here so the image a given value
|
|
4523
|
+
# produces is always the same.
|
|
4524
|
+
def store_x87_extended80(base, sign, exponent, significand)
|
|
4525
|
+
emit(:store, a: base, b: significand, size: 8)
|
|
4526
|
+
high = wide_op(:or, wide_op(:shl, sign, wide_const(15)), exponent)
|
|
4527
|
+
emit(:store, a: piece_address(base, 8), b: high, size: 8)
|
|
4528
|
+
end
|
|
4529
|
+
|
|
4530
|
+
# The IEEE binary128 image: a 112-bit fraction in bits 0..111, the biased
|
|
4531
|
+
# exponent in bits 112..126 and the sign in bit 127. binary128 keeps its
|
|
4532
|
+
# leading significand bit implicit like binary64 does, so the explicit one
|
|
4533
|
+
# at bit 63 is shifted out and the 63 bits below it become the top of the
|
|
4534
|
+
# fraction field — the remaining 49 low bits are zero, this significand
|
|
4535
|
+
# having come from a 53-bit one.
|
|
4536
|
+
def store_binary128(base, sign, exponent, significand)
|
|
4537
|
+
low = wide_op(:shl, significand, wide_const(49))
|
|
4538
|
+
# (significand << 1) >> 16 drops the leading bit and lands the 63
|
|
4539
|
+
# fraction bits at 0..47, the top of the fraction field's high half.
|
|
4540
|
+
fraction_high = wide_op(:shr, wide_op(:shl, significand, wide_const(1)), wide_const(16))
|
|
4541
|
+
high = wide_op(:or, wide_op(:or, wide_op(:shl, sign, wide_const(63)),
|
|
4542
|
+
wide_op(:shl, exponent, wide_const(48))),
|
|
4543
|
+
fraction_high)
|
|
4544
|
+
emit(:store, a: base, b: low, size: 8)
|
|
4545
|
+
emit(:store, a: piece_address(base, 8), b: high, size: 8)
|
|
4546
|
+
end
|
|
4547
|
+
|
|
4548
|
+
# The double in `vreg` reinterpreted as the 64-bit integer of its bits.
|
|
4549
|
+
# The IR has no bit-cast op, and needs none: a slot holds a double as the
|
|
4550
|
+
# eight bytes of its encoding, so storing it to memory and reading those
|
|
4551
|
+
# bytes back as an integer moves the value between the two views without
|
|
4552
|
+
# converting it.
|
|
4553
|
+
def double_bit_pattern(vreg)
|
|
4554
|
+
address = new_vreg
|
|
4555
|
+
emit(:object_addr, dst: address, a: new_object(8))
|
|
4556
|
+
emit(:store, a: address, b: vreg, size: 8)
|
|
4557
|
+
bits = new_vreg
|
|
4558
|
+
emit(:load, dst: bits, a: address, size: 8)
|
|
4559
|
+
bits
|
|
4560
|
+
end
|
|
4561
|
+
|
|
4562
|
+
# A 64-bit integer constant in a fresh vreg, and a 64-bit binary integer
|
|
4563
|
+
# op over two of them. The long-double conversion is all 64-bit bit
|
|
4564
|
+
# manipulation, so both spell out the size the rest of the generator
|
|
4565
|
+
# passes case by case.
|
|
4566
|
+
def wide_const(value)
|
|
4567
|
+
dst = new_vreg
|
|
4568
|
+
emit(:const, dst: dst, a: value, size: 8)
|
|
4569
|
+
dst
|
|
4570
|
+
end
|
|
4571
|
+
|
|
4572
|
+
def wide_op(op, lhs, rhs)
|
|
4573
|
+
dst = new_vreg
|
|
4574
|
+
emit(op, dst: dst, a: lhs, b: rhs, size: 8)
|
|
4575
|
+
dst
|
|
4576
|
+
end
|
|
4577
|
+
|
|
4287
4578
|
# "lhs && rhs": short-circuit, so rhs is only evaluated when lhs is
|
|
4288
4579
|
# non-zero. Both operands are conditions (int required). Lowered with a
|
|
4289
4580
|
# single result vreg written from one of two "const 1"/"const 0" arms,
|
|
@@ -4707,8 +4998,8 @@ module Rubycc
|
|
|
4707
4998
|
# unsigned char / uint8_t buffer and handing it to the char* str*/mem* API
|
|
4708
4999
|
# (e.g. redcarpet's html_smartypants.c passes a uint8_t* to strncmp). Two
|
|
4709
5000
|
# such pointees address objects of identical size and alignment, so the
|
|
4710
|
-
# reinterpretation is benign; accept it here (this subset
|
|
4711
|
-
#
|
|
5001
|
+
# reinterpretation is benign; accept it here (this subset warns about
|
|
5002
|
+
# nothing, so it is accepted silently). The three 1-byte character types are
|
|
4712
5003
|
# also mutually compatible, including plain char vs signed char which share
|
|
4713
5004
|
# a signedness -- this is the char*/signed char* debt Step 73 opened
|
|
4714
5005
|
# (docs/development/ROADMAP.md), which the character family carries no representation
|
|
@@ -4757,6 +5048,18 @@ module Rubycc
|
|
|
4757
5048
|
# long covers unsigned int, so "long + unsigned int" is long).
|
|
4758
5049
|
def common_arithmetic_type(lhs_type, rhs_type)
|
|
4759
5050
|
if lhs_type.float? || rhs_type.float?
|
|
5051
|
+
# 6.3.1.8's first floating case: if either operand is `long double`,
|
|
5052
|
+
# the result is `long double`. rubycc computes it with double's range
|
|
5053
|
+
# and precision (Type::LongDouble is 8 bytes here), so nothing about
|
|
5054
|
+
# the arithmetic changes -- but the *name* has to survive, because a
|
|
5055
|
+
# variadic call site converts by static type and a libc callee reads
|
|
5056
|
+
# back the wide format. Deciding on size alone dropped the name, and
|
|
5057
|
+
# `printf("%Lg", a + b)` then pushed 8 bytes where the callee read 16:
|
|
5058
|
+
# correct for `a` and wrong for `a + b`, which is the worst shape a
|
|
5059
|
+
# defect can take (docs/development/STEPS.md, long-double-varargs-1).
|
|
5060
|
+
long_double = lhs_type == Type::LongDouble || rhs_type == Type::LongDouble
|
|
5061
|
+
return Type::LongDouble if long_double
|
|
5062
|
+
|
|
4760
5063
|
double = (lhs_type.float? && lhs_type.size == 8) || (rhs_type.float? && rhs_type.size == 8)
|
|
4761
5064
|
return double ? Type::Double : Type::Float
|
|
4762
5065
|
end
|
|
@@ -5227,6 +5530,13 @@ module Rubycc
|
|
|
5227
5530
|
# AArch64 has a native unsigned W-form).
|
|
5228
5531
|
def convert_floating(vreg, from, to, token)
|
|
5229
5532
|
if from.float? && to.float?
|
|
5533
|
+
# `double` and `long double` are two names over one representation
|
|
5534
|
+
# (see Type::LongDouble), so a conversion between them changes no bit
|
|
5535
|
+
# and emits nothing. Only float<->double actually changes format, and
|
|
5536
|
+
# :ftof reads `size` as the source width to pick a direction — which
|
|
5537
|
+
# a same-width pair would misread as a narrowing to `float`.
|
|
5538
|
+
return vreg if from.size == to.size
|
|
5539
|
+
|
|
5230
5540
|
dst = new_vreg
|
|
5231
5541
|
emit(:ftof, dst: dst, a: vreg, size: from.size)
|
|
5232
5542
|
dst
|
|
@@ -5753,7 +6063,7 @@ module Rubycc
|
|
|
5753
6063
|
static_type(node.right)
|
|
5754
6064
|
when Front::AST::LogicalAnd, Front::AST::LogicalOr,
|
|
5755
6065
|
Front::AST::BuiltinConstantP, Front::AST::BuiltinBitScan,
|
|
5756
|
-
Front::AST::BuiltinOverflow
|
|
6066
|
+
Front::AST::BuiltinPopcount, Front::AST::BuiltinOverflow
|
|
5757
6067
|
Type::Int
|
|
5758
6068
|
when Front::AST::BuiltinUnreachable
|
|
5759
6069
|
Type::Void
|
data/lib/rubycc/ir/ir.rb
CHANGED
|
@@ -9,6 +9,22 @@ module Rubycc
|
|
|
9
9
|
# constant, otherwise a 32-bit one)
|
|
10
10
|
# :copy dst <- a
|
|
11
11
|
# :add/:sub/:mul dst <- a op b
|
|
12
|
+
# :scaled_add dst <- a + b*size the address a subscript forms: the
|
|
13
|
+
# pointer in a offset by the index in b, that
|
|
14
|
+
# index scaled by `size` — the element width,
|
|
15
|
+
# which is 1, 2, 4 or 8 and nothing else. The
|
|
16
|
+
# computation is always 64-bit, a pointer
|
|
17
|
+
# being what it produces, so `size` here names
|
|
18
|
+
# the scale rather than the operand width (the
|
|
19
|
+
# same reading it has on :load/:store, where
|
|
20
|
+
# it is the access width rather than the
|
|
21
|
+
# register's). No generator emits it: it is
|
|
22
|
+
# what IR::Simplify folds a ":mul index by a
|
|
23
|
+
# constant element size" plus the ":add" of
|
|
24
|
+
# that to a base into, and both targets have a
|
|
25
|
+
# single instruction for it (x86-64's `lea`
|
|
26
|
+
# with a SIB scale, AArch64's add with a
|
|
27
|
+
# shifted register operand)
|
|
12
28
|
# :div/:mod dst <- a op b (signed division/remainder)
|
|
13
29
|
# :udiv/:umod dst <- a op b (unsigned division/remainder;
|
|
14
30
|
# the backend zeroes edx and uses `div`)
|
|
@@ -118,7 +134,16 @@ module Rubycc
|
|
|
118
134
|
# aggregate AAPCS64 passes by reference is reduced by
|
|
119
135
|
# the generator to a single :gp pointer to a
|
|
120
136
|
# caller-made copy, so no backend needs a rule of its
|
|
121
|
-
# own for it.
|
|
137
|
+
# own for it. One further kind appears only in a
|
|
138
|
+
# variadic call's variable part: :sse16 takes the next
|
|
139
|
+
# vector register as a whole 16-byte value (AAPCS64's
|
|
140
|
+
# quad-precision `long double`), and its pair's vreg
|
|
141
|
+
# carries the *address* of that value rather than the
|
|
142
|
+
# value, no 8-byte slot being able to hold one — the
|
|
143
|
+
# backend loads the register from there. The same
|
|
144
|
+
# argument on System V is X87/X87UP-classed and so
|
|
145
|
+
# travels as two ordinary :mem eightbytes instead, and
|
|
146
|
+
# :sse16 never reaches that backend. A call whose struct result comes back
|
|
122
147
|
# through a hidden pointer also prepends that
|
|
123
148
|
# [vreg, kind] pointer as the first argument. `size` is nil, or a
|
|
124
149
|
# [fixed, ret] pair when either half is non-nil:
|
|
@@ -224,6 +249,19 @@ module Rubycc
|
|
|
224
249
|
# one, at the W or X width `size` names. A zero
|
|
225
250
|
# operand is undefined (as in gcc), so no zero
|
|
226
251
|
# case is emitted. The result is an int
|
|
252
|
+
# :popcount dst <- ones(a) counts the set bits of the integer in vreg a,
|
|
253
|
+
# for __builtin_popcount (and its "l"/"ll"
|
|
254
|
+
# forms); `size` is the operand width (4 or 8)
|
|
255
|
+
# and b is unused. Every operand value is
|
|
256
|
+
# defined, zero included. Neither backend uses
|
|
257
|
+
# a hardware population count — x86-64's
|
|
258
|
+
# `popcnt` is an SSE4.2 instruction the
|
|
259
|
+
# baseline does not have, and aarch64's `cnt`
|
|
260
|
+
# is an AdvSIMD one over a vector register —
|
|
261
|
+
# so both expand the same divide-and-conquer
|
|
262
|
+
# (SWAR) sum of bit fields, described in
|
|
263
|
+
# backend/x86_64.rb#emit_popcount. The result
|
|
264
|
+
# is an int
|
|
227
265
|
#
|
|
228
266
|
# The five atomic ops below lower gcc's __atomic_* builtins. Every one is
|
|
229
267
|
# sequentially consistent — the IR carries no memory order at all, because
|