HansKristian-Work / dxil-spirv

DXIL conversion to SPIR-V for D3D12 translation libraries
Other
166 stars 32 forks source link

Fails for some dx.ops when dxil to spirv #195

Closed fire-emblem closed 2 months ago

fire-emblem commented 3 months ago

Convert will be failed when processing dx.op as:

dx.op.binaryWithTwoOuts dx.op.BinaryWithCarryOrBorrow

%1 = call %dx.types.twoi32 @dx.op.binaryWithTwoOuts.i32(i32 43, i32 %0, i32 4)

// Binary uint with carry or borrow BinaryWithCarryOrBorrow,

// Binary uint with two outputs BinaryWithTwoOuts,

example dxil: https://github.com/microsoft/DirectXShaderCompiler/blob/8652894e69753185589be7f1c371b77fb3abcc36/projects/dxilconv/test/dxbc2dxil-asm/hs3.ref#L7

dxil op define: https://github.com/llvm/llvm-project/blob/421c3fe54b56608bc6b23716d1cac96c8b3c38c5/llvm/lib/Target/DirectX/DXIL.td#L59

https://github.com/gongminmin/Dilithium/blob/976ce6d6420e45ac3088fe345793bfca80cd3acd/Src/HLSL/DxilOperations.cpp#L116

          // Binary int with two outputs                                                                                                       void,     h,     f,     d,    i1,    i8,   i16,   i32,   i64  function attribute
          {  OpCode::IMul,                    "IMul",                     OpCodeClass::BinaryWithTwoOuts,        "binaryWithTwoOuts",          false, false, false, false, false, false, false,  true, false, Attribute::AK_ReadNone, },
          {  OpCode::UMul,                    "UMul",                     OpCodeClass::BinaryWithTwoOuts,        "binaryWithTwoOuts",          false, false, false, false, false, false, false,  true, false, Attribute::AK_ReadNone, },
          {  OpCode::UDiv,                    "UDiv",                     OpCodeClass::BinaryWithTwoOuts,        "binaryWithTwoOuts",          false, false, false, false, false, false, false,  true, false, Attribute::AK_ReadNone, },

          // Binary int with carry                                                                                                             void,     h,     f,     d,    i1,    i8,   i16,   i32,   i64  function attribute
          {  OpCode::IAddc,                   "IAddc",                    OpCodeClass::BinaryWithCarry,          "binaryWithCarry",            false, false, false, false, false, false, false,  true, false, Attribute::AK_ReadNone, },
          {  OpCode::UAddc,                   "UAddc",                    OpCodeClass::BinaryWithCarry,          "binaryWithCarry",            false, false, false, false, false, false, false,  true, false, Attribute::AK_ReadNone, },
          {  OpCode::ISubc,                   "ISubc",                    OpCodeClass::BinaryWithCarry,          "binaryWithCarry",            false, false, false, false, false, false, false,  true, false, Attribute::AK_ReadNone, },
          {  OpCode::USubc,                   "USubc",                    OpCodeClass::BinaryWithCarry,          "binaryWithCarry",            false, false, false, false, false, false, false,  true, false, Attribute::AK_ReadNone, },
HansKristian-Work commented 3 months ago

Do you have an example DXIL that demonstrates this? If I can't make DXC generate it, it's hard to test.

fire-emblem commented 3 months ago
  1. HLSL to DXBC by fxc.exe
fxc.exe /T cs_5_0 /E CSMain /Fo cs.dxbc cs.hlsl /Fc out.txt
#define MyRS1 "UAV(u0) "

RWStructuredBuffer<int2> Input : register(u0); 

[RootSignature(MyRS1)]
[numthreads(1, 1, 8)]
void CSMain(int3 dispatchThreadID : SV_DispatchThreadID)
{
    int index = dispatchThreadID.x;
    Input[index].y = (Input[index].x + 1) * Input[index].x;
    // Input[index].y = (Input[index].x + 1) / Input[index].x;
}

dxbc disasm:

cs_5_0
dcl_globalFlags refactoringAllowed
dcl_uav_structured u0, 8
dcl_input vThreadID.x
dcl_temps 1
dcl_thread_group 1, 1, 8
ld_structured_indexable(structured_buffer, stride=8)(mixed,mixed,mixed,mixed) r0.x, vThreadID.x, l(0), u0.xxxx
iadd r0.y, r0.x, l(1)
imul null, r0.x, r0.x, r0.y
store_structured u0.x, vThreadID.x, l(4), r0.x
ret 

or

cs_5_0
dcl_globalFlags refactoringAllowed
dcl_uav_structured u0, 8
dcl_input vThreadID.x
dcl_temps 1
dcl_thread_group 1, 1, 8
ld_structured_indexable(structured_buffer, stride=8)(mixed,mixed,mixed,mixed) r0.x, vThreadID.x, l(0), u0.xxxx
iadd r0.y, r0.x, l(1)
xor r0.z, r0.x, r0.y
imax r0.xy, r0.xyxx, -r0.xyxx
udiv r0.x, null, r0.y, r0.x
and r0.y, r0.z, l(0x80000000)
ineg r0.z, r0.x
movc r0.x, r0.y, r0.z, r0.x
store_structured u0.x, vThreadID.x, l(4), r0.x
ret 
  1. DXBC to DXIL by dxbc2dxil.exe

dxbc2dxil.exe is a tool in dxc windows build: https://github.com/microsoft/DirectXShaderCompiler/tree/master/projects/dxilconv/lib/DxbcConverter

gen dxil container

dxbc2dxil.exe cs.dxbc /o cs.dxil

gen dxil ir

dxbc2dxil.exe cs.dxbc /emit-llvm

dx.op.binaryWithTwoOuts.i32 or BinaryWithCarryOrBorrow exists in the function

define void @main() {
entry:
  %0 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 1, i32 0, i32 0, i1 false)
  %1 = call i32 @dx.op.threadId.i32(i32 93, i32 0)
  %2 = call %dx.types.ResRet.i32 @dx.op.bufferLoad.i32(i32 68, %dx.types.Handle %0, i32 %1, i32 0)
  %3 = extractvalue %dx.types.ResRet.i32 %2, 0
  %4 = add i32 %3, 1
  %5 = call %dx.types.twoi32 @dx.op.binaryWithTwoOuts.i32(i32 41, i32 %3, i32 %4)
  %6 = extractvalue %dx.types.twoi32 %5, 1
  %7 = call i32 @dx.op.threadId.i32(i32 93, i32 0)
  call void @dx.op.bufferStore.i32(i32 69, %dx.types.Handle %0, i32 %7, i32 4, i32 %6, i32 undef, i32 undef, i32 undef, i8 1)
  ret void
}
  1. DXIL to SPIRV by dxil-spirv
dxil-spirv ./cs.dxil

Then will report error

[ERROR] Unimplemented DXIL opcode 41

We can add "emit_xxx_instruction" in opcodes_dxil_builtins.cpp for these opcodes

Attach cs.zip

fire-emblem commented 3 months ago

These dx.op builtins may be the old style DXBC legacy.

HansKristian-Work commented 3 months ago

Does dxbc2dxil support DXBC asm? That test you provided only covers imul.

HansKristian-Work commented 2 months ago

Should be implemented on master now. Note that it's mostly untested.