mirror of
https://gitee.com/openharmony/arkcompiler_runtime_core
synced 2024-11-27 17:00:40 +00:00
c658ccf319
Issue: https://gitee.com/openharmony/arkcompiler_runtime_core/issues/I5G96F Test: Test262 suit, ark unittest, rk3568 XTS, ark previewer demo Signed-off-by: huangyu <huangyu76@huawei.com> Change-Id: I3f63d129a07deaa27a390f556dcaa5651c098185
201 lines
6.2 KiB
Ruby
201 lines
6.2 KiB
Ruby
# 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.
|
|
|
|
def assert(name)
|
|
loc = caller_locations(1, 1).first
|
|
raise "#{loc.path}:#{loc.lineno}: '#{name}' assertion failed" unless yield
|
|
end
|
|
|
|
module Enumerable
|
|
def sorted?
|
|
each_cons(2).all? { |a, b| (a <=> b) <= 0 }
|
|
end
|
|
|
|
def sorted_by?(&block)
|
|
map(&block).sorted?
|
|
end
|
|
|
|
def uniq?
|
|
uniq.size == size
|
|
end
|
|
end
|
|
|
|
assert('Unique opcodes') { Panda.instructions.map(&:opcode).uniq? }
|
|
|
|
assert('Non-prefixed instruction opcodes and prefixes should fit one byte') do
|
|
Panda.instructions.reject(&:prefix).size + Panda.prefixes.size <= 256
|
|
end
|
|
|
|
assert('Non-prefixed instruction opcode indexes are sorted') do
|
|
Panda.instructions.reject(&:prefix).sorted_by?(&:opcode_idx)
|
|
end
|
|
|
|
assert('Prefix opcode indexes are sorted') do
|
|
Panda.prefixes.sorted_by?(&:opcode_idx)
|
|
end
|
|
|
|
assert('All instructions for a prefix should fit one byte') do
|
|
Panda.prefixes.map do |prefix|
|
|
Panda.instructions.select { |insn| insn.prefix && (insn.prefix.name == prefix.name) }.size <= 256
|
|
end.all?
|
|
end
|
|
|
|
assert('Prefixed instruction should have some prefix specified') do
|
|
Panda.instructions.map do |insn|
|
|
insn.format.prefixed? != insn.prefix.nil?
|
|
end.all?
|
|
end
|
|
|
|
assert('Prefix should be defined') do
|
|
Panda.instructions.map do |insn|
|
|
next true unless insn.prefix
|
|
|
|
Panda.prefixes.map(&:name).include?(insn.prefix.name)
|
|
end.all?
|
|
end
|
|
|
|
assert('All prefixes should have unique name') do
|
|
Panda.prefixes.map(&:name).uniq?
|
|
end
|
|
|
|
assert('There should be non-zero gap between non-prefixed and prefixes') do
|
|
!Panda.dispatch_table.invalid_non_prefixed_interval.to_a.empty?
|
|
end
|
|
|
|
assert('There should be non-zero gap between public and private prefixes') do
|
|
!Panda.dispatch_table.invalid_prefixes_interval.to_a.empty?
|
|
end
|
|
|
|
assert('All tags are unique between categories') do
|
|
%i[verification exceptions properties].flat_map { |type| Panda.send(type).map(&:tag) }.uniq?
|
|
end
|
|
|
|
assert('All tags are used') do
|
|
%i[verification exceptions properties].map do |type|
|
|
uses = Panda.instructions.flat_map(&type.to_proc).uniq
|
|
defs = Panda.send(type).map(&:tag)
|
|
(defs - uses - ['suspend']).size # 'suspend' is non-core optional property, allowed to be unused
|
|
end.reduce(:+).zero?
|
|
end
|
|
|
|
assert('All tags are defined') do
|
|
%i[verification exceptions properties].map do |type|
|
|
uses = Panda.instructions.flat_map(&type.to_proc).uniq
|
|
defs = Panda.send(type).map(&:tag)
|
|
(uses - defs - ['acc_read', 'acc_write', 'acc_none']).size
|
|
end.reduce(:+).zero?
|
|
end
|
|
|
|
assert('Format operands are parseable') { Panda.instructions.each(&:operands) }
|
|
|
|
assert('Verification, exceptions and properties are not empty for every instruction group') do
|
|
%i[verification exceptions properties].map do |type|
|
|
!Panda.groups.map(&type).empty?
|
|
end.all?
|
|
end
|
|
|
|
assert('Mnemonic defines operand types') do
|
|
Panda.instructions.group_by(&:mnemonic).map do |_, insns|
|
|
insns.map { |insn| insn.operands.map(&:name) }.uniq.one?
|
|
end.all?
|
|
end
|
|
|
|
assert('Dtype should be none when bytecode doesn\'t write into accumulator or registers') do
|
|
Panda.instructions.map do |i|
|
|
next true if i.properties.include?('language')
|
|
|
|
i.acc_and_operands.map(&:dst?).any? == (i.dtype != 'none')
|
|
end.all?
|
|
end
|
|
|
|
assert('Instruction::float? should play well with operand types') do
|
|
Panda.instructions.map do |i|
|
|
i.float? == i.acc_and_operands.any? { |op| op.type.start_with?('f') }
|
|
end.all?
|
|
end
|
|
|
|
assert('Conditionals should be jumps') do # At least currently
|
|
Panda.instructions.select(&:conditional?).map(&:jump?).all?
|
|
end
|
|
|
|
assert('Acc_none should not be specified along with other accumulator properties') do
|
|
Panda.instructions.map do |i|
|
|
i.acc_none? == !(i.acc_read? || i.acc_write?)
|
|
end.all?
|
|
end
|
|
|
|
assert('All calls write into accumulator') do
|
|
Panda.instructions.select { |i| i.properties.include?('call') }.map(&:acc_write?).all?
|
|
end
|
|
|
|
assert('Jumps differ from other control-flow') do # At least currently
|
|
Panda.instructions.select { |i| i.mnemonic.match?(/^(throw|call|return)/) }.map do |i|
|
|
!i.jump?
|
|
end.all?
|
|
end
|
|
|
|
assert('Conversions should correspond to source and destination type') do
|
|
Panda.instructions.map do |i|
|
|
match = i.mnemonic.match(/[ifu](\d+)to[ifu](\d+)/)
|
|
next true unless match
|
|
|
|
ssize, dsize = match.captures
|
|
i.acc_and_operands.select(&:src?).first.type[1..-1].to_i >= ssize.to_i && i.dtype[1..-1].to_i >= dsize.to_i
|
|
end.all?
|
|
end
|
|
|
|
assert('Operand type should be one of none, ref, u1, u2, i8, u8, i16, u16, i32, u32, b32, i64, u64, b64, f64, top, any') do
|
|
types = %w[none ref u1 u2 i8 u8 i16 u16 i32 u32 b32 f32 i64 u64 b64 f64 top any]
|
|
Panda.instructions.map do |i|
|
|
i.acc_and_operands.all? { |op| types.include?(op.type.sub('[]', '')) }
|
|
end.all?
|
|
end
|
|
|
|
assert('Instruction should have not more than one destination') do
|
|
# Otherwise support it in Assembler IR
|
|
Panda.instructions.map do |i|
|
|
i.acc_and_operands.select(&:dst?).count <= 1
|
|
end.all?
|
|
end
|
|
|
|
assert('Instruction should have not more than one ID operand') do
|
|
# Otherwise support it in Assembler IR
|
|
Panda.instructions.map do |i|
|
|
i.operands.select(&:id?).count <= 1
|
|
end.all?
|
|
end
|
|
|
|
assert('Register encoding width should be the same in instruction') do
|
|
# Otherwise support it in Assembler
|
|
Panda.instructions.map do |i|
|
|
registers = i.operands.select(&:reg?)
|
|
registers.empty? || registers.map(&:width).uniq.one?
|
|
end.all?
|
|
end
|
|
|
|
assert('Calls should have call property and x_call exception tag') do
|
|
Panda.instructions.map do |i|
|
|
next true unless i.mnemonic.start_with?('call')
|
|
|
|
i.properties.include?('call') && i.exceptions.include?('x_call')
|
|
end.all?
|
|
end
|
|
|
|
assert('Virtual calls should have call_virt property') do
|
|
Panda.instructions.map do |i|
|
|
next true unless i.mnemonic.include?('call.virt')
|
|
|
|
i.properties.include?('call_virt')
|
|
end.all?
|
|
end
|