HaxeFoundation / haxe

Haxe - The Cross-Platform Toolkit
https://haxe.org
6.18k stars 655 forks source link

Error: Don't know how to compare array and array (hlc) when compiling Heaps.io for HL/C with DX12 #11468

Open dipyalov opened 10 months ago

dipyalov commented 10 months ago

Haxe: latest git Hashlink: latest git Heaps.io: latest git

I'm compiling a sample Heaps.io project with DX12 backend to HL/C target. Compiler throws "Error: Don't know how to compare array and array (hlc)" message.

My investigation has shown the following:

The "flushPipeline" method of heaps/h3d/DX12Driver.hx has the following code:

    function flushPipeline() {
        if( !needPipelineFlush ) return;
        needPipelineFlush = false;
        var signature = pipelineSignature;
        var signatureSize = PSIGN_LAYOUT + currentShader.inputCount;
        adlerOut.setI32(0, 0);
        hl.Format.digest(adlerOut, signature, signatureSize, 3);
        var hash = adlerOut.getI32(0);
        var pipes = currentShader.pipelines.get(hash);
        if( pipes == null ) {
            pipes = new hl.NativeArray(1);
            currentShader.pipelines.set(hash, pipes);
        }

And something between:

var pipes = currentShader.pipelines.get(hash);
if( pipes == null ) {

makes HL/C generate the following C code:

    r36 = r0->currentShader;
    if( r36 == NULL ) hl_null_access();
    r35 = r36->pipelines;
    if( r35 == NULL ) hl_null_access();
    r37 = r32;
    r34 = haxe_ds_IntMap_get(r35,r37);
    r38 = (varray*)r34;
    r39 = (varray*)hl_dyn_castp(&r34,&t$_dyn,&t$_array);
    ### WRONG 0 ### r38 == r39 -> label$6a3cd68_69_40 ###;
    hl_assert();
    label$6a3cd68_69_40:
    r40 = r38;
    r43 = r40;
    if( r43 ) goto label$6a3cd68_69_54;

The ### WRONG ### part is my modification to debug this as the haxe compiler actually fails at this point because it can't generate comparison statement for 2 arrays.

dipyalov commented 10 months ago

Forgot to mention - I have --debug option set. And my investigation has shown that this code is generated for debugging purposes in unsafe_cast HL op produced here:

https://github.com/HaxeFoundation/haxe/blob/584a42cb60370b6bf652061e7950603a7500e97e/src/generators/genhl.ml#L2208C4-L2208C4

Still don't understand how it should be fixed yet.

dipyalov commented 10 months ago

Should replacing unsafe_cast_to ctx ret rt e.epos with unsafe_cast_to ~debugchk:false ctx ret rt e.epos be OK? Or is there a special idea to not set debugchk to false?

onehundredfeet commented 8 months ago

I'm getting a similar error, but I have no idea where in my codebase it's coming from. It doesn't show up when compiling for hashlink HL

Error: Don't know how to compare bytes and bytes (hlc)
onehundredfeet commented 8 months ago

I was able to narrow it down to hl.Bytes. But that makes little sense.

class Junk{
    public static function exists2(a : hl.Bytes) {
        return a != null;
    }   
}

class HelloWorld {
    public static function main() {

        trace('Hello, World! ${Junk.exists2(null)}'); 
    }
}

Error: Don't know how to compare bytes and bytes (hlc)

onehundredfeet commented 8 months ago

I don't see HBytes anywhere here, but my ocaml is not great.

let common_type ctx e1 e2 for_eq p =
    let t1 = to_type ctx e1.etype in
    let t2 = to_type ctx e2.etype in
    let rec loop t1 t2 =
        if t1 == t2 then t1 else
        match t1, t2 with
        | HUI8, (HUI16 | HI32 | HI64 | HF32 | HF64) -> t2
        | HUI16, (HI32 | HI64 | HF32 | HF64) -> t2
        | (HI32 | HI64), HF32 -> t2 (* possible loss of precision *)
        | (HI32 | HI64 | HF32), HF64 -> t2
        | (HUI8|HUI16|HI32|HI64|HF32|HF64), (HUI8|HUI16|HI32|HI64|HF32|HF64) -> t1
        | (HUI8|HUI16|HI32|HI64|HF32|HF64), (HNull t2) -> if for_eq then HNull (loop t1 t2) else loop t1 t2
        | (HNull t1), (HUI8|HUI16|HI32|HI64|HF32|HF64) -> if for_eq then HNull (loop t1 t2) else loop t1 t2
        | (HNull t1), (HNull t2) -> if for_eq then HNull (loop t1 t2) else loop t1 t2
        | HDyn, (HUI8|HUI16|HI32|HI64|HF32|HF64) -> HF64
        | (HUI8|HUI16|HI32|HI64|HF32|HF64), HDyn -> HF64
        | HDyn, _ -> HDyn
        | _, HDyn -> HDyn
        | _ when for_eq && safe_cast t1 t2 -> t2
        | _ when for_eq && safe_cast t2 t1 -> t1
        | HBool, HNull HBool when for_eq -> t2
        | HNull HBool, HBool when for_eq -> t1
        | HObj _, HVirtual _ | HVirtual _, HObj _ | HVirtual _ , HVirtual _ -> HDyn
        | HFun _, HFun _ -> HDyn
        | _ ->
            abort ("Don't know how to compare " ^ tstr t1 ^ " and " ^ tstr t2) p
    in
    loop t1 t2

But this is the regular HL code emitter, which works. It's just the HL/C equivalent that doesn't work.

onehundredfeet commented 8 months ago

in hl2c.ml I wonder if adding HByte comparison case at line 747 should be:

match rtype a, rtype b with
            | (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool | HI64), (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool | HI64) ->
                phys_compare()
            | HBytes, HBytes ->
                phys_compare()
onehundredfeet commented 8 months ago

@Simn I saw your HArry / HArry compare case change and thought this was something similar.

onehundredfeet commented 8 months ago

Add PR.

https://github.com/HaxeFoundation/haxe/pull/11610