Skip to content

reinterpret of a pointer sum to an integer has no mode that runs it: the interpreter throws an internal binding error on i_das_ptr_add, and -jit fails codegen with Trunc only operates on integer for the 32-bit form #4108

Closed

Description

@lookibed

daslang 0.6.4 at master 237df6024, Linux x86_64 (WSL2, kernel 6.6), gcc 11.4, Release, LLVM 22.1.5 prebuilt.

reinterpret<uint64>(...) or reinterpret<uint>(...) applied directly to the result of pointer arithmetic (p + n, p - n) compiles, and then has no mode that runs it. The interpreter throws an internal binding error from the reinterpret node; -jit fails LLVM codegen for the 32-bit form. Storing the sum in a variable first and reinterpreting the variable works everywhere, so the operation itself is supported - only the direct spelling is broken.

Reproduction

sum64.das:

options gen2
[export]
def main() {
    var data : uint8[64]
    let p = unsafe(addr(data[0]))
    let a = unsafe(reinterpret<uint64>(unsafe(p + 4)))
    let base = unsafe(reinterpret<uint64>(p))
    print("{a - base}\n")
}
$ daslang sum64.das
EXCEPTION: internal binding error: typed eval on wrong extern return kind, i_das_ptr_add
$ daslang -jit sum64.das
0x4

sum32.das, the same with reinterpret<uint> on both lines:

$ daslang sum32.das
EXCEPTION: internal binding error: typed eval on wrong extern return kind, i_das_ptr_add
$ daslang -jit sum32.das
Trunc only operates on integer
  %trunc_cast = trunc ptr %19 to i32
failed to simulate

With let q : uint8? = unsafe(p + 4) and reinterpret<uint64>(q) both modes print 0x4. The pointee type (uint8?, int?, float?), the offset spelling (p + 4, p + n, p - 4) and -no-optimization do not change the result.

Expected

Both spellings behave like the through-a-variable form: the interpreter prints the address, and -jit produces the low 32 bits for reinterpret<uint>. If a 32-bit reinterpret of a pointer is meant to be rejected, a compile-time error is the right place; a verifier failure inside codegen and a run-time internal binding error are not.

Where

  • Interpreter: the message is ext_wrong_slot (include/daScript/simulate/interop.h). i_das_ptr_add is an extern returning a pointer, and the reinterpret node reads its result through the evalUInt64 / evalUInt slot, which ext_slot_cast does not accept for a pointer carrier.
  • JIT: the emitter builds trunc ptr -> i32 directly on the pointer value; LLVM requires ptrtoint first.

Test

Drops into tests/jit_tests/ (or tests/language/); on master the interpreter reports two errors and -jit fails the file at codegen.

options gen2
require dastest/testing_boost

def offset_u64(p : uint8?; n : int) : uint64 {
    return unsafe(reinterpret<uint64>(unsafe(p + n))) - unsafe(reinterpret<uint64>(p))
}

def offset_u32(p : uint8?; n : int) : uint {
    return unsafe(reinterpret<uint>(unsafe(p + n))) - unsafe(reinterpret<uint>(p))
}

def offset_via_variable(p : uint8?; n : int) : uint64 {
    let q : uint8? = unsafe(p + n)
    return unsafe(reinterpret<uint64>(q)) - unsafe(reinterpret<uint64>(p))
}

[test]
def test_reinterpret_of_a_pointer_sum(t : T?) {
    var data : uint8[64]
    let p = unsafe(addr(data[0]))
    t |> run("through a variable") @(t : T?) {
        t |> equal(offset_via_variable(p, 4), 4ul)
    }
    t |> run("reinterpret<uint64> of the sum") @(t : T?) {
        t |> equal(offset_u64(p, 4), 4ul)
    }
    t |> run("reinterpret<uint> of the sum") @(t : T?) {
        t |> equal(offset_u32(p, 4), 4u)
    }
}
$ daslang dastest/dastest.das -- --test reinterpret_ptr_sum.das
	--- PASS 'through a variable'
[E] :0: 	internal binding error: typed eval on wrong extern return kind, i_das_ptr_add
[E] :0: 	internal binding error: typed eval on wrong extern return kind, i_das_ptr_add
4 tests, 1 passed, 0 failed, 3 errors, 0 skipped
$ daslang dastest/dastest.das -jit -- --test reinterpret_ptr_sum.das
Trunc only operates on integer
  %trunc_cast = trunc ptr %3 to i32
1 tests, 0 passed, 0 failed, 1 errors, 0 skipped

Activity

  1. borisbat commented on Nov 7, 2026

    @borisbat
    Collaborator

    Both halves are in: #4472 (dasLLVM) and #4480 (the optimizer and front end). Closing.

  2. lookibed commented on Nov 9, 2026

    @lookibed
    ContributorAuthor

    Fixed on master: at abf1d40e35 the repro prints u64 0x4 / u32 0x4 in the interpreter and under -jit, and the test above passes on both tiers (f04c0ed and the #4480 batch). Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions