# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

definitions:
  - name: pandasm_header
    template: |
      .language PandaAssembly
      .record panda.Object <external>
      .record Q {}
      .record R {
        u1             fu1
        u8             fu8
        i8             fi8
        u16            fu16
        i16            fi16
        u32            fu32
        i32            fi32
        u64            fu64
        i64            fi64
        f32            ff32
        f64            ff64
        # objects:
        i32[]          fi32Array
        Q              fQ
        Q[]            fQArray
        panda.Object   fObj
        panda.Object[] fObjArray
      }

  - name: PandaAssembly_header
    template: |
      .language PandaAssembly
      .record panda.Object <external>
      .record I <panda.interface> {}
      .record Q <panda.implements=I> {}
      .record R <panda.extends=Q> {
        u1                 fu1
        i8                 fi8
        u16                fu16
        i16                fi16
        i32                fi32
        i64                fi64
        f32                ff32
        f64                ff64
        # objects
        i32[]              fi32Array
        Q                  fQ
        Q[]                fQArray
        R                  fR
        R[]                fRArray
        I                  fI
        I[]                fIArray
        panda.Object   fObj
        panda.Object[] fObjArray
      }


tests:
  - file-name: "stobj.v"
    isa:
      title: Store register content into object field
      description: >
        Store register content into object field by field_id. For non-object variant the size of actually stored
        value is determined by field_id, other register bits are discarded.
      instructions:
        - sig: stobj.v v1:in:b32, v2:in:ref, field_id
          acc: none
          format: [op_v1_4_v2_4_id_16]
    commands:

      - file-name: "check_if_regs_initialized_p"
        description: Check that verifier reports error if a register is not initialized in PandaAssembly context.
        isa:
          description: Store register content into object field by field_id.
        header-template: ['pandasm_header']
        check-type: exit-positive
        tags: ['verifier']
        runner-options: ['verifier-failure', 'verifier-config']
        code-template: |

          %s

          .function i32 main() {
            newobj v0, R
            movi v1, 1
            %s
        cases:
          - values:
            - ""
            - stobj.v v2, v0, R.fi32
          - values:
            - ""
            - stobj.v v1, v2, R.fi32
          - values:
            - |
              # v0 (value) not initialized in the frame
              .function void check(R a0) <static> {
                stobj.v v0, a0, R.fi32
                return.void
              }
            - call.short check, v0
          - values:
            - |
              # v0 (object) not initialized in the frame
              .function void check(i32 a0) <static> {
                stobj.v a0, v0, R.fi32
                return.void
              }
            - call.short check, v1


      - file-name: "check_if_regs_initialized_j"
        description: Check that verifier reports error if a register is not initialized in PandaAssembly context
        isa:
          description: Store register content into object field by field_id.
        header-template: ['PandaAssembly_header']
        check-type: exit-positive
        tags: [verifier, pa-verifier]
        runner-options: ['use-pa', 'verifier-failure', 'verifier-config']
        code-template: |

          %s

          .function i32 main() {
            newobj v0, R
            movi v1, 1
            %s
        cases:
          - values:
            - ""
            - stobj.v v2, v0, R.fi32
          - values:
            - ""
            - stobj.v v1, v2, R.fi32
          - values:
            - |
              # v0 (value) not initialized in the frame
              .function void check(R a0) <static> {
                stobj.v v0, a0, R.fi32
                return.void
              }
            - call.short check, v0
          - values:
            - |
              # v0 (object) not initialized in the frame
              .function void check(i32 a0) <static> {
                stobj.v a0, v0, R.fi32
                return.void
              }
            - call.short check, v1


      - file-name: "with_null_ref_p"
        description: Check that NullPointerException is thrown if object ref is null in PandaAssembly context
        isa:
          exceptions:
            - x_null
        header-template: ['pandasm_header']
        check-type: empty
        tags: ['irtoc_ignore']
        code-template: |
          .record panda.NullPointerException <external>

          .function R get_null() {
            lda.null
            return.obj
          }

          .function i32 main() {
            call.short get_null
            sta.obj v0
            %s
          try_begin:
            stobj.v v1, v0, %s
            ldai 1
            return
          try_end:
            ldai 0
            return
          .catch panda.NullPointerException, try_begin, try_end, try_end
          }
        cases:
          - values:
            - movi v1, 1
            - R.fu1
          - values:
            - movi v1, 1
            - R.fu8
          - values:
            - movi v1, 1
            - R.fi8
          - values:
            - movi v1, 1
            - R.fu16
          - values:
            - movi v1, 1
            - R.fi16
          - values:
            - movi v1, 1
            - R.fu32
          - values:
            - movi v1, 1
            - R.fi32
          - values:
            - fmovi v1, -1.1
            - R.ff32


      - file-name: "with_null_ref_j"
        description: Check that NullPointerException is thrown if object ref is null in PandaAssembly context
        isa:
          exceptions:
            - x_null
        header-template: ['PandaAssembly_header']
        runner-options: ['use-pa']
        check-type: empty
        tags: ['irtoc_ignore']
        code-template: |
          .record panda.NullPointerException <external>

          .function R get_null() {
            lda.null
            return.obj
          }

          .function i32 main() {
            call.short get_null
            sta.obj v0
            %s
          try_begin:
            stobj.v v1, v0, %s
            ldai 1
            return
          try_end:
            ldai 0
            return
          .catch panda.NullPointerException, try_begin, try_end, try_end
          }
        cases:
          - values:
            - movi v1, 1
            - R.fu1
          - values:
            - movi v1, 1
            - R.fi8
          - values:
            - movi v1, 1
            - R.fu16
          - values:
            - movi v1, 1
            - R.fi16
          - values:
            - movi v1, 1
            - R.fi32
          - values:
            - fmovi v1, 1.1
            - R.ff32


      - file-name: "with_non_object_ref_p"
        description: Check that verifier reports error when the 2nd register is not a ref to an object (other than array) in PandaAssembly context
        isa:
          verification:
            - v2_object
        header-template: ['pandasm_header']
        check-type: exit-positive
        tags: ['verifier']
        runner-options: ['verifier-failure', 'verifier-config']
        code-template: |

          .function i32 main() {
            *s
            movi v1, 1
            stobj.v v1, v0, %s
        template-cases:
          - values: ['R.fu1']
            bugid: ['5502']
          - values: ['R.fi8']
            bugid: ['5502']
            ignore: true
          - values: ['R.fu8']
            bugid: ['5502']
            ignore: true
          - values: ['R.fi16']
            bugid: ['5502']
            ignore: true
          - values: ['R.fu16']
            bugid: ['5502']
            ignore: true
          - values: ['R.fi32']
          - values: ['R.fu32']
            bugid: ['5502']
            ignore: true
        cases:
          - values:
            - movi v0, 0
          - values:
            - movi v0, 1
          - values:
            - movi.64 v0, 0x00
          - values:
            - movi.64 v0, 0xCAFECAFECAFECAFE
          - values:
            - fmovi.64 v0, 0.0
          - values:
            - fmovi.64 v0, 6.62607015
          - values:
            - |
              #
                movi v1, 10
                newarr v0, v1, panda.Object[]


      - file-name: "with_non_object_ref_j"
        description: Check that verifier reports error when the 2nd register is not a ref to an object (other than array) in PandaAssembly context
        isa:
          verification:
            - v2_object
        header-template: ['PandaAssembly_header']
        check-type: exit-positive
        tags: [verifier, pa-verifier]
        runner-options: ['use-pa', 'verifier-failure', 'verifier-config']
        code-template: |

          .function i32 main() {
            *s
            movi v1, 1
            stobj.v v1, v0, %s
        template-cases:
          - values: ['R.fu1']
            bugid: ['5502']
          - values: ['R.fi8']
            bugid: ['5502']
            ignore: true
          - values: ['R.fi16']
            bugid: ['5502']
            ignore: true
          - values: ['R.fu16']
            bugid: ['5502']
            ignore: true
          - values: ['R.fi32']
        cases:
          - values:
            - movi v0, 0
          - values:
            - movi v0, 1
          - values:
            - movi.64 v0, 0x00
          - values:
            - movi.64 v0, 0xCAFECAFECAFECAFE
          - values:
            - fmovi.64 v0, 0.0
          - values:
            - fmovi.64 v0, 6.62607015
          - values:
            - |
              #
                movi v1, 10
                newarr v0, v1, panda.Object[]


      - file-name: "with_static_field_id_p"
        description: >
          Check that verifier reports error if the field doesn't resolve to
          a non-static valid object field in PandaAssembly context
        isa:
          verification:
            - field_id_non_static
        header-template: []
        check-type: exit-positive
        runner-options: ['compile-failure']
        code-template: |
          .record W {
            i32   static_field  <static>
          }
          .record random_record {
            i32 random_field
            i32 random_static_field <static>
          }
          .function void random_function() {
            return.void
          }

          .function i32 main() {
            newobj v0, W
            movi v2, 1
            stobj.v v2, v0, %s
        cases:
          - values:
            - W.static_field
            runner-options: ['verifier-failure', 'verifier-config']
            tags: ['verifier']
          - values:
            - random_record
          - values:
            - random_function
          - values:
            - W.field_not_exists
          - values:
            - random_record.random_field
            runner-options: ['verifier-failure', 'verifier-config']
            tags: ['verifier']
          - values:
            - random_record.random_static_field
            runner-options: ['verifier-failure', 'verifier-config']
            tags: ['verifier']
          - values:
            - 0
          - values:
            - -1.1
          - values:
            - "null"
          - values:
            - "\"abc\""


      - file-name: "with_static_field_id_j"
        description: >
          Check that verifier reports error if the field doesn't resolve to
          a non-static valid object field in PandaAssembly context
        isa:
          verification:
            - field_id_non_static
        header-template: []
        check-type: exit-positive
        runner-options: ['use-pa', 'verifier-failure', 'verifier-config']
        tags: [verifier, pa-verifier]
        code-template: |
          .language PandaAssembly
          .record A {
            i32   a_field  <static>
          }
          .record B <panda.extends=A> {
            i32   b_field  <static>
          }
          .record C <panda.extends=B> {
            i32   c_field  <static>
          }

          .function i32 main() {
            newobj v0, %s
            movi v2, 1
            stobj.v v2, v0, %s
        cases:
          - values:
            - C
            - C.c_field
          - values:
            - C
            - B.b_field
          - values:
            - C
            - A.a_field
          - values:
            - B
            - B.a_field
            runner-options: ['compile-failure']
          - values:
            - B
            - B.c_field
            runner-options: ['compile-failure']


      - file-name: "with_wrong_field_size_p"
        description: >
          Check that verifier reports error when the field resolves to a field with size
          that is not corresponding to bytecode in PandaAssembly context.
        isa:
          verification:
            - field_id_size
        header-template: ['pandasm_header']
        check-type: exit-positive
        tags: ['verifier']
        runner-options: ['verifier-failure', 'verifier-config']
        code-template: |
          .function i32 main() {
            newobj v0, R
            %s
            stobj.v v2, v0, %s
        cases:
          - values:
            - movi v2, 0
            - R.fi64
          - values:
            - movi v2, 0
            - R.fu64
          - values:
            - fmovi v2, 0.0
            - R.ff64
          - values:
            - movi v2, 0
            - R.fObj
          - values:
            - movi v2, 0
            - R.fObjArray
          - values:
            - movi v2, 0
            - R.fi32Array


      - file-name: "with_wrong_field_size_j"
        description: Check that verifier reports error when the field resolves to a field with size that is not corresponding to bytecode in PandaAssembly context.
        isa:
          verification:
            - field_id_size
        header-template: ['PandaAssembly_header']
        check-type: exit-positive
        tags: [verifier, pa-verifier]
        runner-options: ['use-pa', 'verifier-failure', 'verifier-config']
        code-template: |
          .function i32 main() {
            newobj v0, R
            %s
            stobj.v v2, v0, %s
        cases:
          - values:
            - movi v2, 0
            - R.fi64
          - values:
            - fmovi v2, 0.0
            - R.ff64
          - values:
            - fmovi v2, 0.1
            - R.fObj
          - values:
            - movi v2, 0
            - R.fObjArray
          - values:
            - movi v2, 0
            - R.fi32Array
          - values:
            - fmovi v2, 0.2
            - R.fI
          - values:
            - movi v2, 0
            - R.fIArray


      - file-name: "with_correct_field_size_or_type"
        description: Check that verifier does not report any error when the field has size or type corresponding to bytecode
        isa:
          verification:
            - field_id_size
        header-template: ['pandasm_header']
        check-type: exit-positive
        tags: ['verifier']
        runner-options: ['verifier-only', 'verifier-config']
        code-template: |
          .function i32 main() {
            newobj v0, R
            %s
            stobj.v v2, v0, %s
        cases:
          - values:
            - movi v2, 1
            - R.fu1
          - values:
            - movi v2, 1
            - R.fu8
          - values:
            - movi v2, -1
            - R.fi8
          - values:
            - movi v2, 1
            - R.fu16
          - values:
            - movi v2, -1
            - R.fi16
          - values:
            - movi v2, 1
            - R.fu32
          - values:
            - movi v2, -1
            - R.fi32
          - values:
            - fmovi v2, -0.1
            - R.ff32


      - file-name: "with_wrong_reg_type_p"
        description: Check that verifier reports error when the register contains a value of type not corresponding to the bytecode in PandaAssembly context
        isa:
          verification:
            - v1_type
        header-template: ['pandasm_header']
        check-type: exit-positive
        tags: ['verifier']
        runner-options: ['verifier-failure', 'verifier-config']
        code-template: |
          .function i32 main() {
            newobj v0, R
            %s
            stobj.v v1, v0, %s
        cases:
          - values:
            - movi.64 v1, 0xF000F000F000F000
            - R.fu1
            bugid: ['4166']
          - values:
            - movi.64 v1, 0
            - R.fi8
            bugid: ['4166']
          - values:
            - movi.64 v1, 0xCAFECAFECAFECAFE
            - R.fu8
            bugid: ['4166']
          - values:
            - movi.64 v1, 0
            - R.fi16
            bugid: ['4166']
          - values:
            - movi.64 v1, 0x5A5A5A5A5A5A5A5A
            - R.fi32
            bugid: ['4166']
          - values:
            - movi.64 v1, 1234567890
            - R.fu32
            bugid: ['4166']
          - values:
            - fmovi.64 v1, 0x7FFFFFFFFFFFFFFF
            - R.fu1
          - values:
            - fmovi.64 v1, 0.0
            - R.fu8
          - values:
            - fmovi.64 v1, -0.0
            - R.fi8
          - values:
            - fmovi.64 v1, 1.0
            - R.fu16
          - values:
            - fmovi.64 v1, 3.0
            - R.fi16
          - values:
            - fmovi.64 v1, 0.123456
            - R.fu32
          - values:
            - fmovi.64 v1, 123456.0
            - R.fi32
          - values:
            - movi.64 v1, 7890
            - R.ff32
          - values:
            - fmovi.64 v1, 7890.0
            - R.ff32
            bugid: ['4166']
          - values:
            - mov.null v1
            - R.fu32
          - values:
            - newobj v1, panda.Object
            - R.fi32
          - values:
            - |
              #
                movi v1, 10
                newarr v1, v1, i32[]
            - R.fi32


      - file-name: "with_wrong_reg_type_j"
        description: >
          Check that verifier reports error when the register contains
          a value of type not corresponding to the bytecode in PandaAssembly context.
        isa:
          verification:
            - v1_type
        header-template: ['PandaAssembly_header']
        check-type: exit-positive
        tags: [verifier, pa-verifier]
        runner-options: ['use-pa', 'verifier-failure', 'verifier-config']
        code-template: |
          .function i32 main() {
            newobj v0, R
            %s
            stobj.v v1, v0, %s
        cases:
          - values:
            - movi.64 v1, 0xF000F000F000F000
            - R.fu1
            bugid: ['4166']
          - values:
            - movi.64 v1, 0
            - R.fi8
            bugid: ['4166']
          - values:
            - movi.64 v1, 0
            - R.fi16
            bugid: ['4166']
          - values:
            - movi.64 v1, 0x5A5A5A5A5A5A5A5A
            - R.fi32
            bugid: ['4166']
          - values:
            - fmovi.64 v1, 0x7FFFFFFFFFFFFFFF
            - R.fu1
          - values:
            - fmovi.64 v1, -0.0
            - R.fi8
          - values:
            - fmovi.64 v1, 1.0
            - R.fu16
          - values:
            - fmovi.64 v1, 3.0
            - R.fi16
          - values:
            - fmovi.64 v1, 123456.0
            - R.fi32
          - values:
            - movi.64 v1, 7890
            - R.ff32
          - values:
            - fmovi.64 v1, 7890.0
            - R.ff32
            bugid: ['4166']
          - values:
            - mov.null v1
            - R.fi32
          - values:
            - newobj v1, Q
            - R.fi16
          - values:
            - |
              #
                movi v1, 10
                newarr v1, v1, i32[]
            - R.fi32
          - values:
            - |
              #
                movi v1, 10
                newarr v1, v1, panda.Object[][]
            - R.fi8


      - file-name: "op_v1_4_v2_4_id_16"
        description: Check that compiler reports error when the register number is out of 4 bit size
        isa:
          instructions:
            - sig: stobj.v v1:in:b32, v2:in:ref, field_id
              acc: none
              format: [op_v1_4_v2_4_id_16]
        header-template: ['pandasm_header']
        runner-options: ['compile-failure']
        check-type: exit-positive
        code-template: |

          .function i32 main() {
            stobj.v %s, R.fi32
        cases:
          - values: ['v15, v15']
            runner-options: ['compile-only']
          - values: ['v16, v15']
          - values: ['v15, v16']
          - values: ['v255, v0']
          - values: ['v15, v256']
          - values: ['v65535, v65535']
          - values: ['v32767, v0']


      - file-name: "into_all_unsigned_field_types"
        description: Check that register value is stored in field. Unsigned cases.
        isa:
          description: If field type size is less than 32, register content will be truncated to storage size before storing.
        header-template: ['pandasm_header']
        check-type: exit-positive
        tags: ['tsan', 'irtoc_ignore']
        code-template: |

          .function i32 main() {
            movi v7, 123456789
            newobj v0, R
            %s
            ldai 123456789
            stobj.v v1, v0, R.%s
            jeq v7, cont   # check acc_none
            ldai 2
            return
          cont:
            ldobj.v v2, v0, R.%s
            lda v2
            movi v1, %s
            ucmp v1
            jeqz success
            ldai 1
            return
          success:
        cases:
          # u1
          - values: ['movi v1, 0x00000000', 'fu1', 'fu1', 0]
          - values: ['movi v1, 0xffffffff', 'fu1', 'fu1', 1]
            bugid: ['1848']
            ignore: true
          - values: ['movi v1, 0x00000001', 'fu1', 'fu1', 1]
          - values: ['movi v1, 0xfffffffe', 'fu1', 'fu1', 0]
            bugid: ['1848']
            ignore: true
          - values: ['movi v1, 0x11111111', 'fu1', 'fu1', 1]
            bugid: ['1848']
            ignore: true
          - values: ['movi v1, 0x88888888', 'fu1', 'fu1', 0]
            bugid: ['1848']
            ignore: true
          # u8
          - values: ['movi v1, 0x00000000', 'fu8', 'fu8', 0]
          - values: ['movi v1, 0xffffffff', 'fu8', 'fu8', 255]
          - values: ['movi v1, 0x000000ff', 'fu8', 'fu8', 255]
          - values: ['movi v1, 0xffffff00', 'fu8', 'fu8', 0]
          - values: ['movi v1, 0x11111111', 'fu8', 'fu8', 17]
          - values: ['movi v1, 0x88888888', 'fu8', 'fu8', 136]
          # u16
          - values: ['movi v1, 0x00000000', 'fu16', 'fu16', 0]
          - values: ['movi v1, 0xffffffff', 'fu16', 'fu16', 65535]
          - values: ['movi v1, 0x0000ffff', 'fu16', 'fu16', 65535]
          - values: ['movi v1, 0xffff0000', 'fu16', 'fu16', 0]
          - values: ['movi v1, 0x11111111', 'fu16', 'fu16', 4369]
          - values: ['movi v1, 0x88888888', 'fu16', 'fu16', 34952]
          # u32
          - values: ['movi v1, 0x00000000', 'fu32', 'fu32', 0]
          - values: ['movi v1, 0xffffffff', 'fu32', 'fu32', 4294967295]
          - values: ['movi v1, 0x11111111', 'fu32', 'fu32', 286331153]
          - values: ['movi v1, 0x88888888', 'fu32', 'fu32', 2290649224]


      - file-name: "into_float_field_type"
        description: Check that register value is stored in field.
        isa:
          instructions:
            - sig: stobj.v v1:in:b32, v2:in:ref, field_id
              acc: none
              format: [op_v1_4_v2_4_id_16]
        header-template: ['pandasm_header']
        check-type: exit-positive
        tags: ['tsan', 'irtoc_ignore']
        code-template: |
          .function i32 main() {
            movi v7, 5151515
            newobj v0, R
            %s
            ldai 5151515
            stobj.v v1, v0, R.%s
            jeq v7, cont   # check acc_none
            ldai 2
            return
          cont:
            ldobj.v v2, v0, R.%s
            lda v2
            %s
            jeqz success
            ldai 1
            return
          success:
        cases:
          # f32
          - values:
            - fmovi v1, 0.0
            - ff32
            - ff32
            - |
              #
                fmovi v1, 0.0
                fcmpg v1
          - values:
            - fmovi v1, -6510615.0
            - ff32
            - ff32
            - |
              #
                fmovi v1, -6510615.0
                fcmpg v1
          - values:
            - fmovi v1, 0x7fffffff  # NaN
            - ff32
            - ff32
            - |
              #
                fmovi v1, 0.0
                fcmpg v1
                subi 1
          - values:
            - fmovi v1, 0x7f800000  # + Inf
            - ff32
            - ff32
            - |
              #
                fmovi v1, 0x7f800000
                fcmpg v1
          - values:
            - fmovi v1, 0xff800000  # - Inf
            - ff32
            - ff32
            - |
              #
                fmovi v1, 0xff800000
                fcmpg v1


      - file-name: "into_all_field_types_int"
        description: Check that register value is stored in field. Version for signed types.
        isa:
          description: If field type size is less than 32, register content will be truncated to storage size before storing.
        header-template: ['pandasm_header']
        check-type: exit-positive
        tags: ['tsan', 'irtoc_ignore']
        code-template: |

          .function i32 main() {
            movi v7, 123456789
            newobj v0, R
            %s
            ldai 123456789
            stobj.v v1, v0, R.%s
            jeq v7, cont   # check acc_none
            ldai 2
            return
          cont:
            ldobj.v v2, v0, R.%s
            lda v2
            movi v1, %s
            jeq v1, success
            ldai 1
            return
          success:
        cases:
          # i8
          - values: ['movi v1, 0x00000000', 'fi8', 'fi8', 0]
          - values: ['movi v1, 0xffffffff', 'fi8', 'fi8', -1]
          - values: ['movi v1, 0x000000ff', 'fi8', 'fi8', -1]
          - values: ['movi v1, 0xffffff00', 'fi8', 'fi8', 0]
          - values: ['movi v1, 0x11111111', 'fi8', 'fi8', 17]
          - values: ['movi v1, 0x88888888', 'fi8', 'fi8', -120]
          # i16
          - values: ['movi v1, 0x00000000', 'fi16', 'fi16', 0]
          - values: ['movi v1, 0xffffffff', 'fi16', 'fi16', -1]
          - values: ['movi v1, 0x0000ffff', 'fi16', 'fi16', -1]
          - values: ['movi v1, 0xffff0000', 'fi16', 'fi16', 0]
          - values: ['movi v1, 0x11111111', 'fi16', 'fi16', 4369]
          - values: ['movi v1, 0x88888888', 'fi16', 'fi16', -30584]
          # i32
          - values: ['movi v1, 0x00000000', 'fi32', 'fi32', 0]
          - values: ['movi v1, 0xffffffff', 'fi32', 'fi32', -1]
          - values: ['movi v1, 0x11111111', 'fi32', 'fi32', 286331153]
          - values: ['movi v1, 0x88888888', 'fi32', 'fi32', -2004318072]