KhronosGroup / SPIRV-Tools

Apache License 2.0
1.08k stars 555 forks source link

spirv-fuzz: Add a transformation and fuzzer pass for changing memory semantics #4421

Open afd opened 3 years ago

afd commented 3 years ago

This transformation (and fuzzer pass) should strengthen the memory semantics of atomic operations and barrier operations.

For example: a relaxed load can be changed to an acquire load; a release store can be changed to a sequentially consistent store.

afd commented 3 years ago

@Mostafa-ashraf19 This would be a good one for you to work on in due course.

Mostafa-ashraf19 commented 3 years ago

Overview

The idea is to create a transformation that takes the current value of memory semantics for specific atomic instruction then changes it stronger memory order with a range of 5 bits of values.

Implementation details

The initial structure of Transformation Changing Memory Semantics, the structure of the Protobuf following by SPIR-V assembly example, before and after the transformation.

message TransformationChangingMemorySemantics {

  // This transformation is responsible for changing the mask of memory 
  // semantics with a range of 5 bits of values.

  // The id of specific atomic instruction.
  uint32  pointer_id = 1;

  // The new value added.
  uint32  memory_semantics_new_value_1 = 2;

  // The n2w value-added for atomic instructions that's takes 2 memory 
  // semantics values, e.g. OpAtomicCompareExchange.
  uint32  memory_semantics_new_value_2 = 3;
}

SPIR-V example


  const std::string shader = R"(
               OpCapability Shader
               OpCapability Int8
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Fragment %4 "main"
               OpExecutionMode %4 OriginUpperLeft
               OpSource ESSL 320
          %2 = OpTypeVoid
          %3 = OpTypeFunction %2
          %6 = OpTypeInt 32 1
          %7 = OpTypeInt 8 1
          %9 = OpTypeInt 32 0
         %26 = OpTypeFloat 32
          %8 = OpTypeStruct %6
         %10 = OpTypePointer StorageBuffer %8
         %11 = OpVariable %10 StorageBuffer
         %19 = OpConstant %26 0
         %18 = OpConstant %9 1
         %12 = OpConstant %6 0
         %13 = OpTypePointer StorageBuffer %6
         %15 = OpConstant %6 4
         %16 = OpConstant %6 7
         %17 = OpConstant %7 4
         %20 = OpConstant %6 4 ; Release value
          %4 = OpFunction %2 None %3
          %5 = OpLabel
         %14 = OpAccessChain %13 %11 %12
         %21 = OpAtomicLoad %6 %14 %15 %20
         %24 = OpAccessChain %13 %11 %12
               OpReturn
               OpFunctionEnd
  )";

    const std::string after_transformation = R"(
               OpCapability Shader
               OpCapability Int8
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Fragment %4 "main"
               OpExecutionMode %4 OriginUpperLeft
               OpSource ESSL 320
          %2 = OpTypeVoid
          %3 = OpTypeFunction %2
          %6 = OpTypeInt 32 1
          %7 = OpTypeInt 8 1
          %9 = OpTypeInt 32 0
         %26 = OpTypeFloat 32
          %8 = OpTypeStruct %6
         %10 = OpTypePointer StorageBuffer %8
         %11 = OpVariable %10 StorageBuffer
         %19 = OpConstant %26 0
         %18 = OpConstant %9 1
         %12 = OpConstant %6 0
         %13 = OpTypePointer StorageBuffer %6
         %15 = OpConstant %6 4
         %16 = OpConstant %6 7
         %17 = OpConstant %7 4
         %20 = OpConstant %6 8 ; AcquireRelease value
          %4 = OpFunction %2 None %3
          %5 = OpLabel
         %14 = OpAccessChain %13 %11 %12
         %21 = OpAtomicLoad %6 %14 %15 %20
         %24 = OpAccessChain %13 %11 %12
               OpReturn
               OpFunctionEnd
  )";

ping @afd, @paulthomson. What do you think @paulthomson?

paulthomson commented 3 years ago

Nice thanks. This is helpful, as there are definitely some changes needed, and we can iterate quickly here.

This transformation should target an atomic instruction like OpAtomicLoad, OpAtomicStore, OpControlBarrier, OpMemoryBarrier, etc. And the transformation should change the operand that is used to a different id (that is a constant), not the OpConstant value itself because the OpConstant could be used by other instructions. So, for example:

%21 = OpAtomicLoad %6 %14 %15 %20 -> %21 = OpAtomicLoad %6 %14 %15 %100

Note that many of the atomic instructions do not have result id, so it can be difficult to refer to these instructions. This is why we have the InstructionDescriptor type. So use InstructionDescriptor to specify which atomic instruction the transformation will change.

Mostafa-ashraf19 commented 3 years ago

Improved version

Overview

The idea is to create a transformation that takes the current value of memory semantics for specific atomic instruction then changes it stronger memory order with a range of 5 bits of values.

Implementation details

The initial structure of Transformation Changing Memory Semantics, the structure of the Protobuf following by SPIR-V assembly example, before and after the transformation.


message TransformationChangingMemorySemantics {

  // This transformation is responsible for changing the mask of memory 
  // semantics with a range of 5 bits of values.

  // The atomic instruction we are looking for.
  InstructionDescriptor atomic_instruction = 1;

  // The operand index needs to change, 0 for the first memory semantics operand, 1 for the second memory 
  // semantics operand(if found).
  uint32  memory_semantics_operand_index = 2;

  // The id of new value.
  uint32  memory_semantics_new_value_id = 3;

}

SPIR-V example

    const std::string shader = R"(
               OpCapability Shader
               OpCapability Int8
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Fragment %4 "main"
               OpExecutionMode %4 OriginUpperLeft
               OpSource ESSL 320
          %2 = OpTypeVoid
          %3 = OpTypeFunction %2
          %6 = OpTypeInt 32 1
          %7 = OpTypeInt 8 1
          %9 = OpTypeInt 32 0
         %26 = OpTypeFloat 32
          %8 = OpTypeStruct %6
         %10 = OpTypePointer StorageBuffer %8
         %11 = OpVariable %10 StorageBuffer
         %19 = OpConstant %26 0
         %18 = OpConstant %9 1
         %12 = OpConstant %6 0
         %13 = OpTypePointer StorageBuffer %6
         %15 = OpConstant %6 4
         %16 = OpConstant %6 7
         %17 = OpConstant %7 4
         %20 = OpConstant %9 4
         %21 = OpConstant %6 4
        %100 = OpConstant %6 8 ; AcquireRelease value
          %4 = OpFunction %2 None %3
          %5 = OpLabel
         %14 = OpAccessChain %13 %11 %12
         %24 = OpAccessChain %13 %11 %12
               OpAtomicStore %14 %15 %20 %21
               OpReturn
               OpFunctionEnd
  )";

      const std::string after_transformation = R"(
               OpCapability Shader
               OpCapability Int8
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Fragment %4 "main"
               OpExecutionMode %4 OriginUpperLeft
               OpSource ESSL 320
          %2 = OpTypeVoid
          %3 = OpTypeFunction %2
          %6 = OpTypeInt 32 1
          %7 = OpTypeInt 8 1
          %9 = OpTypeInt 32 0
         %26 = OpTypeFloat 32
          %8 = OpTypeStruct %6
         %10 = OpTypePointer StorageBuffer %8
         %11 = OpVariable %10 StorageBuffer
         %19 = OpConstant %26 0
         %18 = OpConstant %9 1
         %12 = OpConstant %6 0
         %13 = OpTypePointer StorageBuffer %6
         %15 = OpConstant %6 4
         %16 = OpConstant %6 7
         %17 = OpConstant %7 4
         %20 = OpConstant %9 4
         %21 = OpConstant %6 4
        %100 = OpConstant %6 8 ; AcquireRelease value
          %4 = OpFunction %2 None %3
          %5 = OpLabel
         %14 = OpAccessChain %13 %11 %12
         %24 = OpAccessChain %13 %11 %12
               OpAtomicStore %14 %15 %100 %21
               OpReturn
               OpFunctionEnd
  )";

What do you think @paulthomson?

paulthomson commented 3 years ago

Looks good to me!