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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +61 -0
  3. data/README.md +26 -14
  4. data/data/verified_gems.json +85 -63
  5. data/exe/rubycc-ar +11 -3
  6. data/include/libc/sys/cdefs.h +12 -0
  7. data/lib/rubycc/backend/aarch64.rb +705 -117
  8. data/lib/rubycc/backend/slot_residency.rb +169 -0
  9. data/lib/rubycc/backend/x86_64.rb +924 -137
  10. data/lib/rubycc/command_line.rb +339 -0
  11. data/lib/rubycc/compile_error.rb +6 -3
  12. data/lib/rubycc/compiler.rb +17 -2
  13. data/lib/rubycc/diagnostics.rb +105 -0
  14. data/lib/rubycc/doctor/gemfile.rb +12 -3
  15. data/lib/rubycc/doctor/verified_gems.rb +5 -1
  16. data/lib/rubycc/driver.rb +66 -10
  17. data/lib/rubycc/front/ast.rb +18 -7
  18. data/lib/rubycc/front/constant_evaluator.rb +12 -0
  19. data/lib/rubycc/front/lexeme_reader.rb +3 -1
  20. data/lib/rubycc/front/parser.rb +51 -18
  21. data/lib/rubycc/ir/analysis.rb +82 -0
  22. data/lib/rubycc/ir/call_convention.rb +74 -7
  23. data/lib/rubycc/ir/generator.rb +319 -9
  24. data/lib/rubycc/ir/ir.rb +39 -1
  25. data/lib/rubycc/ir/promotion.rb +255 -0
  26. data/lib/rubycc/ir/simplify.rb +570 -0
  27. data/lib/rubycc/link/library_resolver.rb +17 -5
  28. data/lib/rubycc/link/partial_linker.rb +8 -1
  29. data/lib/rubycc/link/shared_linker.rb +2 -2
  30. data/lib/rubycc/mkmf_shim.rb +178 -12
  31. data/lib/rubycc/objfile/ar_archive.rb +13 -2
  32. data/lib/rubycc/objfile/elf_reader.rb +13 -2
  33. data/lib/rubycc/pkgconf/parser.rb +4 -0
  34. data/lib/rubycc/pkgconf/resolver.rb +3 -1
  35. data/lib/rubycc/pkgconf/system_path_filter.rb +8 -2
  36. data/lib/rubycc/preprocess/preprocessor.rb +161 -37
  37. data/lib/rubycc/preprocess/scanner.rb +69 -14
  38. data/lib/rubycc/preprocess/token_converter.rb +11 -1
  39. data/lib/rubycc/rmake/cli.rb +32 -4
  40. data/lib/rubycc/rmake/executor.rb +157 -226
  41. data/lib/rubycc/rmake/makefile.rb +35 -13
  42. data/lib/rubycc/rmake/parser.rb +8 -2
  43. data/lib/rubycc/rmake/rmake.rb +1 -0
  44. data/lib/rubycc/rmake/tool_command.rb +69 -0
  45. data/lib/rubycc/shell.rb +510 -0
  46. data/lib/rubycc/type.rb +23 -7
  47. data/lib/rubycc/version.rb +1 -1
  48. data/lib/rubycc.rb +12 -0
  49. data/lib/rubygems_plugin.rb +31 -3
  50. metadata +14 -3
@@ -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/ctzll/clz/clzll(x)": counts x's trailing (ctz) or leading
2422
- # (clz) zero bits, as an int. The operand is converted to the unsigned
2423
- # integer of the builtin's width (4 or 8 bytes), then a single :bit_scan op
2424
- # lowers to bsf (forward/ctz) or bsr-based (reverse/clz) hardware. A
2425
- # zero operand is undefined behavior (gcc), so no zero handling is emitted.
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
- [place_scalar_argument(*promote_variadic_argument(vreg, arg_type, node.token), placer)]
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 has no warning
4711
- # channel, so nothing is emitted). The three 1-byte character types are
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. A call whose struct result comes back
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