Subject: bug#78606: 31.0.50; [nativecomp] native-ice in emit_mvar_rval

From: Pip Cet <[email-masked]>
Date: Tue, 27 May 2025 13:38:02 +0000

This reduced test case:

;; -*- lexical-binding: t; -*-

(defun f (x)
  (and (= x 1)
       (if (eql x 1)
           1
         x)))

causes a native-ice:

Error: native-ice (\"can't find data in relocation containers\")

when Emacs is run as:

./src/emacs -Q --batch --eval '(native-compile "native.el")'

The problem, as far as I can see, is that emit_mvar_rval appears to
assume that if the constraint part of an mvar allows only a single
value, that value can also be fetched from the reloc array.  In this
case, the constraints on x make it so only 1.0 is a legal value in one
basic block, but 1.0 isn't in the data array.

Note that it is not a valid fix to make obj_to_reloc fail gently if it
cannot find obj in either data container: if 1.0 is present in the
ephemeral vector but not in the default vector, referring to the
ephemeral vector after top_level_run has completed will fail.

The problem is this limple insn:

(set #(mvar 17592188503872 1 (member 1.0)) #(mvar 17592188503233 0 (member 1.0)))

The RHS mvar was not created with :constant 1.0 (so 1.0 was never added
to the data container), but it is comp-cstr-imm-vld-p.

The test case is reduced from mule-diag.el:

(defun list-block-of-chars (charset row min max)
  (let (i ch)
    (insert-char ?- (+ 7 (* 4 16)))
    (insert "\n     ")
    (setq i 0)
    (while (< i 16)
      (insert (format "%4X" i))
      (setq i (1+ i)))
    (setq i (* (/ min 16) 16))
    (while (<= i max)
      (if (= (% i 16) 0)
	  (insert (format "\n%6Xx" (/ (+ (* row 256) i) 16))))
      (setq ch (if (< i min)
		   32
		 (or (decode-char charset (+ (* row 256) i))
		     32)))		; gap in mapping
      ;; Don't insert control codes, non-Unicode characters.
      (if (or (< ch 32) (= ch 127))
	  (setq ch (single-key-description ch))
	(if (and (>= ch 128) (< ch 160))
	    (setq ch (format "%02Xh" ch))
	  (if (> ch #x10FFFF)
	      (setq ch 32))))
      (insert "\t" ch)
      (setq i (1+ i))))
  (insert "\n"))

But the original problem in mule-diag.el (generating a basic block which
would call (single-key-description 127.0) ) only showed up with other
modifications to the nativecomp compiler.

There are several ways to fix this, but I must note that adding a
constant that is highly likely to be already present in the register
file is usually wasteful: in this case, we don't want to create the
constant 1.0, we simply want to return the register which we now know to
contain 1.0.