# 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.

tests:
  - file-name: lda.const
    isa:
      title: Create and initialize new constant array
      description: >
        Create a new single-dimensional constant literal array and put a reference to it into register.

    commands:
      - file-name: array_def_err
        description: >
          Check that compiler and/or verifier produce meaningful
          diagnostics on constant array definition error.
        isa:
          instructions:
            - sig: lda.const v:out:ref, literalarray_id
              acc: none
              format: [op_v_8_id_32]
          verification:
            - constant_literalarray_id
        runner-options: [compile-failure]
        header-template: []
        code-template: |
          .record panda.String <external>
          .record panda.Object <external>
          .record panda.Class <external>
          .record E {}
          %s
          .function i32 main() {
              lda.const v0, arr1
        check-type: exit-positive
        cases:
          - values: ['.array arr1']
          - values: ['.array arr1 i32']
          - values: ['.array arr1 i32 4']
            bugid: ['5698']
            ignore: true
          - values: ['.array arr1 i32 4 { }']
          - values: ['.array arr1 i32 4 { 1 }']
          - values: ['.array arr1 i32 4 { 1 2 3 4 5 }']
          - values: ['.array arr1 i32 0 { }']
          - values: ['.array arr1 i32[] 1 { 1 }']
          - values: ['.array arr1 panda.String 1 { }']
          - values: ['.array arr1 panda.String 1 { "" }']
            runner-options: ['compile-only']
          - values: ['.array arr1 E 1 { "" }']
          - values: ['.array arr1 xyz 1 { 0 }']
          - values: ['.array arr1 panda.String 1 { 0 }']
          - values: ['.array arr1 panda.String 1 { null }']
          - values: ['.array arr1 panda.Object 1 { "" }']
          - values: ['.array arr1 panda.Class 1 { panda.Object }']
          - values: ['.array arr1 i32 { 1 2 3 4 5 }']
          - values: ['.array arr1 i32 2 { "1" "2" }']
          - values: ['.array arr1 main 2 { 1 2 }']
          - values: ['.array 123 i32 2 { 1 2 }']


      - file-name: instr_err
        description: >
          Check that compiler and/or verifier produce meaningful diagnostics
          on lda.const syntax errors.
        isa:
          instructions:
            - sig: lda.const v:out:ref, literalarray_id
              acc: none
              format: [op_v_8_id_32]
          verification:
            - constant_literalarray_id
        header-template: []
        runner-options: [compile-failure]
        code-template: |
          .record E {}
          .array arr1 i32 4 { 1 2 3 4 }

          .function i32 main() {
              lda.const %s
        check-type: exit-positive
        cases:
          - values: ['v0']
          - values: ['v0, E']
          - values: ['v0, E[]']
          - values: ['v256, arr1']
          - values: ['v32767, arr1']
          - values: ['v32768, arr1']
          - values: ['v65535, arr1']
          - values: ['v65536, arr1']
          - values: ['a0, arr1']
          - values: ['arr1']


      - file-name: big_size_primitives
        description: >
          Check that big size literal arrays of primitives work as expected.
        isa:
          instructions:
            - sig: lda.const v:out:ref, literalarray_id
              acc: none
              format: [op_v_8_id_32]
          verification:
            - constant_literalarray_id
        header-template: []
        tags: ['irtoc_ignore']
        bugid: ['5693']
        code-template: |
          .array arr1 %s

          .function i32 main() {
              lda.const v0, arr1
              movi v1, %s
              lda v1
              %s
              inci v1, 1
              jeq v1, ok
              ldai 1
              return
          ok:
        check-type: exit-positive
        cases:
          - values:
            - "#{'i64 255 { ' + [*1..255].map do |i| \"#{i} \" end .join + '}' }"
            - 254
            - |
              #
                  ldarr.64 v0
                  i64toi32
          - values:
            - "#{'u32 511 { ' + [*1..511].map do |i| \"#{i} \" end .join + '}' }"
            - 510
            - ldarr v0
          - values:
            - "#{'i16 1024 { ' + [*1..1024].map do |i| \"#{i} \" end .join + '}' }"
            - 1023
            - ldarr.16 v0
          - values:
            - "#{'u16 4096 { ' + [*1..4096].map do |i| \"#{i} \" end .join + '}' }"
            - 4095
            - ldarru.16 v0


      - file-name: big_size_str
        description: >
          Check that big size literal arrays of strings work as expected.
        isa:
          instructions:
            - sig: lda.const v:out:ref, literalarray_id
              acc: none
              format: [op_v_8_id_32]
          verification:
            - constant_literalarray_id
        header-template: []
        tags: ['irtoc_ignore']
        code-template: |
          .record panda.String <external>
          .array arr1 %s

          .function i32 main() {
              lda.const v0, arr1
              lda.str "%s"
              sta.obj v1
              ldai %s
              %s
              jeq.obj v1, ok
              ldai 1
              return
          ok:
        check-type: exit-positive
        cases:
          - values:
            - "#{'panda.String 1024 { ' + [*1..1024].map do |i| \"\\\"#{i}\\\" \" end .join + '}' }"
            - 1024
            - 1023
            - ldarr.obj v0
            bugid: ['5693']
          - values:
            - "#{'panda.String 4096 { ' + [*1..4096].map do |i| \"\\\"#{i}\\\" \" end .join + '}' }"
            - 4001
            - 4000
            - ldarr.obj v0
            bugid: ['5696']


      - file-name: values_u1
        description: >
          Check values in literal array.
        isa:
          instructions:
            - sig: lda.const v:out:ref, literalarray_id
              acc: none
              format: [op_v_8_id_32]
        header-template: []
        tags: ['irtoc_ignore']
        bugid: ['5693']
        code-template: |
          .array v1 %s

          .function i32 main() {
              lda.const v0, v1
              movi v1, %s        # index
              movi v15, %s       # value at index
          loop:
              lda v1
              jltz ok
              %s
              jne v15, err
              inci v1, -1
              lda v15
              xori 1
              sta v15
              jmp loop
          err:
              ldai 1
              return
          ok:
        check-type: exit-positive
        cases:
          - values:
            - "#{'u1 2560 { ' + [*0..2559].map do |i| \"#{i%2} \" end .join + '}' }"
            - 2559
            - 1
            - ldarru.8 v0


      - file-name: values_i32
        description: >
          Check values in literal array.
        isa:
          instructions:
            - sig: lda.const v:out:ref, literalarray_id
              acc: none
              format: [op_v_8_id_32]
        header-template: []
        tags: ['irtoc_ignore']
        bugid: ['5693']
        code-template: |
          .array v1 %s

          .function i32 main() {
              lda.const v0, v1
              movi v1, %s        # index
              movi v15, %s       # value at index
          loop:
              lda v1
              jltz ok
              %s
              jne v15, err
              inci v1, -1
              inci v15, -1
              jmp loop
          err:
              ldai 1
              return
          ok:
        check-type: exit-positive
        cases:
          - values:
            - "#{'i8 256 { ' + [*-128..127].map do |i| \"#{i} \" end .join + '}' }"
            - 255
            - 127
            - ldarr.8 v0
          - values:
            - "#{'u8 256 { ' + [*0..255].map do |i| \"#{i} \" end .join + '}' }"
            - 255
            - 255
            - ldarru.8 v0
          - values:
            - "#{'i16 512 { ' + [*-206..305].map do |i| \"#{i} \" end .join + '}' }"
            - 511
            - 305
            - ldarr.16 v0
          - values:
            - "#{'u16 512 { ' + [*65024..65535].map do |i| \"#{i} \" end .join + '}' }"
            - 511
            - 0xffff
            - ldarru.16 v0
          - values:
            - "#{'i32 100 { ' + [*-2147483648..-2147483549].map do |i| \"#{i} \" end .join + '}' }"
            - 99
            - -2147483549
            - ldarr v0
            tags: [sanitizer-fail]


      - file-name: values_i64
        description: >
          Check values in literal array.
        isa:
          instructions:
            - sig: lda.const v:out:ref, literalarray_id
              acc: none
              format: [op_v_8_id_32]
        header-template: []
        tags: ['irtoc_ignore']
        bugid: ['5693']
        code-template: |
          .array v1 %s

          .function i32 main() {
              movi.64 v2, 1
              lda.const v0, v1
              movi v1, %s        # index
              movi.64 v15, %s    # value at index
          loop:
              lda v1
              jltz ok
              %s
              cmp.64 v15
              jnez err
              inci v1, -1
              lda.64 v15
              sub2.64 v2
              sta.64 v15
              jmp loop
          err:
              ldai 1
              return
          ok:
        check-type: exit-positive
        cases:
          - values:
            - "#{'i64 45 { ' + [*9223372036854775763..9223372036854775807].map do |i| \"#{i} \" end .join + '}' }"
            - 44
            - 0x7fffffffffffffff
            - ldarr.64 v0


      - file-name: values_f32
        description: >
          Check values in literal array of f32.
        isa:
          instructions:
            - sig: lda.const v:out:ref, literalarray_id
              acc: none
              format: [op_v_8_id_32]
        header-template: []
        tags: ['irtoc_ignore']
        bugid: ['5693']
        code-template: |
          .array v1 %s

          .function i32 main() {
              fmovi v2, 10.0
              lda.const v0, v1
              movi v1, %s        # index
              fmovi v15, %s      # value at index
          loop:
              lda v1
              jltz ok
              fldarr.32 v0
              fcmpg v15
              jnez err
              inci v1, -1
              lda v15
              fdiv2 v2
              sta v15
              jmp loop
          err:
              ldai 1
              return
          ok:
        check-type: exit-positive
        cases:
          - values:
            - f32 10 { 1.0 10.0 100.0 1000.0 10000 100000 1000000 10000000 1e8 1e9 }
            - 9
            - 1000000000


      - file-name: values_f64
        description: >
          Check values in literal array of f64.
        isa:
          instructions:
            - sig: lda.const v:out:ref, literalarray_id
              acc: none
              format: [op_v_8_id_32]
        header-template: []
        tags: ['irtoc_ignore']
        bugid: ['5693']
        code-template: |
          .array v1 %s

          .function i32 main() {
              fmovi.64 v2, 10.0
              lda.const v0, v1
              movi v1, %s        # index
              fmovi.64 v15, %s   # value at index
          loop:
              lda v1
              jltz ok
              fldarr.64 v0
              fcmpg.64 v15
              jnez err
              inci v1, -1
              lda.64 v15
              fdiv2.64 v2
              sta.64 v15
              jmp loop
          err:
              ldai 1
              return
          ok:
        check-type: exit-positive
        cases:
          - values:
            - "#{'f64 10 { ' + [*-4..5].map do |i| \"1e#{i} \" end .join + '}' }"
            - 9
            - 1e5


      - file-name: values_str
        description: >
          Check values in literal array.
        isa:
          instructions:
            - sig: lda.const v:out:ref, literalarray_id
              acc: none
              format: [op_v_8_id_32]
        header-template: []
        tags: ['irtoc_ignore']
        bugid: ['5693']
        code-template: |
          .record panda.String <external>
          .array v1 %s

          .function i32 main() {
              lda.const v0, v1
              movi v1, %s        # size, then index
          %s
              jmp ok
          err:
              ldai 1
              return
          ok:
        check-type: exit-positive
        cases:
          - values:
            - "#{'panda.String 300 { ' + [*0..299].map do |i| \"\\\"#{i}\\\" \" end .join + '}' }"
            - 300
            - "#{[*0..299].map do |i| \"    inci v1, -1\\n    lda v1\\n    ldarr.obj v0\\n    sta.obj v2\\n    lda.str \\\"#{299-i}\\\"\\n    jne.obj v2, err\\n\" end .join }"


      - file-name: primitive_types_p
        description: Check acceptable array of primitive types in Panda Assembly context.
        isa:
          instructions:
            - sig: lda.const v:out:ref, literalarray_id
              acc: none
              format: [op_v_8_id_32]
        tags: ['verifier']
        header-template: []
        runner-options: ['verifier-only', 'verifier-config']
        code-template: |
          .array v0 %s
          .function i32 main() {
              lda.const v0, v0
        check-type: exit-positive
        cases:
          - values: ['u1  1 { 1 }']
          - values: ['u8  1 { 1 }']
          - values: ['i8  1 { 1 }']
          - values: ['u16 1 { 1 }']
          - values: ['i16 1 { 1 }']
          - values: ['u32 1 { 1 }']
          - values: ['i32 1 { 1 }']
          - values: ['u64 1 { 1 }']
          - values: ['i64 1 { 1 }']
          - values: ['f32 1 { 1 }']
          - values: ['f64 1 { 1 }']


      - file-name: primitive_types_j
        description: Check acceptable array of primitive types in PandaAssembly context.
        isa:
          instructions:
            - sig: lda.const v:out:ref, literalarray_id
              acc: none
              format: [op_v_8_id_32]
        tags: [verifier, pa-verifier]
        header-template: []
        runner-options: ['verifier-only', 'verifier-config', 'use-pa']
        code-template: |
          .language PandaAssembly
          .array v0 %s
          .function i32 main() {
              lda.const v0, v0
        check-type: exit-positive
        cases:
          - values: ['u1  1 { 1 }']
          - values: ['u8  1 { 1 }']
            runner-options: ['verifier-failure', 'verifier-config', 'use-pa']
            bugid: ['5694']
          - values: ['i8  1 { 1 }']
          - values: ['u16 1 { 1 }']
          - values: ['i16 1 { 1 }']
          - values: ['u32 1 { 1 }']
            runner-options: ['verifier-failure', 'verifier-config', 'use-pa']
            bugid: ['5694']
          - values: ['i32 1 { 1 }']
          - values: ['u64 1 { 1 }']
            runner-options: ['verifier-failure', 'verifier-config', 'use-pa']
            bugid: ['5694']
          - values: ['i64 1 { 1 }']
          - values: ['f32 1 { 1 }']
          - values: ['f64 1 { 1 }']


      - file-name: array_out_of_bounds_p
        isa:
          instructions:
            - sig: lda.const v:out:ref, literalarray_id
              acc: none
              format: [op_v_8_id_32]
        description: Check that ArrayIndexOutOfBoundsException is thrown for literal array.
        header-template: []
        tags: ['irtoc_ignore']
        bugid: ['5693']
        code-template: |
          .record panda.ArrayIndexOutOfBoundsException <external>
          .array arr1 %s

          .function i32 main() {
              lda.const v0, arr1
          begin:
              ldai %s
              %s
          end:
              ldai 1 # Should not reach this line
              return

          catch_AOOBE:
              ldai 0 # Expected panda.ArrayIndexOutOfBoundsException
              return

          catch_all:
              ldai 2 # Unexpected exception, test failed
              return

          .catch panda.ArrayIndexOutOfBoundsException, begin, end, catch_AOOBE
          .catchall begin, end, catch_all
        check-type: none
        cases:
          - values:
            - i32 4 { 1 2 3 4 }
            - 4
            - ldarr v0
          - values:
            - u8 1 { 0xff }
            - 65536
            - ldarru.8 v0


      - file-name: array_out_of_bounds_j
        isa:
          instructions:
            - sig: lda.const v:out:ref, literalarray_id
              acc: none
              format: [op_v_8_id_32]
        description: Check that ArrayIndexOutOfBoundsException is thrown for literal array.
        runner-options: [use-pa]
        header-template: []
        tags: ['irtoc_ignore']
        bugid: ['5693']
        code-template: |
          .language PandaAssembly
          .record panda.Object <external>
          .record panda.String <external>
          .record panda.ArrayIndexOutOfBoundsException <external>
          .array arr1 %s

          .function panda.Object load_array() {
              lda.const v0, arr1
              ldai %s
              %s
              lda.obj v0
              return.obj
          }

          .function i32 main() {
          begin:
              call.short load_array
          end:
              ldai 1 # Should not reach this line
              return

          catch_AOOBE:
              ldai 0 # Expected panda.ArrayIndexOutOfBoundsException
              return

          catch_all:
              ldai 2 # Unexpected exception, test failed
              return

          .catch panda.ArrayIndexOutOfBoundsException, begin, end, catch_AOOBE
          .catchall begin, end, catch_all
        check-type: none
        cases:
          - values:
            - f64 3 { 0 1.1 2.2 }
            - -3
            - fldarr.64 v0
          - values:
            - panda.String 10 { "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" }
            - 10
            - ldarr.obj v0