From 1a00d24e1e147302d03a0cfa0ab6bd7c8071c841 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Fri, 24 May 2024 12:06:44 +0100 Subject: [PATCH 01/48] Added STREAMING versions of relevant aarch64 instruction groups. --- .../simeng/arch/aarch64/InstructionGroups.hh | 86 +++++++++++++------ 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/src/include/simeng/arch/aarch64/InstructionGroups.hh b/src/include/simeng/arch/aarch64/InstructionGroups.hh index b50005571c..3c28712537 100644 --- a/src/include/simeng/arch/aarch64/InstructionGroups.hh +++ b/src/include/simeng/arch/aarch64/InstructionGroups.hh @@ -72,37 +72,53 @@ const uint16_t LOAD_SVE = 62; const uint16_t STORE_ADDRESS_SVE = 63; const uint16_t STORE_DATA_SVE = 64; const uint16_t STORE_SVE = 65; -const uint16_t PREDICATE = 66; -const uint16_t LOAD = 67; -const uint16_t STORE_ADDRESS = 68; -const uint16_t STORE_DATA = 69; -const uint16_t STORE = 70; -const uint16_t BRANCH = 71; -const uint16_t SME = 72; -const uint16_t SME_SIMPLE = 73; -const uint16_t SME_SIMPLE_ARTH = 74; -const uint16_t SME_SIMPLE_ARTH_NOSHIFT = 75; -const uint16_t SME_SIMPLE_LOGICAL = 76; -const uint16_t SME_SIMPLE_LOGICAL_NOSHIFT = 77; -const uint16_t SME_SIMPLE_CMP = 78; -const uint16_t SME_SIMPLE_CVT = 79; -const uint16_t SME_MUL = 80; -const uint16_t SME_DIV_OR_SQRT = 81; -const uint16_t LOAD_SME = 82; -const uint16_t STORE_ADDRESS_SME = 83; -const uint16_t STORE_DATA_SME = 84; -const uint16_t STORE_SME = 85; -const uint16_t ALL = 86; -const uint16_t NONE = 87; +const uint16_t STREAMING_SVE = 66; +const uint16_t STREAMING_SVE_SIMPLE = 67; +const uint16_t STREAMING_SVE_SIMPLE_ARTH = 68; +const uint16_t STREAMING_SVE_SIMPLE_ARTH_NOSHIFT = 69; +const uint16_t STREAMING_SVE_SIMPLE_LOGICAL = 70; +const uint16_t STREAMING_SVE_SIMPLE_LOGICAL_NOSHIFT = 71; +const uint16_t STREAMING_SVE_SIMPLE_CMP = 72; +const uint16_t STREAMING_SVE_SIMPLE_CVT = 73; +const uint16_t STREAMING_SVE_MUL = 74; +const uint16_t STREAMING_SVE_DIV_OR_SQRT = 75; +const uint16_t LOAD_STREAMING_SVE = 76; +const uint16_t STORE_ADDRESS_STREAMING_SVE = 77; +const uint16_t STORE_DATA_STREAMING_SVE = 78; +const uint16_t STORE_STREAMING_SVE = 79; +const uint16_t SME = 80; +const uint16_t SME_SIMPLE = 81; +const uint16_t SME_SIMPLE_ARTH = 82; +const uint16_t SME_SIMPLE_ARTH_NOSHIFT = 83; +const uint16_t SME_SIMPLE_LOGICAL = 84; +const uint16_t SME_SIMPLE_LOGICAL_NOSHIFT = 85; +const uint16_t SME_SIMPLE_CMP = 86; +const uint16_t SME_SIMPLE_CVT = 87; +const uint16_t SME_MUL = 88; +const uint16_t SME_DIV_OR_SQRT = 89; +const uint16_t LOAD_SME = 90; +const uint16_t STORE_ADDRESS_SME = 91; +const uint16_t STORE_DATA_SME = 92; +const uint16_t STORE_SME = 93; +const uint16_t PREDICATE = 94; +const uint16_t STREAMING_PREDICATE = 95; +const uint16_t LOAD = 96; +const uint16_t STORE_ADDRESS = 97; +const uint16_t STORE_DATA = 98; +const uint16_t STORE = 99; +const uint16_t BRANCH = 100; +const uint16_t ALL = 101; +const uint16_t NONE = 102; } // namespace InstructionGroups /** The number of aarch64 instruction groups. */ -static constexpr uint8_t NUM_GROUPS = 88; +static constexpr uint8_t NUM_GROUPS = 103; const std::unordered_map> groupInheritance_ = { {InstructionGroups::ALL, {InstructionGroups::INT, InstructionGroups::FP, InstructionGroups::SVE, - InstructionGroups::PREDICATE, InstructionGroups::SME, + InstructionGroups::STREAMING_SVE, InstructionGroups::SME, + InstructionGroups::PREDICATE, InstructionGroups::STREAMING_PREDICATE, InstructionGroups::LOAD, InstructionGroups::STORE, InstructionGroups::BRANCH}}, {InstructionGroups::INT, @@ -176,6 +192,19 @@ const std::unordered_map> groupInheritance_ = { {InstructionGroups::SVE_SIMPLE_ARTH_NOSHIFT}}, {InstructionGroups::SVE_SIMPLE_LOGICAL, {InstructionGroups::SVE_SIMPLE_LOGICAL_NOSHIFT}}, + {InstructionGroups::STREAMING_SVE, + {InstructionGroups::STREAMING_SVE_SIMPLE, + InstructionGroups::STREAMING_SVE_DIV_OR_SQRT, + InstructionGroups::STREAMING_SVE_MUL}}, + {InstructionGroups::STREAMING_SVE_SIMPLE, + {InstructionGroups::STREAMING_SVE_SIMPLE_ARTH, + InstructionGroups::STREAMING_SVE_SIMPLE_LOGICAL, + InstructionGroups::STREAMING_SVE_SIMPLE_CMP, + InstructionGroups::STREAMING_SVE_SIMPLE_CVT}}, + {InstructionGroups::STREAMING_SVE_SIMPLE_ARTH, + {InstructionGroups::STREAMING_SVE_SIMPLE_ARTH_NOSHIFT}}, + {InstructionGroups::STREAMING_SVE_SIMPLE_LOGICAL, + {InstructionGroups::STREAMING_SVE_SIMPLE_LOGICAL_NOSHIFT}}, {InstructionGroups::SME, {InstructionGroups::SME_SIMPLE, InstructionGroups::SME_DIV_OR_SQRT, InstructionGroups::SME_MUL}}, @@ -189,11 +218,11 @@ const std::unordered_map> groupInheritance_ = { {InstructionGroups::LOAD, {InstructionGroups::LOAD_INT, InstructionGroups::LOAD_SCALAR, InstructionGroups::LOAD_VECTOR, InstructionGroups::LOAD_SVE, - InstructionGroups::LOAD_SME}}, + InstructionGroups::LOAD_STREAMING_SVE, InstructionGroups::LOAD_SME}}, {InstructionGroups::STORE, {InstructionGroups::STORE_INT, InstructionGroups::STORE_SCALAR, InstructionGroups::STORE_VECTOR, InstructionGroups::STORE_SVE, - InstructionGroups::STORE_SME}}, + InstructionGroups::STORE_STREAMING_SVE, InstructionGroups::STORE_SME}}, {InstructionGroups::STORE_INT, {InstructionGroups::STORE_ADDRESS_INT, InstructionGroups::STORE_DATA_INT}}, {InstructionGroups::STORE_SCALAR, @@ -204,6 +233,9 @@ const std::unordered_map> groupInheritance_ = { InstructionGroups::STORE_DATA_VECTOR}}, {InstructionGroups::STORE_SVE, {InstructionGroups::STORE_ADDRESS_SVE, InstructionGroups::STORE_DATA_SVE}}, + {InstructionGroups::STORE_STREAMING_SVE, + {InstructionGroups::STORE_ADDRESS_STREAMING_SVE, + InstructionGroups::STORE_DATA_STREAMING_SVE}}, {InstructionGroups::STORE_SME, {InstructionGroups::STORE_ADDRESS_SME, InstructionGroups::STORE_DATA_SME}}, {InstructionGroups::STORE_ADDRESS, @@ -211,10 +243,12 @@ const std::unordered_map> groupInheritance_ = { InstructionGroups::STORE_ADDRESS_SCALAR, InstructionGroups::STORE_ADDRESS_VECTOR, InstructionGroups::STORE_ADDRESS_SVE, + InstructionGroups::STORE_ADDRESS_STREAMING_SVE, InstructionGroups::STORE_ADDRESS_SME}}, {InstructionGroups::STORE_DATA, {InstructionGroups::STORE_DATA_INT, InstructionGroups::STORE_DATA_SCALAR, InstructionGroups::STORE_DATA_VECTOR, InstructionGroups::STORE_DATA_SVE, + InstructionGroups::STORE_DATA_STREAMING_SVE, InstructionGroups::STORE_DATA_SME}}}; } // namespace aarch64 From ec8b486cc5dd98f451894e86b4227147f0d9118e Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Tue, 28 May 2024 10:32:27 +0100 Subject: [PATCH 02/48] Removed un-used macros from AArch64 Instruction decode. --- src/lib/arch/aarch64/Instruction_decode.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/lib/arch/aarch64/Instruction_decode.cc b/src/lib/arch/aarch64/Instruction_decode.cc index 6d2007cb55..3535ce590f 100644 --- a/src/lib/arch/aarch64/Instruction_decode.cc +++ b/src/lib/arch/aarch64/Instruction_decode.cc @@ -2,11 +2,6 @@ #include "InstructionMetadata.hh" -#define NOT(bits, length) (~bits & (1 << length - 1)) -#define CONCAT(hi, lo, lowLen) ((hi << lowLen) & lo) -#define ONES(n) ((1 << (n)) - 1) -#define ROR(x, shift, size) ((x >> shift) | (x << (size - shift))) - namespace simeng { namespace arch { namespace aarch64 { From f5f348b8762905ec5af2fdc9f23055a07cc40df4 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Tue, 28 May 2024 11:27:55 +0100 Subject: [PATCH 03/48] Moved aarch64 getGroup logic to instruction_decode. --- .../simeng/arch/aarch64/Instruction.hh | 3 ++ src/lib/arch/aarch64/Instruction.cc | 30 +------------ src/lib/arch/aarch64/Instruction_decode.cc | 42 +++++++++++++++++++ 3 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/include/simeng/arch/aarch64/Instruction.hh b/src/include/simeng/arch/aarch64/Instruction.hh index b5f1f07cc5..3803aed9d6 100644 --- a/src/include/simeng/arch/aarch64/Instruction.hh +++ b/src/include/simeng/arch/aarch64/Instruction.hh @@ -472,6 +472,9 @@ class Instruction : public simeng::Instruction { * the `InsnType` namespace allowing each bit to represent a unique * identifier such as `isLoad` or `isMultiply` etc. */ uint32_t instructionIdentifier_ = 0; + + /** The instruction group this instruction belongs to. */ + uint16_t instructionGroup_ = InstructionGroups::ALL; }; } // namespace aarch64 diff --git a/src/lib/arch/aarch64/Instruction.cc b/src/lib/arch/aarch64/Instruction.cc index e3b697433e..f2a15a79ba 100644 --- a/src/lib/arch/aarch64/Instruction.cc +++ b/src/lib/arch/aarch64/Instruction.cc @@ -131,35 +131,7 @@ bool Instruction::isLoad() const { return isInstruction(InsnType::isLoad); } bool Instruction::isBranch() const { return isInstruction(InsnType::isBranch); } -uint16_t Instruction::getGroup() const { - // Use identifiers to decide instruction group - // Set base - uint16_t base = InstructionGroups::INT; - if (isInstruction(InsnType::isScalarData)) - base = InstructionGroups::SCALAR; - else if (isInstruction(InsnType::isVectorData)) - base = InstructionGroups::VECTOR; - else if (isInstruction(InsnType::isSVEData)) - base = InstructionGroups::SVE; - else if (isInstruction(InsnType::isSMEData)) - base = InstructionGroups::SME; - - if (isInstruction(InsnType::isLoad)) return base + 10; - if (isInstruction(InsnType::isStoreAddress)) return base + 11; - if (isInstruction(InsnType::isStoreData)) return base + 12; - if (isInstruction(InsnType::isBranch)) return InstructionGroups::BRANCH; - if (isInstruction(InsnType::isPredicate)) return InstructionGroups::PREDICATE; - if (isInstruction(InsnType::isDivideOrSqrt)) return base + 9; - if (isInstruction(InsnType::isMultiply)) return base + 8; - if (isInstruction(InsnType::isConvert)) return base + 7; - if (isInstruction(InsnType::isCompare)) return base + 6; - if (isInstruction(InsnType::isLogical)) { - if (isInstruction(InsnType::isShift)) return base + 4; - return base + 5; - } - if (isInstruction(InsnType::isShift)) return base + 2; - return base + 3; // Default return is {Data type}_SIMPLE_ARTH -} +uint16_t Instruction::getGroup() const { return instructionGroup_; } bool Instruction::canExecute() const { return (sourceOperandsPending_ == 0); } diff --git a/src/lib/arch/aarch64/Instruction_decode.cc b/src/lib/arch/aarch64/Instruction_decode.cc index 3535ce590f..8ff87a2b1a 100644 --- a/src/lib/arch/aarch64/Instruction_decode.cc +++ b/src/lib/arch/aarch64/Instruction_decode.cc @@ -646,6 +646,48 @@ void Instruction::decode() { sourceValues_.resize(sourceRegisterCount_); results_.resize(destinationRegisterCount_); } + + // Calculate the instruction's group based on identifiers + // Set base group + uint16_t group = InstructionGroups::INT; + if (isInstruction(InsnType::isScalarData)) + group = InstructionGroups::SCALAR; + else if (isInstruction(InsnType::isVectorData)) + group = InstructionGroups::VECTOR; + else if (isInstruction(InsnType::isSVEData)) + group = InstructionGroups::SVE; + else if (isInstruction(InsnType::isSMEData)) + group = InstructionGroups::SME; + // Identify subgroup type + if (isInstruction(InsnType::isLoad)) + group += 10; + else if (isInstruction(InsnType::isStoreAddress)) + group += 11; + else if (isInstruction(InsnType::isStoreData)) + group += 12; + else if (isInstruction(InsnType::isBranch)) + group = InstructionGroups::BRANCH; + else if (isInstruction(InsnType::isPredicate)) + group = InstructionGroups::PREDICATE; + else if (isInstruction(InsnType::isDivideOrSqrt)) + group += 9; + else if (isInstruction(InsnType::isMultiply)) + group += 8; + else if (isInstruction(InsnType::isConvert)) + group += 7; + else if (isInstruction(InsnType::isCompare)) + group += 6; + else if (isInstruction(InsnType::isLogical)) { + if (isInstruction(InsnType::isShift)) + group += 4; + else + group += 5; + } else if (isInstruction(InsnType::isShift)) + group += 2; + else + group += 3; // Default is {Data type}_SIMPLE_ARTH + + instructionGroup_ = group; } } // namespace aarch64 From ffacdc9da149820273900fce4e12334296e7f3e5 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Tue, 28 May 2024 11:40:30 +0100 Subject: [PATCH 04/48] Moved riscv getGroup logic to instruction_decode. --- .../simeng/arch/aarch64/Instruction.hh | 2 +- src/include/simeng/arch/riscv/Instruction.hh | 3 +++ src/lib/arch/riscv/Instruction.cc | 19 +------------ src/lib/arch/riscv/Instruction_decode.cc | 27 +++++++++++++++++++ 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/include/simeng/arch/aarch64/Instruction.hh b/src/include/simeng/arch/aarch64/Instruction.hh index 3803aed9d6..5a8a57b2ab 100644 --- a/src/include/simeng/arch/aarch64/Instruction.hh +++ b/src/include/simeng/arch/aarch64/Instruction.hh @@ -474,7 +474,7 @@ class Instruction : public simeng::Instruction { uint32_t instructionIdentifier_ = 0; /** The instruction group this instruction belongs to. */ - uint16_t instructionGroup_ = InstructionGroups::ALL; + uint16_t instructionGroup_ = InstructionGroups::NONE; }; } // namespace aarch64 diff --git a/src/include/simeng/arch/riscv/Instruction.hh b/src/include/simeng/arch/riscv/Instruction.hh index 9e707449c6..bff382df04 100644 --- a/src/include/simeng/arch/riscv/Instruction.hh +++ b/src/include/simeng/arch/riscv/Instruction.hh @@ -252,6 +252,9 @@ class Instruction : public simeng::Instruction { * the `InsnType` namespace allowing each bit to represent a unique * identifier such as `isLoad` or `isMultiply` etc. */ uint16_t instructionIdentifier_ = 0; + + /** The instruction group this instruction belongs to. */ + uint16_t instructionGroup_ = InstructionGroups::NONE; }; } // namespace riscv diff --git a/src/lib/arch/riscv/Instruction.cc b/src/lib/arch/riscv/Instruction.cc index c71b581a60..472e7f7ad7 100644 --- a/src/lib/arch/riscv/Instruction.cc +++ b/src/lib/arch/riscv/Instruction.cc @@ -126,24 +126,7 @@ bool Instruction::isLoad() const { return isInstruction(InsnType::isLoad); } bool Instruction::isBranch() const { return isInstruction(InsnType::isBranch); } -uint16_t Instruction::getGroup() const { - uint16_t base = InstructionGroups::INT; - - if (isInstruction(InsnType::isFloat)) { - base = InstructionGroups::FLOAT; - } - - if (isInstruction(InsnType::isBranch)) return InstructionGroups::BRANCH; - if (isInstruction(InsnType::isLoad)) return base + 8; - if (isInstruction(InsnType::isStore)) return base + 9; - if (isInstruction(InsnType::isDivide)) return base + 7; - if (isInstruction(InsnType::isMultiply)) return base + 6; - if (isInstruction(InsnType::isShift) || isInstruction(InsnType::isConvert)) - return base + 5; - if (isInstruction(InsnType::isLogical)) return base + 4; - if (isInstruction(InsnType::isCompare)) return base + 3; - return base + 2; // Default return is {Data type}_SIMPLE_ARTH -} +uint16_t Instruction::getGroup() const { return instructionGroup_; } bool Instruction::canExecute() const { return (sourceOperandsPending_ == 0); } diff --git a/src/lib/arch/riscv/Instruction_decode.cc b/src/lib/arch/riscv/Instruction_decode.cc index e8145d4c11..5337cc095e 100644 --- a/src/lib/arch/riscv/Instruction_decode.cc +++ b/src/lib/arch/riscv/Instruction_decode.cc @@ -310,6 +310,33 @@ void Instruction::decode() { knownOffset_ = sourceImm_; break; } + + // Calculate the instruction's group based on identifiers + // Set base group + uint16_t group = InstructionGroups::INT; + if (isInstruction(InsnType::isFloat)) group = InstructionGroups::FLOAT; + // Identify subgroup type + if (isInstruction(InsnType::isBranch)) + group = InstructionGroups::BRANCH; + else if (isInstruction(InsnType::isLoad)) + group += 8; + else if (isInstruction(InsnType::isStore)) + group += 9; + else if (isInstruction(InsnType::isDivide)) + group += 7; + else if (isInstruction(InsnType::isMultiply)) + group += 6; + else if (isInstruction(InsnType::isShift) || + isInstruction(InsnType::isConvert)) + group += 5; + else if (isInstruction(InsnType::isLogical)) + group += 4; + else if (isInstruction(InsnType::isCompare)) + group += 3; + else + group += 2; // Default return is {Data type}_SIMPLE_ARTH + + instructionGroup_ = group; } } // namespace riscv From 966c0d79fe1584141c1f9ecc374c6a97ad2746b9 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Tue, 28 May 2024 11:42:55 +0100 Subject: [PATCH 05/48] Updated unit tests after changing getGroup logic. --- test/unit/aarch64/InstructionTest.cc | 8 ++++---- test/unit/riscv/InstructionTest.cc | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/unit/aarch64/InstructionTest.cc b/test/unit/aarch64/InstructionTest.cc index 1ecf14a1a6..d76c8c1741 100644 --- a/test/unit/aarch64/InstructionTest.cc +++ b/test/unit/aarch64/InstructionTest.cc @@ -182,8 +182,8 @@ TEST_F(AArch64InstructionTest, invalidInsn_1) { } EXPECT_EQ(insn.getException(), InstructionException::EncodingUnallocated); EXPECT_EQ(insn.getGeneratedAddresses().size(), 0); - // Default Group - EXPECT_EQ(insn.getGroup(), InstructionGroups::INT_SIMPLE_ARTH_NOSHIFT); + // Default Group for instruction that is not decoded + EXPECT_EQ(insn.getGroup(), InstructionGroups::NONE); EXPECT_EQ(insn.getInstructionAddress(), 0x44); EXPECT_EQ(insn.getInstructionId(), 13); EXPECT_EQ(insn.getKnownOffset(), 0); @@ -248,8 +248,8 @@ TEST_F(AArch64InstructionTest, invalidInsn_2) { } EXPECT_EQ(insn.getException(), InstructionException::HypervisorCall); EXPECT_EQ(insn.getGeneratedAddresses().size(), 0); - // Default Group - EXPECT_EQ(insn.getGroup(), InstructionGroups::INT_SIMPLE_ARTH_NOSHIFT); + // Default Group for instruction that is not decoded + EXPECT_EQ(insn.getGroup(), InstructionGroups::NONE); EXPECT_EQ(insn.getInstructionAddress(), 0x43); EXPECT_EQ(insn.getInstructionId(), 15); EXPECT_EQ(insn.getKnownOffset(), 0); diff --git a/test/unit/riscv/InstructionTest.cc b/test/unit/riscv/InstructionTest.cc index 6103cd4f5c..43e0daf745 100644 --- a/test/unit/riscv/InstructionTest.cc +++ b/test/unit/riscv/InstructionTest.cc @@ -178,8 +178,8 @@ TEST_F(RiscVInstructionTest, invalidInsn_1) { } EXPECT_EQ(insn.getException(), InstructionException::EncodingUnallocated); EXPECT_EQ(insn.getGeneratedAddresses().size(), 0); - // Default Group - EXPECT_EQ(insn.getGroup(), InstructionGroups::INT_SIMPLE_ARTH); + // Default Group for instruction that is not decoded + EXPECT_EQ(insn.getGroup(), InstructionGroups::NONE); EXPECT_EQ(insn.getInstructionAddress(), 0x44); EXPECT_EQ(insn.getInstructionId(), 13); EXPECT_EQ(insn.getKnownOffset(), 0); @@ -242,8 +242,8 @@ TEST_F(RiscVInstructionTest, invalidInsn_2) { } EXPECT_EQ(insn.getException(), InstructionException::HypervisorCall); EXPECT_EQ(insn.getGeneratedAddresses().size(), 0); - // Default Group - EXPECT_EQ(insn.getGroup(), InstructionGroups::INT_SIMPLE_ARTH); + // Default Group for instruction that is not decoded + EXPECT_EQ(insn.getGroup(), InstructionGroups::NONE); EXPECT_EQ(insn.getInstructionAddress(), 0x43); EXPECT_EQ(insn.getInstructionId(), 15); EXPECT_EQ(insn.getKnownOffset(), 0); From 5ba3677e0ce63c271474eb4498e9c0eace8c13ac Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Tue, 28 May 2024 14:20:21 +0100 Subject: [PATCH 06/48] Added new AArch64 groups to model config and updated integration test. --- src/lib/config/ModelConfig.cc | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/lib/config/ModelConfig.cc b/src/lib/config/ModelConfig.cc index 6d54b50d06..b911dc58b2 100644 --- a/src/lib/config/ModelConfig.cc +++ b/src/lib/config/ModelConfig.cc @@ -1186,12 +1186,20 @@ void ModelConfig::createGroupMapping() { "STORE_ADDRESS_SVE", "STORE_DATA_SVE", "STORE_SVE", - "PREDICATE", - "LOAD", - "STORE_ADDRESS", - "STORE_DATA", - "STORE", - "BRANCH", + "STREAMING_SVE", + "STREAMING_SVE_SIMPLE", + "STREAMING_SVE_SIMPLE_ARTH", + "STREAMING_SVE_SIMPLE_ARTH_NOSHIFT", + "STREAMING_SVE_SIMPLE_LOGICAL", + "STREAMING_SVE_SIMPLE_LOGICAL_NOSHIFT", + "STREAMING_SVE_SIMPLE_CMP", + "STREAMING_SVE_SIMPLE_CVT", + "STREAMING_SVE_MUL", + "STREAMING_SVE_DIV_OR_SQRT", + "LOAD_STREAMING_SVE", + "STORE_ADDRESS_STREAMING_SVE", + "STORE_DATA_STREAMING_SVE", + "STORE_STREAMING_SVE", "SME", "SME_SIMPLE", "SME_SIMPLE_ARTH", @@ -1206,6 +1214,13 @@ void ModelConfig::createGroupMapping() { "STORE_ADDRESS_SME", "STORE_DATA_SME", "STORE_SME", + "PREDICATE", + "STREAMING_PREDICATE", + "LOAD", + "STORE_ADDRESS", + "STORE_DATA", + "STORE", + "BRANCH", "ALL", "NONE"}; } else if (isa_ == ISA::RV64) { From b6abd5fd78bc51996f9a90f4163a3cc94bc7c552 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Tue, 28 May 2024 14:53:55 +0100 Subject: [PATCH 07/48] Added streaming mode enabled helper functions. --- src/include/simeng/arch/aarch64/Architecture.hh | 6 ++++++ src/lib/arch/aarch64/Architecture.cc | 6 ++++++ src/lib/arch/aarch64/Instruction_execute.cc | 4 ++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/include/simeng/arch/aarch64/Architecture.hh b/src/include/simeng/arch/aarch64/Architecture.hh index 8d4939c991..1041bf85fe 100644 --- a/src/include/simeng/arch/aarch64/Architecture.hh +++ b/src/include/simeng/arch/aarch64/Architecture.hh @@ -70,6 +70,12 @@ class Architecture : public arch::Architecture { /** Returns the current value of SVCRval_. */ uint64_t getSVCRval() const; + /** Returns if SVE Streaming Mode is enabled. */ + bool isStreamingModeEnabled() const; + + /** Returns if the SME ZA Register is enabled. */ + bool isZA_RegisterEnabled() const; + /** Update the value of SVCRval_. */ void setSVCRval(const uint64_t newVal) const; diff --git a/src/lib/arch/aarch64/Architecture.cc b/src/lib/arch/aarch64/Architecture.cc index 015dba62b1..7805ba3750 100644 --- a/src/lib/arch/aarch64/Architecture.cc +++ b/src/lib/arch/aarch64/Architecture.cc @@ -284,6 +284,12 @@ void Architecture::setSVCRval(const uint64_t newVal) const { SVCRval_ = newVal; } +// 0th bit of SVCR register determines if streaming-mode is enabled. +bool Architecture::isStreamingModeEnabled() const { return SVCRval_ & 1; } + +// 1st bit of SVCR register determines if ZA register is enabled. +bool Architecture::isZA_RegisterEnabled() const { return SVCRval_ & 2; } + } // namespace aarch64 } // namespace arch } // namespace simeng diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 20b62904b9..210976dbd2 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -67,9 +67,9 @@ void Instruction::execute() { canExecute() && "Attempted to execute an instruction before all operands were provided"); // 0th bit of SVCR register determines if streaming-mode is enabled. - const bool SMenabled = architecture_.getSVCRval() & 1; + const bool SMenabled = architecture_.isStreamingModeEnabled(); // 1st bit of SVCR register determines if ZA register is enabled. - const bool ZAenabled = architecture_.getSVCRval() & 2; + const bool ZAenabled = architecture_.isZA_RegisterEnabled(); // When streaming mode is enabled, the architectural vector length goes from // SVE's VL to SME's SVL. const uint16_t VL_bits = SMenabled ? architecture_.getStreamingVectorLength() From a0078d9035c8391686a29ed2a580999f59f02f6c Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Wed, 29 May 2024 13:18:13 +0100 Subject: [PATCH 08/48] Added STREAMING group logic to instruction_decode, and logic to change instruction group to STREAMING if SM mode is different to when instruction was first decoded. --- .../simeng/arch/aarch64/Instruction.hh | 5 ++++ src/lib/arch/aarch64/Architecture.cc | 5 ++++ src/lib/arch/aarch64/Instruction.cc | 26 +++++++++++++++++++ src/lib/arch/aarch64/Instruction_decode.cc | 7 +++-- .../aarch64/AArch64RegressionTest.hh | 2 +- 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/include/simeng/arch/aarch64/Instruction.hh b/src/include/simeng/arch/aarch64/Instruction.hh index 5a8a57b2ab..b1728006bb 100644 --- a/src/include/simeng/arch/aarch64/Instruction.hh +++ b/src/include/simeng/arch/aarch64/Instruction.hh @@ -391,6 +391,11 @@ class Instruction : public simeng::Instruction { * processing this instruction. */ InstructionException getException() const; + /** Checks whether the current SVE Streaming Mode status is different to when + * this instruction was first decoded, and updates the instruction group + * accordingly if required. */ + void checkStreamingGroup(); + private: /** Process the instruction's metadata to determine source/destination * registers. */ diff --git a/src/lib/arch/aarch64/Architecture.cc b/src/lib/arch/aarch64/Architecture.cc index 7805ba3750..76b0bf33d5 100644 --- a/src/lib/arch/aarch64/Architecture.cc +++ b/src/lib/arch/aarch64/Architecture.cc @@ -191,6 +191,11 @@ uint8_t Architecture::predecode(const uint8_t* ptr, uint16_t bytesAvailable, newInsn.setExecutionInfo(getExecutionInfo(newInsn)); // Cache the instruction iter = decodeCache_.insert({insn, newInsn}).first; + } else { + // Check if SVE or Predicate instructions need their group updating due to + // SVE Streaming Mode activeness being different from when the instruction + // was first decoded. + iter->second.checkStreamingGroup(); } // Split instruction into 1 or more defined micro-ops diff --git a/src/lib/arch/aarch64/Instruction.cc b/src/lib/arch/aarch64/Instruction.cc index f2a15a79ba..9acd2f53a6 100644 --- a/src/lib/arch/aarch64/Instruction.cc +++ b/src/lib/arch/aarch64/Instruction.cc @@ -164,6 +164,32 @@ const Architecture& Instruction::getArchitecture() const { InstructionException Instruction::getException() const { return exception_; } +void Instruction::checkStreamingGroup() { + // Only instruction groups that depend on SVE Streaming Mode are SVE and + // PREDICATE + if (architecture_.isStreamingModeEnabled()) { + if (instructionGroup_ == InstructionGroups::PREDICATE) { + instructionGroup_ = InstructionGroups::STREAMING_PREDICATE; + } else if (instructionGroup_ >= InstructionGroups::SVE && + instructionGroup_ <= InstructionGroups::STORE_SVE) { + // As STREAMING_SVE and SVE groups have the exact same sub-groups and + // order, we can minus the value of SVE and add the value of STREAMING_SVE + instructionGroup_ = instructionGroup_ - InstructionGroups::SVE + + InstructionGroups::STREAMING_SVE; + } + } else { + if (instructionGroup_ == InstructionGroups::STREAMING_PREDICATE) { + instructionGroup_ = InstructionGroups::PREDICATE; + } else if (instructionGroup_ >= InstructionGroups::STREAMING_SVE && + instructionGroup_ <= InstructionGroups::STORE_STREAMING_SVE) { + // As STREAMING_SVE and SVE groups have the exact same sub-groups and + // order, we can minus the value of STREAMING_SVE and add the value of SVE + instructionGroup_ = instructionGroup_ - InstructionGroups::STREAMING_SVE + + InstructionGroups::SVE; + } + } +} + } // namespace aarch64 } // namespace arch } // namespace simeng diff --git a/src/lib/arch/aarch64/Instruction_decode.cc b/src/lib/arch/aarch64/Instruction_decode.cc index 8ff87a2b1a..92920d278c 100644 --- a/src/lib/arch/aarch64/Instruction_decode.cc +++ b/src/lib/arch/aarch64/Instruction_decode.cc @@ -648,6 +648,7 @@ void Instruction::decode() { } // Calculate the instruction's group based on identifiers + bool smEnabled = architecture_.isStreamingModeEnabled(); // Set base group uint16_t group = InstructionGroups::INT; if (isInstruction(InsnType::isScalarData)) @@ -655,7 +656,8 @@ void Instruction::decode() { else if (isInstruction(InsnType::isVectorData)) group = InstructionGroups::VECTOR; else if (isInstruction(InsnType::isSVEData)) - group = InstructionGroups::SVE; + group = + smEnabled ? InstructionGroups::STREAMING_SVE : InstructionGroups::SVE; else if (isInstruction(InsnType::isSMEData)) group = InstructionGroups::SME; // Identify subgroup type @@ -668,7 +670,8 @@ void Instruction::decode() { else if (isInstruction(InsnType::isBranch)) group = InstructionGroups::BRANCH; else if (isInstruction(InsnType::isPredicate)) - group = InstructionGroups::PREDICATE; + group = smEnabled ? InstructionGroups::STREAMING_PREDICATE + : InstructionGroups::PREDICATE; else if (isInstruction(InsnType::isDivideOrSqrt)) group += 9; else if (isInstruction(InsnType::isMultiply)) diff --git a/test/regression/aarch64/AArch64RegressionTest.hh b/test/regression/aarch64/AArch64RegressionTest.hh index 32d975b09d..fafe7f4f9a 100644 --- a/test/regression/aarch64/AArch64RegressionTest.hh +++ b/test/regression/aarch64/AArch64RegressionTest.hh @@ -29,7 +29,7 @@ }, Ports: { - '0': { Portname: 0, Instruction-Group-Support: [INT, FP, SVE, PREDICATE, LOAD, STORE, BRANCH, SME] }, + '0': { Portname: 0, Instruction-Group-Support: [INT, FP, SVE, PREDICATE, LOAD, STORE, BRANCH, SME, STREAMING_SVE, STREAMING_PREDICATE] }, }, } )YAML"; From b95d973755ab72a4cb15f1271c343d6b2831737e Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Thu, 30 May 2024 14:14:41 +0100 Subject: [PATCH 09/48] Fixed minor issues with new streaming groups and updated SME example config file. --- configs/a64fx_SME.yaml | 86 +++++++++++++++++-- .../simeng/arch/aarch64/Instruction.hh | 5 +- src/lib/arch/aarch64/Architecture.cc | 11 ++- src/lib/arch/aarch64/Instruction.cc | 7 +- src/lib/arch/aarch64/Instruction_decode.cc | 1 - src/lib/arch/aarch64/MicroDecoder.cc | 23 +++++ 6 files changed, 121 insertions(+), 12 deletions(-) diff --git a/configs/a64fx_SME.yaml b/configs/a64fx_SME.yaml index 7fe7086d5e..4408e195c0 100644 --- a/configs/a64fx_SME.yaml +++ b/configs/a64fx_SME.yaml @@ -65,7 +65,12 @@ Ports: Instruction-Group-Support: - INT_SIMPLE - INT_MUL - - STORE_DATA + - STORE_DATA_INT + - STORE_DATA_SCALAR + - STORE_DATA_VECTOR + - STORE_DATA_SVE + - STORE_DATA_STREAMING_SVE + - STORE_DATA_SME 3: Portname: FLB Instruction-Group-Support: @@ -80,17 +85,37 @@ Ports: - INT_DIV_OR_SQRT 5: Portname: EAGA - Instruction-Support: - - LOAD - - STORE_ADDRESS + Instruction-Group-Support: + - LOAD_INT + - LOAD_SCALAR + - LOAD_VECTOR + - LOAD_SVE + - LOAD_STREAMING_SVE + - LOAD_SME + - STORE_ADDRESS_INT + - STORE_ADDRESS_SCALAR + - STORE_ADDRESS_VECTOR + - STORE_ADDRESS_SVE + - STORE_ADDRESS_STREAMING_SVE + - STORE_ADDRESS_SME - INT_SIMPLE_ARTH_NOSHIFT - INT_SIMPLE_LOGICAL_NOSHIFT - INT_SIMPLE_CMP 6: Portname: EAGB - Instruction-Support: - - LOAD - - STORE_ADDRESS + Instruction-Group-Support: + - LOAD_INT + - LOAD_SCALAR + - LOAD_VECTOR + - LOAD_SVE + - LOAD_STREAMING_SVE + - LOAD_SME + - STORE_ADDRESS_INT + - STORE_ADDRESS_SCALAR + - STORE_ADDRESS_VECTOR + - STORE_ADDRESS_SVE + - STORE_ADDRESS_STREAMING_SVE + - STORE_ADDRESS_SME - INT_SIMPLE_ARTH_NOSHIFT - INT_SIMPLE_LOGICAL_NOSHIFT - INT_SIMPLE_CMP @@ -98,10 +123,24 @@ Ports: Portname: BR Instruction-Group-Support: - BRANCH +# Define example SME / SVE Streaming Mode units 8: Portname: SME Instruction-Group-Support: - SME + 9: + Portname: PR_S + Instruction-Group-Support: + - STREAMING_PREDICATE + 10: + Portname: FLA_S + Instruction-Group-Support: + - STREAMING_SVE + 11: + Portname: FLB_S + Instruction-Group-Support: + - STREAMING_SVE_SIMPLE + - STREAMING_SVE_MUL Reservation-Stations: 0: Size: 20 @@ -136,6 +175,13 @@ Reservation-Stations: Dispatch-Rate: 1 Ports: - SME + 6: + Size: 40 + Dispatch-Rate: 3 + Ports: + - FLA_S + - FLB_S + - PR_S Execution-Units: 0: Pipelined: True @@ -191,6 +237,24 @@ Execution-Units: - INT_DIV_OR_SQRT - FP_DIV_OR_SQRT - SVE_DIV_OR_SQRT + 9: + Pipelined: True + Blocking-Groups: + - INT_DIV_OR_SQRT + - FP_DIV_OR_SQRT + - SVE_DIV_OR_SQRT + 10: + Pipelined: True + Blocking-Groups: + - INT_DIV_OR_SQRT + - FP_DIV_OR_SQRT + - SVE_DIV_OR_SQRT + 11: + Pipelined: True + Blocking-Groups: + - INT_DIV_OR_SQRT + - FP_DIV_OR_SQRT + - SVE_DIV_OR_SQRT Latencies: 0: Instruction-Groups: @@ -219,9 +283,11 @@ Latencies: - SCALAR_SIMPLE - VECTOR_SIMPLE_LOGICAL - SVE_SIMPLE_LOGICAL + - STREAMING_SVE_SIMPLE_LOGICAL - SME_SIMPLE_LOGICAL - VECTOR_SIMPLE_CMP - SVE_SIMPLE_CMP + - STREAMING_SVE_SIMPLE_CMP - SME_SIMPLE_CMP Execution-Latency: 4 Execution-Throughput: 1 @@ -235,21 +301,25 @@ Latencies: - SCALAR_SIMPLE_CVT - VECTOR_SIMPLE - SVE_SIMPLE + - STREAMING_SVE_SIMPLE - SME_SIMPLE - FP_MUL - SVE_MUL + - STREAMING_SVE_MUL - SME_MUL Execution-Latency: 9 Execution-Throughput: 1 7: Instruction-Groups: - SVE_DIV_OR_SQRT + - STREAMING_SVE_DIV_OR_SQRT - SME_DIV_OR_SQRT Execution-Latency: 98 Execution-Throughput: 98 8: Instruction-Groups: - PREDICATE + - STREAMING_PREDICATE Execution-Latency: 3 Execution-Throughput: 1 9: @@ -263,8 +333,10 @@ Latencies: 10: Instruction-Groups: - LOAD_SVE + - LOAD_STREAMING_SVE - LOAD_SME - STORE_ADDRESS_SVE + - STORE_ADDRESS_STREAMING_SVE - STORE_ADDRESS_SME Execution-Latency: 6 Execution-Throughput: 1 diff --git a/src/include/simeng/arch/aarch64/Instruction.hh b/src/include/simeng/arch/aarch64/Instruction.hh index b1728006bb..9cb6eea9ee 100644 --- a/src/include/simeng/arch/aarch64/Instruction.hh +++ b/src/include/simeng/arch/aarch64/Instruction.hh @@ -393,8 +393,9 @@ class Instruction : public simeng::Instruction { /** Checks whether the current SVE Streaming Mode status is different to when * this instruction was first decoded, and updates the instruction group - * accordingly if required. */ - void checkStreamingGroup(); + * accordingly if required. + * Returns TRUE if the group was updated, FALSE otherwise. */ + bool checkStreamingGroup(); private: /** Process the instruction's metadata to determine source/destination diff --git a/src/lib/arch/aarch64/Architecture.cc b/src/lib/arch/aarch64/Architecture.cc index 76b0bf33d5..ff0282e9c3 100644 --- a/src/lib/arch/aarch64/Architecture.cc +++ b/src/lib/arch/aarch64/Architecture.cc @@ -192,10 +192,19 @@ uint8_t Architecture::predecode(const uint8_t* ptr, uint16_t bytesAvailable, // Cache the instruction iter = decodeCache_.insert({insn, newInsn}).first; } else { + Instruction& cachedInsn = decodeCache_.at(insn); // Check if SVE or Predicate instructions need their group updating due to // SVE Streaming Mode activeness being different from when the instruction // was first decoded. - iter->second.checkStreamingGroup(); + if (cachedInsn.checkStreamingGroup()) { + // If the instruction's group has changed then update its execution info. + // The newly set group is most likely to be the most accurate, as an + // incorrect group allocation is only achieved when an exception/flush is + // triggered by changing the SVE Streaming Mode state. + cachedInsn.setExecutionInfo(getExecutionInfo(cachedInsn)); + } + // Need to re-set iterator after updating the decodeCache_ structure + iter = decodeCache_.find(insn); } // Split instruction into 1 or more defined micro-ops diff --git a/src/lib/arch/aarch64/Instruction.cc b/src/lib/arch/aarch64/Instruction.cc index 9acd2f53a6..dd8fdc5f67 100644 --- a/src/lib/arch/aarch64/Instruction.cc +++ b/src/lib/arch/aarch64/Instruction.cc @@ -164,30 +164,35 @@ const Architecture& Instruction::getArchitecture() const { InstructionException Instruction::getException() const { return exception_; } -void Instruction::checkStreamingGroup() { +bool Instruction::checkStreamingGroup() { // Only instruction groups that depend on SVE Streaming Mode are SVE and // PREDICATE if (architecture_.isStreamingModeEnabled()) { if (instructionGroup_ == InstructionGroups::PREDICATE) { instructionGroup_ = InstructionGroups::STREAMING_PREDICATE; + return true; } else if (instructionGroup_ >= InstructionGroups::SVE && instructionGroup_ <= InstructionGroups::STORE_SVE) { // As STREAMING_SVE and SVE groups have the exact same sub-groups and // order, we can minus the value of SVE and add the value of STREAMING_SVE instructionGroup_ = instructionGroup_ - InstructionGroups::SVE + InstructionGroups::STREAMING_SVE; + return true; } } else { if (instructionGroup_ == InstructionGroups::STREAMING_PREDICATE) { instructionGroup_ = InstructionGroups::PREDICATE; + return true; } else if (instructionGroup_ >= InstructionGroups::STREAMING_SVE && instructionGroup_ <= InstructionGroups::STORE_STREAMING_SVE) { // As STREAMING_SVE and SVE groups have the exact same sub-groups and // order, we can minus the value of STREAMING_SVE and add the value of SVE instructionGroup_ = instructionGroup_ - InstructionGroups::STREAMING_SVE + InstructionGroups::SVE; + return true; } } + return false; } } // namespace aarch64 diff --git a/src/lib/arch/aarch64/Instruction_decode.cc b/src/lib/arch/aarch64/Instruction_decode.cc index 92920d278c..2bd3a6e6d0 100644 --- a/src/lib/arch/aarch64/Instruction_decode.cc +++ b/src/lib/arch/aarch64/Instruction_decode.cc @@ -689,7 +689,6 @@ void Instruction::decode() { group += 2; else group += 3; // Default is {Data type}_SIMPLE_ARTH - instructionGroup_ = group; } diff --git a/src/lib/arch/aarch64/MicroDecoder.cc b/src/lib/arch/aarch64/MicroDecoder.cc index ea181c8d66..7e98866d7c 100644 --- a/src/lib/arch/aarch64/MicroDecoder.cc +++ b/src/lib/arch/aarch64/MicroDecoder.cc @@ -615,6 +615,29 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, } } } + // TODO: When SVE instructions have micro-op support, include the + // following code to ensure instruction groups are correct in SVE + // Streaming Mode + // + /* else { + std::vector& cachedUops = microDecodeCache_.at(word); + for (size_t uop = 0; uop < iter->second.size(); uop++) { + // Check if SVE or Predicate instructions need their group updating due + // to SVE Streaming Mode activeness being different from when the + // instruction was first decoded. + if (cachedUops[uop].checkStreamingGroup()) { + // If the instruction's group has changed then update its execution + // info. The newly set group is most likely to be the most accurate, + // as an incorrect group allocation is only achieved when an + // exception/flush is triggered by changing the SVE Streaming Mode + // state. + cachedUops[uop].setExecutionInfo( + architecture.getExecutionInfo(cachedUops[uop])); + } + } + // Need to re-set iterator after updating the microDecodeCache_ + structure iter = microDecodeCache_.find(word); + } */ // Get the number of micro-operations split into and transfer into passed // output vector num_ops = iter->second.size(); From a41225f96594324046291182579b4141bd81f0c8 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Thu, 30 May 2024 16:18:29 +0100 Subject: [PATCH 10/48] Re-wrote checkStreamingGroup function. --- src/lib/arch/aarch64/Instruction.cc | 46 +++++++++++++---------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/src/lib/arch/aarch64/Instruction.cc b/src/lib/arch/aarch64/Instruction.cc index dd8fdc5f67..6f3a259aed 100644 --- a/src/lib/arch/aarch64/Instruction.cc +++ b/src/lib/arch/aarch64/Instruction.cc @@ -167,32 +167,28 @@ InstructionException Instruction::getException() const { return exception_; } bool Instruction::checkStreamingGroup() { // Only instruction groups that depend on SVE Streaming Mode are SVE and // PREDICATE - if (architecture_.isStreamingModeEnabled()) { - if (instructionGroup_ == InstructionGroups::PREDICATE) { - instructionGroup_ = InstructionGroups::STREAMING_PREDICATE; - return true; - } else if (instructionGroup_ >= InstructionGroups::SVE && - instructionGroup_ <= InstructionGroups::STORE_SVE) { - // As STREAMING_SVE and SVE groups have the exact same sub-groups and - // order, we can minus the value of SVE and add the value of STREAMING_SVE - instructionGroup_ = instructionGroup_ - InstructionGroups::SVE + - InstructionGroups::STREAMING_SVE; - return true; - } - } else { - if (instructionGroup_ == InstructionGroups::STREAMING_PREDICATE) { - instructionGroup_ = InstructionGroups::PREDICATE; - return true; - } else if (instructionGroup_ >= InstructionGroups::STREAMING_SVE && - instructionGroup_ <= InstructionGroups::STORE_STREAMING_SVE) { - // As STREAMING_SVE and SVE groups have the exact same sub-groups and - // order, we can minus the value of STREAMING_SVE and add the value of SVE - instructionGroup_ = instructionGroup_ - InstructionGroups::STREAMING_SVE + - InstructionGroups::SVE; - return true; - } + const uint16_t currentGroup = instructionGroup_; + const bool smEnabled = architecture_.isStreamingModeEnabled(); + if (isInstruction(InsnType::isPredicate)) { + // Decide on predicate group based on whether SVE Streaming Mode is enabled. + instructionGroup_ = smEnabled ? InstructionGroups::STREAMING_PREDICATE + : InstructionGroups::PREDICATE; + } else if (isInstruction(InsnType::isSVEData)) { + assert((instructionGroup_ >= InstructionGroups::SVE && + instructionGroup_ <= InstructionGroups::STORE_SVE) || + (instructionGroup_ >= InstructionGroups::STREAMING_SVE && + instructionGroup_ <= InstructionGroups::STORE_STREAMING_SVE) && + "Invalid instruction group for SVE instruction."); + // Get instruction group offset. + instructionGroup_ -= (instructionGroup_ >= InstructionGroups::STREAMING_SVE) + ? InstructionGroups::STREAMING_SVE + : InstructionGroups::SVE; + // Add instruction group base depending on whether SVE Streaming Mode is + // enabled. + instructionGroup_ += + smEnabled ? InstructionGroups::STREAMING_SVE : InstructionGroups::SVE; } - return false; + return (currentGroup != instructionGroup_); } } // namespace aarch64 From e1781d08038d00410c481ae29dc6294b947ece22 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Fri, 31 May 2024 11:27:17 +0100 Subject: [PATCH 11/48] Added unit tests for new AArch64 STREAMING groups functionality. --- test/regression/aarch64/Exception.cc | 3 +- test/unit/aarch64/ArchitectureTest.cc | 62 ++++++++++++++++++++ test/unit/aarch64/InstructionTest.cc | 83 +++++++++++++++++++++++++++ 3 files changed, 147 insertions(+), 1 deletion(-) diff --git a/test/regression/aarch64/Exception.cc b/test/regression/aarch64/Exception.cc index b987ae4429..dd92f698a3 100644 --- a/test/regression/aarch64/Exception.cc +++ b/test/regression/aarch64/Exception.cc @@ -389,7 +389,8 @@ INSTANTIATE_TEST_SUITE_P( "{Core: {Vector-Length: 512, Streaming-Vector-Length: 1024}, " "LSQ-L1-Interface: {Load-Bandwidth: 256, Store-Bandwidth: 256}, " "Ports: {'0': {Portname: 0, Instruction-Group-Support: [INT, SVE, " - "PREDICATE, LOAD, STORE, BRANCH, SME]}}}")), + "STREAMING_SVE, PREDICATE, STREAMING_PREDICATE, LOAD, STORE, " + "BRANCH, SME]}}}")), paramToString); } // namespace diff --git a/test/unit/aarch64/ArchitectureTest.cc b/test/unit/aarch64/ArchitectureTest.cc index dbc1fa65ac..a9d4c32c1f 100644 --- a/test/unit/aarch64/ArchitectureTest.cc +++ b/test/unit/aarch64/ArchitectureTest.cc @@ -117,6 +117,51 @@ TEST_F(AArch64ArchitectureTest, predecode) { EXPECT_EQ(result, 4); EXPECT_EQ(output[0]->getInstructionAddress(), 0x4); EXPECT_EQ(output[0]->exceptionEncountered(), false); + EXPECT_EQ(output[0]->getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); + + // Test that a cached (when SVE Streaming Mode was disabled) SVE instruction + // has its group changed to a STREAMING group when SVE Streaming Mode is + // enabled + output = MacroOp(); + EXPECT_FALSE(arch->isStreamingModeEnabled()); + arch->setSVCRval(3); // SVCR.SMZA = 1 + EXPECT_TRUE(arch->isStreamingModeEnabled()); + result = arch->predecode(validInstrBytes.data(), validInstrBytes.size(), 0x4, + output); + EXPECT_EQ(result, 4); + EXPECT_EQ(output[0]->getInstructionAddress(), 0x4); + EXPECT_EQ(output[0]->exceptionEncountered(), false); + EXPECT_EQ(output[0]->getGroup(), + InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); + + // Test that the same cached SVE instruction has its group reverted to + // non-STREAMING when SVE Streaming Mode is disabled again + output = MacroOp(); + EXPECT_TRUE(arch->isStreamingModeEnabled()); + arch->setSVCRval(2); // SVCR.ZA = 1, SVCR.SM = 0 + EXPECT_FALSE(arch->isStreamingModeEnabled()); + result = arch->predecode(validInstrBytes.data(), validInstrBytes.size(), 0x4, + output); + EXPECT_EQ(result, 4); + EXPECT_EQ(output[0]->getInstructionAddress(), 0x4); + EXPECT_EQ(output[0]->exceptionEncountered(), false); + EXPECT_EQ(output[0]->getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); +} + +TEST_F(AArch64ArchitectureTest, predecode_streamingMode) { + // Test that an un-cached SVE instruction is put into a STREAMING group when + // SVE Streaming Mode is enabled + MacroOp output; + EXPECT_FALSE(arch->isStreamingModeEnabled()); + arch->setSVCRval(3); + EXPECT_TRUE(arch->isStreamingModeEnabled()); + uint8_t result = arch->predecode(validInstrBytes.data(), + validInstrBytes.size(), 0x4, output); + EXPECT_EQ(result, 4); + EXPECT_EQ(output[0]->getInstructionAddress(), 0x4); + EXPECT_EQ(output[0]->exceptionEncountered(), false); + EXPECT_EQ(output[0]->getGroup(), + InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); } TEST_F(AArch64ArchitectureTest, getSystemRegisterTag) { @@ -239,6 +284,23 @@ TEST_F(AArch64ArchitectureTest, get_set_SVCRVal) { EXPECT_EQ(arch->getSVCRval(), 3); } +TEST_F(AArch64ArchitectureTest, isSM_ZA_enabled) { + EXPECT_FALSE(arch->isStreamingModeEnabled()); + EXPECT_FALSE(arch->isZA_RegisterEnabled()); + arch->setSVCRval(1); + EXPECT_TRUE(arch->isStreamingModeEnabled()); + EXPECT_FALSE(arch->isZA_RegisterEnabled()); + arch->setSVCRval(2); + EXPECT_FALSE(arch->isStreamingModeEnabled()); + EXPECT_TRUE(arch->isZA_RegisterEnabled()); + arch->setSVCRval(3); + EXPECT_TRUE(arch->isStreamingModeEnabled()); + EXPECT_TRUE(arch->isZA_RegisterEnabled()); + arch->setSVCRval(0); + EXPECT_FALSE(arch->isStreamingModeEnabled()); + EXPECT_FALSE(arch->isZA_RegisterEnabled()); +} + } // namespace aarch64 } // namespace arch } // namespace simeng diff --git a/test/unit/aarch64/InstructionTest.cc b/test/unit/aarch64/InstructionTest.cc index d76c8c1741..83dae83cd8 100644 --- a/test/unit/aarch64/InstructionTest.cc +++ b/test/unit/aarch64/InstructionTest.cc @@ -58,6 +58,18 @@ class AArch64InstructionTest : public testing::Test { &rawInsn_cbz); cbzMetadata = std::make_unique(rawInsn_cbz); + // psel + cs_insn rawInsn_psel; + cs_detail rawDetail_psel; + rawInsn_psel.detail = &rawDetail_psel; + size_t size_psel = 4; + uint64_t address_psel = 0; + const uint8_t* encoding_psel = + reinterpret_cast(pselInstrBytes.data()); + cs_disasm_iter(capstoneHandle, &encoding_psel, &size_psel, &address_psel, + &rawInsn_psel); + pselMetadata = std::make_unique(rawInsn_psel); + const uint8_t* badEncoding = reinterpret_cast(invalidInstrBytes.data()); invalidMetadata = std::make_unique(badEncoding); @@ -74,6 +86,8 @@ class AArch64InstructionTest : public testing::Test { std::array ldpInstrBytes = {0x61, 0x08, 0x40, 0xA9}; // cbz x2, #0x28 std::array cbzInstrBytes = {0x42, 0x01, 0x00, 0xB4}; + // psel p4, p0, p2.s[w13, 0] + std::array pselInstrBytes = {0x44, 0x40, 0x31, 0x25}; std::array invalidInstrBytes = {0x20, 0x00, 0x02, 0x8c}; // A Capstone decoding library handle, for decoding instructions. @@ -85,6 +99,7 @@ class AArch64InstructionTest : public testing::Test { std::unique_ptr fdivMetadata; std::unique_ptr ldpMetadata; std::unique_ptr cbzMetadata; + std::unique_ptr pselMetadata; std::unique_ptr invalidMetadata; std::unique_ptr uopInfo; InstructionException exception; @@ -627,6 +642,74 @@ TEST_F(AArch64InstructionTest, setters) { EXPECT_TRUE(insn.isWaitingCommit()); } +TEST_F(AArch64InstructionTest, checkStreamingGroup) { + EXPECT_FALSE(arch.isStreamingModeEnabled()); + // Insn is `fdivr z1.s, p0/m, z1.s, z0.s` + Instruction SVE_insn = Instruction(arch, *fdivMetadata.get(), MicroOpInfo()); + EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); + // insn is `cbz x2, #0x28` + Instruction nonSVE_insn = + Instruction(arch, *cbzMetadata.get(), MicroOpInfo()); + EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); + // insn is `psel p4, p0, p2.s[w13, 0]` + Instruction PRED_insn = Instruction(arch, *pselMetadata.get(), MicroOpInfo()); + EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::PREDICATE); + + // Without changing SVE Streaming Mode, calling checkStreamingGroup should + // have no effect + EXPECT_FALSE(arch.isStreamingModeEnabled()); + EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); + EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); + EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::PREDICATE); + EXPECT_FALSE(SVE_insn.checkStreamingGroup()); + EXPECT_FALSE(nonSVE_insn.checkStreamingGroup()); + EXPECT_FALSE(PRED_insn.checkStreamingGroup()); + EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); + EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); + EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::PREDICATE); + + // Updating SVE Streaming Mode should mean calling checkStreamingGroup changes + // SVE and PRED groups + arch.setSVCRval(3); + EXPECT_TRUE(arch.isStreamingModeEnabled()); + EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); + EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); + EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::PREDICATE); + EXPECT_TRUE(SVE_insn.checkStreamingGroup()); + EXPECT_FALSE(nonSVE_insn.checkStreamingGroup()); + EXPECT_TRUE(PRED_insn.checkStreamingGroup()); + EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); + EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); + EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::STREAMING_PREDICATE); + + // Calling checkStreamingGroup again should have no effect on SVE and PRED + // groups, and should return false as a result + EXPECT_TRUE(arch.isStreamingModeEnabled()); + EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); + EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); + EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::STREAMING_PREDICATE); + EXPECT_FALSE(SVE_insn.checkStreamingGroup()); + EXPECT_FALSE(nonSVE_insn.checkStreamingGroup()); + EXPECT_FALSE(PRED_insn.checkStreamingGroup()); + EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); + EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); + EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::STREAMING_PREDICATE); + + // Disabling SVE Streaming Mode should cause SVE and PRED groups to be updated + // again to non-STREAMING, and true returned as a result + arch.setSVCRval(0); + EXPECT_FALSE(arch.isStreamingModeEnabled()); + EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); + EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); + EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::STREAMING_PREDICATE); + EXPECT_TRUE(SVE_insn.checkStreamingGroup()); + EXPECT_FALSE(nonSVE_insn.checkStreamingGroup()); + EXPECT_TRUE(PRED_insn.checkStreamingGroup()); + EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); + EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); + EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::PREDICATE); +} + } // namespace aarch64 } // namespace arch } // namespace simeng \ No newline at end of file From 54ebf7cb69d434c575f9ed29ed95c55ee7ada97b Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Fri, 31 May 2024 12:00:19 +0100 Subject: [PATCH 12/48] Updated aarch64 groups diagram in docs. --- docs/sphinx/assets/instruction_groups.png | Bin 56386 -> 0 bytes .../assets/instruction_groups_AArch64.png | Bin 51409 -> 152824 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/sphinx/assets/instruction_groups.png diff --git a/docs/sphinx/assets/instruction_groups.png b/docs/sphinx/assets/instruction_groups.png deleted file mode 100644 index bf5bf5c73a79a69258bd5b8088349cb5627d7ea9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56386 zcmbrlXIPU>w>GSZiXtLirCAZB2MC1TLVyrRXi2C-fKZdr5;`Ix(v_-$fGCR6K?S5K zRY1Uk6s1=M1Oe&oop?X@^XzZ$eH`EY9`BE|$#u;&vu4e?)~t1|NVEZh<>=|7`}XZ) z(bds1+PCk(%)Wj5TbT}l7Is(z0etNDGD2wVE9~U^v2PzU%o~pLcK3C3c5~QwQCjn_ zZxbamlT(gmyr>dmj>;|wvM)*&i|zs`jn^+o?gym(qA)@ zf{H`MW&RqwgSRd5uU3DQmyx`*oTG^&(okAM3?>b8M*Ve-w;#pfuWN{8GSLk@6LL`+ z4kY?7(SiP*|0OJaA72d&#@G$vPt>>bmelw5*0%lYayc_8dwZy^3<519MYX3nP`%Cc zjV?koq)`44cM=YVkTaCB_eUa4kXlZS||bPBKNKjWh_hcu#424>PoS%X6vbUx-9^*tX(^Ho<#TYp{%Nsc0 zwKe6T^5*8QE?yq)1PurYqd}vA`{f{LJ0m2;)WF*nF;iY_M{r?`6A#*w3H|K+XSzHvDJlnP#h(xdfw7#7fE@nx{;=tp(&i` zYK*cc8Trsq1}1uV0uAHrBjbdGoA_(#Q`~4yJ{X$3tG1LD&D6xsUCT??K-+_Y2hY}o zsoTQsX#_dEF5VlC^u(b3kT@5ANfYoiJ*Yjw-O$m4E^>$o)W`!WkA^uL5q$}GU6P)L zy@|XZ429QorMlp?%xN+(Zz)p;LzE6o3-9afqe)el)YQ|{lk!4&8EX2tBV}C7XwE32 zyFCd()N@wH`@`LhY|St*Jl-6y<)e-#Lww*)a14NQnXFvF~$TO zR!&`mN_KK48Q>gUX>bR1O(`8T*;NVwMQG`}pd1iVGWJ^jV4%9vl9~<_V>@GKJ6kx^ zmVnlwph;x+giQb9jdnHAgld!Yh*(KuS!q*}zKkwt zhMC)Y1F>s(sAF9X$bMK?J+ccFZ(9gT(8>O|VF;2N;xwmysq`!vXAY4Y(n~ z4u>={@j%GC$f+CJn%Ya@NoEL$49v;Jn@liv(Lzw{yi5^x>IesY1F|$m&P>A<=YZ34 zQupws`Dv0|{iOZn9Ub)yeB6)-eH}w%DXc5m1fYP1i>C+7P}>NPHFL1XX?sd~BW1kZ zNQQRK{&+hVQ*94_TP>K2zbh78O2qh)JY29IP!ChGnH)ye*2&((g=pxF#~I4I>w4g9 zQFdf)c{1L>S(8jMfkU-vp7vV{d9mFmp39M8eQ^6j^z+yezl^LIQ6FXqYSbz(Ywi1Bkc2IZ4}==I!F)DDP(H zL)PHQG?t|Ab7@yOguWTkTwB*&pF%)T%yGI@s*JQ2%mWJdAe&H8 zaBzo%td0X7LXdRCxS2TQ+W9~Y5olL0C|UAPT^9Sx8UI10?oRo-4*lWM17r;TycLpu>Jfw8Mr=1MqbL-2`aDYqY3kpk%4Hq$?6fIRJgVeia^$vlp+z0 z$#!J2wi_^n+K$>@Zmuwxlexc(r;(#0k)S6BgZlZ?^o-#soTi_#BY|RWuIJ^cu4RPO zMk7!(Ph*^|EmU3C9_r|=?O}+bkYwOE9kQ0TmYF7zjZUqcrI3dP=E+tC@PY2>YiqPpprdqJU25C|3F zW{jo+nQ2qC4IRl4tQPQ1v>{l!w!#evk|?T|oDKp)G$+cyyfihb##kc*FGndelrI>n zo`J8glc|xjjE=LEtEQ$b*52G5K`_SqnmRcVy`&A@QGVKPI(7&u9AaSW1U1D|-H;v{ zJ}`Azb1z#Q0*p^X9qva!JBh>Cs!l9p1ik| z7QxkC_~2_9W!-XsE)6x1{q6LmjQSS+DIsG4>LI& z*~`FB($UzS46!BQU~&|7Jt2~+jnN4u9muqul3x6!xg5otL4(!b`n>40~Tts;ts+^ z`w&fWgav-)D>F7)bA7zfxii$3n|*8nO+$)VeTNUiH!|d;D~DGphTlZC27)>_CjERJ ztBIEs{jk)8yO<+_PNC{Ml03zEUxzP&j}9=Vln2=L6vQZmAS#H@~yhPt-4a5 zy>G+2Q(s@YVpn0x9~44Wch@zYjxjz-_ta}q&GBXwGD!a}qyLnE5U(9}esWJJXn)&} z;GLCTCr%l`e)OkILfm0~Md}Mvoyx)T;b7j_>l3z!Q^o=@SYwoIa*Ywnyndl>Pr#?z zMLQ-WF+0Psq)hTFrGaIzv|W65^Y@SOsk?-@ZZ3zcNLb0!LY)VWoT_OfBRpOY$$6-q z$qedO=arq)jZb!o*QV2>2lr$$zD}^E2~IYdxVaVN)eQ*uNcCb9A_`dT&&J8Ec@~V0wG3C-R*7e^%J{k;M?wD?lIW?}}{r#%A zjbIeZ!}Z9_*lS|to0;qVOnsg$^C2beWq-yq#Zy(idEO<@!!7u~H_-BBmmA}RtH@Ih)N_4f_nfx=n6-2k$IDN$b-zLIh z*Uq7{ z&Yxy8w=@%^&A_W!hKgr@{|2ze!P~?nPT=6!@&9Dnje}Ccg+`EMf`E|D&mFYHf42sH$@6emf`STTlI**KCac zYD`{mLp`&^oOaB~QAL}Wq?HKvM{$1Qn%i!l*#2I!b{^GM&81?tcUZ7)Fsk21c5;xr z9e9HED&x}1P0)!E)Ie%gSCto!=U^5OXke^LuS?frI*Pf@Pw(!2A8uDyjJ z`(HM3TU4BnldmtR+ucmuKQXjusIt+>!Y423RpD$Sx%^(b3TW;SN~(#|IeHygE2^3# z%=O;y>==>b_TOu5Q@gG!kPs28RtpxqtE9c1r(n*NgD%X{OSg;U>|2Y(xK^yF{Y^XD z%U$ys0rRbVzJnq&4L4bq*J9&O%eINU8gGvE3ffxr+1p*K8%(tc{z0=y_%R-@O63sJ zry#{E?WZW8tFLW6A*Oq1%Xy47%Jf@wBu+-K7bL*Mb++B=|G8*PvvWh%M;BUN$hq*{7LvJUJt^OAiZEer)L4BAZu%@&joIHX!lk!n`V7DlTV zYPVj89anhwz<=i1{9IYrs)Ji;tI+P6sBwev43j7>3szQKe^jKR*E*o1=JzM$@ku4& zpAQs#JS{_d%7}*L^RH(WsPMwdsnbP#nckmt=fAoZ`NXSi=FWb~iQe0K@!4S3I(Wlj z!F;jX*s$`8nMDV4&;y?ykD}_OC{<+b=1g7{FS+`o$R3k>yz=TVNP|m!)80*9Qm)?3 z?nj21DyEZ{S12ihdN1^*D$XpH9YJjW(MgLP37hQ;tgQ{&XKX47Ytwy`lhJ0YFC*!D zyr1J;FK_7t)&R3Nl|~*o7cDyGm>EQ+eSa9Cz`3yhz@ZBDutSyn)V{YY0!n>Vg&Y+D zv9dkCUVlv^*ZxphA2~qB)GAY~)fb<+zK=VzHhZ2xi5_=F8^}3-xv&e)&(vmDqUdZ4Go-(8_Xo6rb?Li_X^Rm%E9oA4f$Py4Ghj-!xFyz z<^Zc(=u#txp>H1SwZIW1%(}bc9V@>=cM!0B^FY4Tz4aE=>M#7|RHfX=pqtjWMpG`p zYoda=Ien5G6c~x0cyL!kQ`phn9<+)dPtvxBk8-VK*|VO4G+OkqopIj!S-wWQx2)8& zYHR>&V!nNAPB7>r60o zf7D-ACU0*tI&*HMDcfzAXHHrydK+ZuMjYSl z2hy4luNYyV0U!u~r_UBk6|&z_5}w)H=n5I=kQ<&OWDEiaL_oA~fiE^C+ZwLQ9Ob_h z;|~b{a>)sJ7|!k4#JOTc8~kF?UQ{)&P*h#FHWaYC9Z;Ohb7e;OH?HRg6Rx-99X8GG z&v?IO_=i|;yRpZ#E_@@`tqk|%mvw%1$qC+=9r|yBF{nSX2g1Km0N_BrfVte5s_|t^OVcV*VdswaQo@n z#&VbHj=R!led*Y=fceVLoF5(i{uqXR2MANz$MDW1&U$0cCWp5NdD2C7ywcv1C!6SU zDiXuvr+>-#bp2WS1!8p;9VAm!LV)BqN)CxAz8=&QDVQKt{e%w7(wWQs5 z9hNVOQ%^~2oVrI85d2{k<A1H_yrBJj*}EEsuzkI^yR~!1sDmr~rQ^vk!C_d?$Y_M%>KEc#8Merp zwA>-Lw%6fva|_rnn`|h){4Tf+sdrRMIBH78Y@g*}o0I8(g^Y*O^tX!@th>5SR< z>J#=CE_8~7`-j)Dc_-{k3is4)7^;tFdfKJBS1p*A5P6a>FqJms_cV?4`iFS|x46w< z6-}ZwCF@H1JdTJ_H9Qc zw@lG&Z6*}YL67a#XN&e9ihIVUIt2!@Hbg40>OGx7Jbr0u0s77Dvk~KlhsQ+BIc6yP z5Dg*V_ZZuz`+i(>UB2!lduU`QY?@E*i;3~eZI)=}!aF-#YinlrPUPmwPUVZ-dSpER z%~gzCFmdNe(TkL)-F@@ z3DrBbcds379yNFXCFl^Ot}oQ%I>B<}V#Kat@uXfYvf5P2j!S4vF=tUh>|&Qvkl^>D z`JstN;I~iW8(WS>*)GwhjC(Ex9%%e{^jY6#*vc{92;T!`AL0Jf4`|i%i@>J8zUO%V z+1%!>k|-(Y4}N{vZ;ocu<`*w6zfwwAVG4@(X*08MUrD_(mfd->^YopU=Vmnr1|q+9 z^6868cRqU5TLQKHiD;xX`)w+}odk~ONX_%s2BE{VTyZ*teM7EAHPzd=tq#?_ZRbUk zq@ww-*6_&6yYL51OJM5_vitFWpSv>F*@-~6W!KJ?w)@LbRZbt0VJEROB_EWppE{;x zJN+b#!lS@E;ldG3R8dkX#$9e_&9UVFv2GdBVjo*-@LNmBPSiE<%mq##1%nC;e zk8O)-)e(!GMMShMmY4%iojECgQZga37Gl?U>v^HD=%up0I*W~um)6ZN-S{(C`^WTH z4w>)niI%+|Q=rYy6`%ajau;`Z`;^Wp9;RdL?8C}o&}a>A0o;)81mV1}XeaZjZGiG( zJIVVqU*FJ*VP=T=5Tffgws@S=YNpe!IYD%ri4>W}jnRjtXxh1jo{EBq+ZH>NL_bAC zO0qQX2sfofUXeU6aCrRe9&h!jUEpMG@w+5RLQ%JR-)`a4&#N};B$bGsGGEWRV^O&a ze2k*|_6e5NInQif0{9RyvmR+abUJN3&~F3;sTIfKSt9xVA=+M=vO#X~I&(&*Yn7l(LPB zn?q3e)@9c#P_t7FC8W_--yy$gzvjtiQlZ(EOP_J>&IRe!?FSA%NW1Yp?W7jktdDVY zTWlM-f`R5>`Y>(x*3gXob7KJ`PQt@3=oG!6)ch(x2`@E>t^FH~Q__>V0)cC8x8B5{ zE;n-|*?fKP_dP53QR15vqU5T_q)gkH<^x90Rt~$W^*|aYj|x=Bq{cYBf0!U#sOGWqnQ~Y0vZG`(j%$0sKa?|*(`SKNA zYYfg^vH>@s0W%90z9;(W$a?53TO?d^_z3gyG5xEi1RfaU=Ey1TA*`iGczMqaxWuqf zPy&Cj(5vEaRt6YWvxA!pM=qs*@Ekn9px&x=D(C&}_26eB;%2RPPdWFQuiK(*F>ma{ zl5ca028n*a2_Kw15MC+C=9^>m3ioqSMu&9mM(wGjEVK$U``uCPz;>~6`?e4D60y~7 zD_E$SC`8xz5;CKYZlgu57w?{ZSRvK5#PUcuD>q_a@k5koW3i^2xuGA->7-WPHEmRj;U~Z>qqKbLXgb?~hjXIVMF}59qtg zlxCXTmTR_@`$Ak&CxVBZ=yw!?F@^X*ck=%2vBbkM( z8p267DK5I*7nQH%u*cqlQR7)_Gi)WPYc}V7Lwr96=meR$b`L|V%+`X(Jx2a z&g)8yoDbbNeFhv$vJ)$~OUc8v!L}L~Fs`Lbnz}8e0!o3!+Zdsv0cdUt(q8()h2WNp zrADtNTv3>opm>P+__gqagJ+`e0%X}R6{+*wNnR3#JbR_mGfh|)d73+}cS}(rh@&a> z-~~M?QmHT_&a&i0iJDz#6QAbZTMMC>@Kyr%3)Pt9rX+<;Rco)n^SW^Uyz|TQEid&h zCUrzh)b?3?!U*>}8JK(MU7l&Gt+89kOIFI?5t@*Iz8dRzbEuV=88js~mvC8Fa@0J> zhyapmz}oe+wN@#eBw*g%lPj4jO}V;UOR+-tA;NOfSIi#jXKdo{P@6-jGb7?E&C>ZUCG`*h#|-@Z3ovx>9TlwLVEy#iIV zij>ZoOVt~F$8@jE#Dq`wAgZIQ-aI2hM)!w?zO$2z7K^_dlw;kNkS%~Q!bz3fTBu&` zyx8TwBz2QN=#b`a+Moe-XzIReA-CKP&eRoHA6fVVu)xYm{M>654Q1^Yqy0T1r7J(x z;V3s78{6;gdSW@7XAsWqkstSP#U&$z>tP3u^a^p3pdl3O6oQ3iR_EZEuJ?0FsgyVi4wGAkt$ksU?p*%|pF zLx%&W-LAi+azmAP}fp)@Xb%%_OgeS5{&a_Q& zV(UxSkN1oiMfsPIi~6=)F0vvsb*IFjuS%urOTsA^Nf6eS%3sf!5FE(Z!Q^)`W)|im zPX#94`o`BcZziz>L2JHG>q5U=RVr$| z^os}h1i;i`#;QHPjJgTG-~V>d!5DUl`xsC=DGv;V4)IXu`%e+pL>;4)DW=Bdc2NrA z?)u#NZ}i)Yx{<~OjVm>MT;X5di9{0%cH+qgMI3Hn)PCcYuzk;(4{|vqHZc?iRv6uE zWVjva3E~pJrOyA-dE+49kR0C3V-q;a^M%p*a!xJ*_2?LP_XY0w^ewwjlNQIP^TOZ{ zyp|aq&-$7Qh|YAMif8N`9BaNMa>4pwdZfs7Ft5-rBew&~J)Ay;YG;3$F}Wnp*`zOD z3_jSi3wGs}&C6k}%H61gZRZkQW(h$mQ2HsC*HS(7sx_1NbZc4h+w3?9Utyar$=qyq zv$I)h8qwf*RsN9y-|4AKqLZyR!ZXLklv*m?wCCYc1qWqaoyekhAQ6#V~i}Q+sotK_Uw(nhgF>GMHq>Jf_zL35wC|pH87A#dH z9I1TABrN}Kw!x`mS}%CyL=TDJyQ32ev@jCf=#tZZ4vYCO_dHgkvaW;|{+tt7o9q9a zdGOL*UglR5ANO$&RwP4Cjg{1Uu`2&Yx6i9`ABwZN3Kz-A9e3=~;4?hMo_JXuPHA`W zbo&|OU(8)1b>dvf69?DHmVo{m;!<4!*9vW=-ioVF^mdU(WCx|wz_v`iofJi zg3AnA4?|42Dy4bBlH0gd=vB76No<#eu=pPcYJ9fHtcit)4? zSJatk^5)r;aEgu4!jbuwicf?=TXliX{0RT69iyvsL>5Bcx)R7>Hx|Ygxaq zezdjaA%(n4uss(1-IoSi(VXdLU%KBF`q2fg`(L)|is$od2r(ky8Da z>wFv6VM7=76vcq%6Fzn&ci^#6cL>H#KB%s_@MFFO7F}grI)+ zYzR-lG0yk5MSRYymXxRF9;k0W(L~!8WT=AC2Ve&FszDNvxr|*KgfTAAQ5l-dO{=HY(nx zX3~Bm`C#f`eb(_5g+{vT!d&G&M~ay3KlvhoO)~PyyW?4$E1yh|`0jQq3@*01)EBC~ zH~vju`_NR3Jg@oL8A#P`MH-=!klq#wKVHX;bJV#M=;; zU$y2c8g;A5qK%z;~&+4_>h>e=Hn$w z%6)>ku7rGCOK~leS#wWPmR@a5k3Ckz54VMSCs^npCdx|Y-BguxzCeC|Rr1;Xm&bpoq({BQR`X!*n$avP^vs=$ z<2apnyzy_da#Pb9W=92lejkdt!WUkz_{nA8vlk&A)ln(}wOmR;w^{bzz<)z$)?dAw zoMQFEtJ19dR5f0UM<_45^G#<^7zm22ar5VYpSyoPuoG33VKhu+!e1%KPH*QdG zz{q1dD%p%LM&~|3>sc7=@bATGxossWN?^hq(lw zrk^)Q3@dJU2_4hf*Wh#GDtb=dgOv2(3e~*N*3RyrXec|SvKqwy17*xCsm1R~jKjkt z!dcSa zWFacKcr!dN=}HH71~v;4M8{VwZ?5-0z7+f?qgAk*DiNFzF=2cDcF{n|me<_U5?o~K zYa=}cH+N)Wmc=X>xAk#LzULhqk7%FU`lH-O5gv)^DM!Xnq#cYFf1RtU5E+^p%W$3D zYwjj0?=ex2+vgcGoSz3mT`Vs2nm?F&8MqUW@nL#wFWG`2VWd#|_Du>u<2=;T_)Xlg zy$YV>vVw}G5ry_j=_J3-#8HKM)r>g zi#YQX#OD}qz70wr#(dSqwU=ZZfd1Hw(}*{E54$oHPB~H=dXfKNdceWTOv!=r7-qh- z1B^{?4u&bsJ&j?Ih_Ty?o4L{bY|`pYGW?FId)x4-;J^On}+?56W%vp+pe@U zWn}R)UcY+y>DRK-bipgtMCF2Ot;8L)=mP0RHJBk!%Y~-Dxd7S!aJG#j5eYFESw@*g zov2{=FLL(KVfce@R7%99hvgnS;#em3n0wWu&=YpCx8t{Qvm1N3{)Pgz(bW^2K0~~n zxrgPpDO`}D{?Qo!XOKQz@#6uJne|-`w!1n3=?C9jG5EEQ(N%OfczwX0f&Ub4Qi2RimE0JYk`<{TAVE{>s?5#D~ao_ffFIZYMo4PY5G$_Pn8!#f1zF*4ltrwYQ3>}ZzcT_=9w29M) zq1_`m{VI9Va(HbxBxIr1px<&$%VZU#K?cZ7BN-Vc-7wWI^{#ON1gPu2;#V~ zj2Ss;Q?>^;E=r_z^HZLb*6nZPdt&;Yo zp$^n986UP3ygsYQdpMnVNkO@XHbVnPFOwjyJ1+@5)Tq8myrNYN$kC)V{==nv+r}F2 z!ca}m`-V8~t zsi*Qu+1*&XF{KCfe&boV&?qWmdQ9coc5}6cIh46~6I9Fu4qo*Uq;wxUZhd6_E zy7SjMfjk*cm6FBmj0EkEy;RM9b-D!@i2v4PvEhN(0EzIQ@$6p4JmOOoZw?zeaQckh zeV9AGKh}r$Aa6PCSY<_yV8C3-?kR@1w(l;+oou$uXb`zSGAg{K6*L{A$TloBvLwNn zINonW>_#SkEPgxTX7#An%Yr_-ilzAfhq2A4KYC;NnVVgpU3h>`SI9*X@c``dLd<|J zpJKD|{i{R1${Y`OIu#e(E+6P}vAcJtg6DxqZKnUs<-K7(3!!>Ntkjbk7}pGSo*HcaFc z+*^X5S0hd+!SzcTH__R$rJYCFRny-5Lsfjpy`2!{Uu!P-6k3|wGJ5hQXJ@C^RPCqb z)k$mXXnI0pW`nj^rfc{Q`2j9(;{$rgbvsnSkt()C&J{kr*eCh##O@z9(LdDH=*(Eb z%ADM9ryPwKunaK*%3p_n_EvgLXOn&wp=4&Lf8dnVM0qCg8W-TBp`UdP%zsXTn_ znt-+4_T+<2R}y35?mCAXb9W-rr&(cLKFG-Gss5#b z!}o59^#6Jed$CtT*Ogwds(aypA1>R#0*6hITUa`&NOd#u%W}HX&otrl zC`@Fyemkvtx1;ClI*?5Z@i}|mg%bgXUv$s5i^(H*NUg{RrB~9j!T|fn^`m3CPYwP% z50YDG@-;r^Ct&JSB9}zgGR(IHM2hXXeF`Sm(w^+*Y}(vkvYWmKSZQDO>@-dNxH!~4 zzW18xD|xiF`i;D7*_6x6FMQw6psY)!Y6~z*mMohr$=(yEEfYv}rwWvxIj4#Bn=2BjbT5 z^wfTqZD?rp-)crz63=Kg4~Ek=OJ5W(#0R!&zSK2Ti}LrUw)NXH%KZAqDE_x+Os9Ue zi7^;;&*rc?RTuH-KFgS7(!od|bn2qt>@hiwl=~d~_Xq$(4ozaaooy`HSQJRAT^Gs zERX)S|CzCwo^sIrL4q3zMH6=<{Bof`j?g2e2C%f4Ylni<-uzdxoLVKl2mc=jPA|;D zjh+)>U}f6bJ}sO(6YZa*k`?*+CgyK^>S{KuKYEdbR`R$98q`b9_?4B|)sWnv=Rhc{%7ihm0XP$h-SK@b0% zn(ZR4HlHGT1AZJwd=jG&>V6XBY3V@*QI(`mY)-v}57Gb|^^=2{czK^)bS21km|f6P zV>Cberf=Y(X2cWQWxxliisZO7^{VC_AqDT)>b|4kGczIJI}$q3W60Ic3Wl_CC)_2$ zi$O4W-L}*9?!wH@uLjnQ!mFLGrFymD<*X@WXt~N4(HA=uxP1q1ROYGjAGl*<|NF} z0acN+2q4hR7Nb!wJlYephbl@<+rczX-?}EWdWikW{c{ZGKA;)zy9bh9tv1i+kMX2A zji+3K*LXPOr9^^fo!F0>W4WL&3kQRE$RzV^eZcK!>>$2L0{XF8%rMHIzik!Bi3S)q z5w63vLGYJ*J8Q#(CdMe!k7fQkj9OiYnt&AdNVWEV z769mifd%DXT|{VL-6}4oT9!JA)UJ;)%MAxESK5T^d_hTf$oO=do0@`tb=5ekHpA$h zP9&<8#ddY{4E5C*Y};|T4=g>-?TvJc0DLy!)$y+Z0&j&+uT^g>AMDcuz>1omEvlo^ zNhzEw3U?kozs%r##L3POX|Mt0qIJgNZ=tOT{4F%=OQrnsl&o)rc;x{)Z>`?y4M;o1 zRju?`4C-EbFj4#}1kAdSwlGu+2MLD~UO7_wH^6(WhCd*R*KK>swTqTj&}nY&WgSqT zPoAb=MfWk>@B6~~=ZTsB7QfHG#cyE0Mdzk9@z@OPX>K$>uLU`+SLwzJU-D9U6{-1E zK)nK^*B3HFcKhi(Rcnlm`^zr_Ak#bof+XS*pY|481gj46SQZ?3ZB@{ zb|N&8-Rae0W&c;+s@_N&x9nJp3?PMspL9ARomfeRPtR?{NOyi0n+8;bH0*oi23P=acfe;^oI~r98srD=+rgEBpWch{!w7dG<{3%xPyjiXsb}H~azl z?@5Ng3vJ~Kw!C^H(NM*MS?tB_fW;=B!P{pwtLuXSL27fje8}Hbu1jh8h475!4=7mc z&EctZF9SK>Usua}%w1uHr1Kak?|wb7;WjRO_|E(`&i)|aW_r0c5Bmr5o7>-c|toQA>X*%IHes@IJ9 z;Sc_EC+?^{l3+ZaZG-_sJBK!A=#W$?yV(ed`E-iC4VL1a|5GpL$gNC&ozrxjM!SY7 zg={ZIDE|JSxuZODwxD{cZJzF90BxuQY|*aj@bt1-TxZD(iShwYu_%SM9l$}FFY_$i z$qGB}5@z;289c`Mh)jcqq!{lc2VK8jUHEWpT>9uHpV#|Q7Ui=j#h)*B?_b4#ZeLSb z6zS42)HeWLz=M^e`I8mZ93{%&1akk{*2i4TqX7^O`q{u|-Re`KkfS=t5Lmlxiljx@=%iIBCF@abLRR$B%`G z6?Z; zFlU8JCjtV6#4*+!W}^+Pssj%~b~h@O^^Vk47b?z%3I<6OZ7*$F*_%pSp26R7&-Sd$ zc!W$9-;I*{^lP+X@6#q=_bMvfPhh&G=Fd>VbNz>Fb~=3)XBc!DN?M3*iP=fD@soIr z;qddXlQ)JR>n6IaY1BLu2KEQ`gD*39^I5>|#8k`K_4rb04%AWjvsFiockES-(C9W(^`RR&Qg__{B1HPF3EzyL3nS z@jc;Lz`ymnluo(61!#o>#}(&BIu&L`myDx{dE>IH{zG+be>fdRK9=kz){e^9x)S+4k8of?$i0 z?m46^>iq_QJaWKG>DQYBqzu0)53df{RKQf3KHPhx~}N4%yxcI#szY)l<;_`&pZ*!-9b$$vbqzCI*b;{P#!k)QW!9)jon4 zv30{ej0H-e9~Dex3IWTuZjk~C7)+84S%LnW7^-m)SKcRSG6KkQQ9rY~4rssTlJ7n% zf-?jQDF2AQXA$MEe}7M8wqiWa%TRUa1vXz7lpJ_v2Cd%v=0967NQVKyyyaa30JJVW zh^snMo8ldWux*(!5K!Ufbk84oq#f(|G~F`_yXyhFH*EVD7OxXRUg}SQz_X3iBo%R^njF+#8s#F6&V1tDy&ljJr!7+kk3@#4m0W@9qpO#jXSbQ@vbA zhz$XlTzxL?;2xN%TWk61SJ!~(?JIftW0{CZR_8l#?nSfR%TMmsr@nPmd+A)W(zER6 zQG{jR&-N|_=#bmSb8os1=^+1-@{6C(djtOjrTf>L-UIj->ex#T&)Eh$j7l5yN!@E_ zmZ%<~`#gJlB~R+s$D&D1T-e_|^8k_kAaMSJr+ap9FSFxQR?*;yIn zws0FgP|xNTM_l{rDzOG!=dCkTCC!cSCfOtGk5>Vo-*u3APk55tN&>i{RVM`Ssj zXF5iqaK-It*0$H7;Lj+zo#%>E$6N&y}N#Ws(2UOGkA)2#gfaG!YxekED9f>)BA=9vlSr_eb#dB7$t1 z38DlwpLjX1W*{C;&qy=8@p#D_dB!KHW%z43d4W0{L@Ng@+|9fJ9m~TJY09J@U|?3Q zJswp4CKb!iW@1Orb(T42(U(}6zQoc!ynozHmVZg^#j}iMU;+I9BRN-ePnLSvHkWIJ zU~mPt?TCJatK!FA5mb6+9q=~?=#@|^yX)hnM}tZ{SI%PfEW0AFJ-AjYr>L3y$6Vq6 znyN%Jbh=U>Y(d1ox1b|STYUk&+F~tq3LJ*a%7LUet3K!H7S-*(W`(ru%xYyAru{zq z^y1UNb7fAl@4^p)`qmFv4uN5!%ba!lGeeOXBKfi4!XkMwQ^eccY%lY{5i|! z?Y#P&2>2TxDz#ezB5dA7%G19&iLjm%%SCK3%_cRo<80z0<}kx?WQE2uiex~*04 z2gWi0jLn^zW%(nen{;?U`JJ>x&*=!?RNt6f&7#-fDTA80-IOd)iuDd83Ve3&+Z3*X zzZB;y8t9DX-6v;1fq>R**m2`d`avVb+TXeS?IGR@dQ}fUJ^X#oW4zh#BJag?*$Zux zVEzlqyXg2g39~nxIqDwe3W6i|Zkt^pmkOw<+u0)$9(FH$@eO)1iY*ur89m)L0Dv#Z zEjOIo{9O$I==pfnT_@X)5U+5^o+2oC+7R{XQZARvdMVW9GJ9`o!~7T0xXAH6h@a^` z4hDz?jGSU;5OAS(RaWW5$SQvKiqV_%069GAwn}~G3hJ2rzun+@?i1`YWcp7o1Kb#!j%izM zLGa@>NFqJ5J6)kxveh>7{C`J~my@V;`H%G6iS@%~rZ8Fl_!fF`LT+|keaupaS4Dc+ z6A_bcL)auIFbr#clW9bcFhuBuAaL?31YFqT@MYj<{*Ho1Dfpo)G_%F>m7k5XBSl9C zm)80StYjH;phy;-&r-K)PFI?=7u_#yzdWN`_>1n@)p#6>-k{rHs}WEvH<5w`Orz8U z;{DfVX-~PgpBEUHsYt+Uj$8naS4$PWify>ufL=o}V1yK#q*1|sUBI%h{(=;WCL z@3@S+VP&28-}YnU4h$7zQ6k%nbc=xI1-8_+0Z;y8qFjyuEzT1omk&~x0e9b?efmSg zoo2hElfb6`Tpgs@6!GzR19nMP^Y_*&}6U zYe$Nxp@gy}WbZwa5=BO3WUr8ymA(0158dT{AHVxOKL7uY!`;!{({nw> zHO}k2&gXc;N|)iulSes>6*$M%n_Wny=MHjz8l1e~vS>7m?WMwGUvsmdZB{jrO{RT5 zqp(+sdrn7y9v1q>Q7qUgE(#J=VZvYAin@i1235>sqn4Zj{GxN# ze0m|;uE)G&ts@xF8xH8h)+RW4UiS+8`cZ0!Th`8=!~RTeZ;1YRXJ)VvzbB@e1YX96 z1MX+6zt26se0Z+m90BKtx7-+2XU~mken%)W7Nw`^wW)#gJ)s>50laF4VViYeeN&ua z-uGvMFFjzzZsZe+To{kG6zzmQRLP_@#cEr(f-kqw{$qE`{SpO_NGlp6^)rRR^_ zKKyJ|mvTwb=z_|XHraVrz~A&ytiJqcY5#5%c^R!k8Rya`1+-_3x&UMw%?QDf#o|7l zK0+Fj7~Fnb;=Op0?r$!@Ho{v<^vRY^FdSJ~xvem6L{Gpb__CcLWXwoN9d zfMe5w)1Aary{`JBVKgLxv^1BykQxqoU3HeXWi(%FTR>%P+%VGb+%l zC7!@N(B(WH+lOL|V1|1vDi(H_wvUqLv!7o+3|Uu`8ScN)JLcb!_Rsc)chnr3g+-lc zD3|o1@3*QK63NN%pO@ICzm8ZfyEGT93?2fWSzuPEvI{!1gx4!zTA zI>S-gQ?&NYXVEA9#GG^QftdY zH{srpcVB{1t@gmrd&VykwPoXK$vz0S`{;C-8->j$r}78Tvl$&YB50j<$Lls#OQ_#b zIjKf9F(ppN8{7Hh;sR#pUTKd0UBuyMPRI94yj?$)m$jI`S(QORwX3 z^A6hG6G5fmuXKlzEkmoq;V_lce;B2u7>FFdKuP8=JmFX#JMO|qrub6teFv_x^I9k{ z#oC2Vetjj^dr2t@UM&Oeovye0mZHd%!BESYbhS%unwh=-ldE5452Q2y-4b7`I6|3B zEO1sXoDnA(|A*_%o!uPLjdb_9Ipf=aKDyfVEg(Kf=Tk3G*1xdd>^Ku5JPfsHXe?O# zT7kN{!N+!MK_jY#KSP8S^sHxvBy7XBUKeT>f;z#~5ZY;%<*A7dEk~`A#$;c{>5`rAQPjE7GMB90kVplDpT}7v_ z4?K?c+JOF3nO<7gsUg!x?Q!MEUnzZVeW*!sR)igg5of*s#%h=vO6$4K{F=GDhgytl zUb9diopueRA@xd3**+>czp1O2>_BGIf@`4p;v~#@4F|2MfXBQ^gobTs(C`E?UpUTUsXtF zV{<{Z2L((kC{^&K(*EWSX*9sD9gblek15skk2r#}TbIGkTmvNq3nhAw?KMMw=vOWS zp%$fI*iOo~6G@PL)N?>P@eB&a z3_AhsXYNCYIIy8+%O|t@)jj&`JDo?jfP`zymYI7=LE?ljZKEJOlRf)m8?zyHe!*x;`bM^zYM4jLd`$czb(+qK>5zwAp+1pEBYv+!6K z|NdAmJKI}Zk&8$}q#}RBg_e6rdEmw613A59g~6T$pSYwma#Rh%m5>-quZ@gGlnY62 zaDtuWaqIglq|9UcTh!c;NnL~~NP)uc?jmJ?Maqrh^z)6Z{B~WMw(K4g5(mZJCrGt$ z-jziNrgCcPtD@WW>8vYRI`-{K{nWDhYalkzd~4AQd!JkF8g$^bpK$r{0)_0JEFlZC zc09lCqRWZgc-S!rHct&b>nwUEvK}Z zJ@WkdESweFXjF<#B4MfRJJMR)FaGw{O}IUE!0!TJtkUlSV2QVxHPgq2EMt_CK|*-0 zqM!tuvPuzZG`LXG#L(^zkldeQpWyFeU)&QjZ0R@1)yOVCfQ;s&2q<)H$1U(o02aHb zlEIPx;q>;Dqf-kQ<>`Cnu>ew9to|GlP2Yg(+v72chBE-Ta6@&^mXSnB5{=Hbr_g@3zwf|3qFFV7#6S3!tU*))! z2hUqXpWt5=QMhz=7Z{28>!ll9FB!-M=orK-hAr&xLShis=8kduYS$(i-yOCEl+(Azy8eU~#H()i?Z_>B8c*1_Df~j?Ei3atd}Bcq3eqPW!#u(I zX&)Jnv&mK*XuftAP0BOhkjz{lEgVAwcmcodHS{i+?Ji zgTE`GB4@ht7raA}Xof4*5-9F`0zg=M#)s&v)h;mIHXdbqc4rm>duvD&Vt0KR9QYpR zHh;a^*5^{o*#@M6a#-*O-Hs&$_g0`jkhalTy*+wZ_@}tzX9=pc6(p6h>(X|dvXT4& z_^uTiJm%rvWDg|30(FpDB(X9BatMxRB!lfhX(`)t7jQ>`-yf3DZoE0R zD)~4=%#|w+r(eHJMRs9kIFK_gbH8f&!-L0$DV%zHu9s$rL0uAQO{GdHFeUVY{S@mG z`i8HH^rBEip0&DL9%Y0(4$Lb|!#;?5_IsO(X#C!$hV(rNsbF1aEKtD$3IG)J1%pDQf05|=HY8@Vz2f@mLSlN?JrA+)ni63a3~%T(;IWxGSZ;T0hMJVI=CRswdW=QFr}A|{3bCJ1pFp3)P-lMGlC5f2fhja<8$rg zun!-cZZ#XREhyr5Fr@hXVnJ*gMK{0;cmpTGlI~7A3rxx(iQg8wnf14Y{$Cvpf3{gW z7u;+AX)w;-_tR1!{NN$~&Cn6b_`TqMF?1fY;Q*#+i^7F$%q_X_A*s5P{a-5LHz2xphcn7Wck@>EQ1a> zPoWP@&fpx97SGn^`@G9G1qK#5Q^MT)4xv8;TeHpi7$_pfCBH29N51-sE?LShY0D-M zXkVE?0yCshL+mi`x+adl*hb>n_(rFTp+EwvTZr5i;GzuN!GfSnbfWkO)bf6@m*`Y* zd5-kdo$<9pPE4={u>a3kNBNl#lOT@YE*CLQ>16Aw*%>x;Vrwas zs(;Ph2MTPNT0ZMt>Mgv=HHDURVk5WWClu&Jqh84WeyxS?0bY!{(HC~#F-!yM|Ay@c zctm?X?2ZAC1yqE8tt}e~ak4y_FDx&AJBkD4Ef?Z4J)8LXIZjE8qQ za=<+Va=;RHPzzuF?ukLsFnqgf-&+%g&y4Khe;vMP(p3<}>jT#44AivmBD-IH?uh5l zngbSK8y$A_;eeL$ImQ0dLL)Nd#RDF$D5WSDbzd+1DKwGvv=^2Z2C21m0t;7||AovX z@aMlpY?nZuRPu8JYRu~E10W&Rkz(K0D3QQHU%&{^H zDOMrUQR+kLVuKW`HCf=PW&rB5fwH&COwVU!3Qd=ZVQN#eAwG9p`qU=Tk0C%}pR{)IL zhv@qIfgwQU3qWNxB0aVGi{B)DZuxqx7qyZj?ht|i9oHvbRcKealtJaN0JhIsB+fNiU<&IA~1tW^2|)dtOJsx(jm#mIxgl>*<+HC)e8j{rG@pj9->#z zbqT9KD?FFyQ4kN8B1?$xgCOGdjtp-*6oLjkSGFucEo5;^@j7l)q*onP^dev(#1flO zx{u3zjA|t>{8+;o={%Y~Uxtdn!sjAXhx)z7mg~)T zCdqThhsvSs$GBneD%N3M@^zRL8S`C=2;QpvxHBH%*6Ay+fVNkGtK@m)gMjyKCF1rl z-YP+F3UzaRnVevq-1LW<`6(*(a&kbB4dUcmL)gp5Wm^C*CC~#cng1y4Y_n+Ub$K88L=y)ffGf!sZw2 zjAxp_jFwQemv4c1rn%|dyMv-!_IFICE$v(BmCloT15Qz+qxMdT?+TkrI*?zRFisSr zGK-t7J3uSdXS-1*kx+w=n^B%QF@Z~yiE%DYu{FI0lp=fG2ZLK-o!4fEI>LpyG7orI zJ*9n|y#kE3dYLj(T))I#fRawOM~B(H9I19)nVJ4!B-KUQ8r#kH8dX;{jFZF7e0i*A zP%4)NB>(=3 zn>i`z-w55_i(ukk8FnrTNCFlIW>J*??x&-jh}=8=xdV&m$v1ksJtp(BmEO=CnM;3X zLO&J-TfI0HB{~i)oADXITpS^i;t>fH#sY`-)MwWsBf-`noqk*C*L(zjnke=I=79y^HMgSmI>mFt_dHLaC^QX4MP!=pe4Awrt6_1oCuyTNprBBN((*H9-1#^wA79TtR*0ccL z_F6o6J>MxLMTw}p^;&T#*P?+|*IiOor;g`z9FXe>rTuqQHCQmc@uDM-xXXcgQD+$@ zbp!nFbyhRQHuG=bqfZ|(n$iXL{C(Hm-)_v>{ynZakNe(u@9RS-DkL64`~ZKhYyJzN zcPH8ql6~P7D5us>0}Q79q@LkKa@-qJw4rt-G?AaA)Us1pfxM>zJX|a4TkB_)({6Ts zxf%~{PgK4qTt$1LZz^vrC$EmWzbSST62AfsU>o&9=sdDZ@lZf1wpO*rR_{$Ykx}qW zypB_O_3KT(pho#Vo&gxP?R`P~{XYhZJ~BqHF5h=4z_v!bwQD2QA)jYp$K48-BsP?U z^%Ru#-xnjB{tC>eNM&XMueL#}vJ{}nHZ4SBOG}QJm->lP%wU1BqdD^6 z`^GE)Gs!xb_7~lIXLbC zwx38y7brBb8-QK(0sN&2iLh3QMPDz%6Boo9Dl62RqtXV;(2)P#LGDuE;kBB> zyKSrWzn@j@y$u)DbcgAOK)h<#kde^FNgT-`|l<|DlkO#T1GVTD-pm_wY+?JU_2j8Mp?h#LBZT z@^A7IR%QnVs-P9wbM27taiA>SF9cK@F#n!rj*6-LeiOMe`qLRBq+*~ooAarF;Ein( zz*+S>(D0fd#6BGp&2)MLCZ#Pgb;Kql@#GgIZ>zPC*ET|_qgpMMYc!aCUvWC_iLhDb zpT-mj{Nps{i>_Zo!T6g9jV;u;`(+%IKu-x}euZUTQ~?@!8a7Y`V6s4Jpq#H)6NNy- zt}0wOMumx5kkT}4q@lCxIY8K=S4nbUi5)y}$B|D#(i1le@4_GGkOb!AEMH^55BczCSzt zi9ysUB4;;9n_h?9FFhE^mk>nM;-f>upO%tCB}QWb{I_3b>c#WTh9=X@nhU4>R)!%0 zzMJ7BYg7N-&^R=lLsE3^#`}A~!wD_^u997?{#_xX()?qNviT>Bh+-QXec*3?cg#M? zxw@iQ+dk$I2(cncvf(AS`omA)xqv42QULcpk(O;F0Ss-qiw)cthYP8Bl5< zu%goJE3*i;U211^cWNhXTwZ%Vf0WPc`Rvz4X~iFUW@n!u*En012TkZMoW#M#ByEp( zPLjIEd0eNvqRWx{aS;%Pl1&7bua_PY=0@E7Ge?h4(2?kI%~e^MB^A~3*VidMB7dsG zu#^_ogNPXpz1ET^bxza2ovHG-4V#fz3A|T`8vgmd#(Z z{`1QYQptEH&Vh@WE5&%#s+G57opC}fov$Xx`PJm~Rz4WghZ4<-Y1w1GekZ-z_ZI+q zD%lL0^IkIvBVh*<17(G9*!Ts5c=UL?U$=G=51U952}xlKgX(p z#Zy$nT}OWUDA&c{NXJlPsL42t)Q31i8N{$lpqyOepwgqE_oUS$?d1^FuZcID8WL!r zjxNFjG1BwvIz^Y*+jaClBz3Q=##s`1M68do@38D+-fDFwT42gT=xM%eEvoP;{o z$-;M9Gt7gfBS`93jv6d)yk`s0sAmrF#Esq?n{xTG6l;ht`jA4bY02hb^Nm}~1X62s zB&Kxw^)&B~0sSPp>C8H7fMe-f3*E%uT!1AkJl~poGARjGl&noob|goiTsRCx`^WJ& z{KLfu^oK`F@wAz1?Gui#lSvBv)V`h~f0A-vSmceV^qZYWStzTeCKXxu$?f^(@NXO= z)fRqqp8e=rwnCfO=FiKX&~K|aNYzb&si|Yk6ZDxn%IRNI^Fa59juXujpG>t)t~d&5 z1gNbXPu!xflh^gkeQ|NP?$Noc4+grJ4ZI&2-pZ?OI%bxVuO_AYME0>ZMaEs5}L4b6`SpH%Cdy)1udL$8!q-%p@!5ozH zHE-UPO6p$5iaT|r)e%u{OO_s=%l~*#hL>}eYmO)wu?;DQ1PIcKnKf9kA7Chiz_Nc`X5gZN;l3v_ z*ZByaZawm)CFG66neHjERBCfNoU3|e?Ujx-&%Ge2FgwbxntB8(>>8?WN1t__d&~A6 zXmZ91V;XERc&C@Hs*OJ<4Ya76@!Z)M=-2aJ$$uerVy!>jnbV+PaQwp&A}PMAYlTnq z#5z`@+gD!LnB#UUzINJ|fA->a$;hOge1|u_7np;YF-Ixo$tM=*$(^?;v+o#uVjVNk zeR)%~BwVM=Ip}tU8LQ2-#kc1#m1~cjPH6?gUVlEzr{@Q6QnqS7qd9nfl-%B8*qg=L zTlT^bt{CG38L2wlFolML{!0|L=S*e!6xct$4dG={!T!o0EIfZr=TMzfon}X^nMeK@ zJD+4hjT%eOAV)+mR*lp9v9tMaK2VVA34Ky^Jy&e_u@w|MdqJ`D5jkaKQrc4nxhxQ; zjw-2CY+GP_Lfv*C<4B-ka|5@6O8Lddnbc>mI*}xlvW(sn&-8wLJ<^x3fi(KURMN{z z`j&eXteE52HOZX4x?ZE9*Q0$u$O=t^d*<#++)T)ACC-bQXICKv4azy~JNr)2chj(^ zo~I`X)Je9#^I3zS1mrUzG|;xZcq;EXXe5@oX&wq22az!~Zv$dq?2tpG4LCGGK$BNc zc%)kJgWF7*kt~oW%sPw^mc@b6axQxI^+j$zCJpHqab{SphSwj3uyd(tE@%f^^n$#4 z%F2FA{QhS*ie@~+mv4$tJrvhyD1r5*P)qn}DYwRjmfW8F%j43f{gx+ihKud<(H2Gg z2@m13cMlOyBkZy&-|w{lfunktN-@PTiHG$b@tP^?af~rDEU@{{nL;ILUfGV6#`n=3 z=4@X*EowDT#7NRpBc^@s#DlanbGIp@U$PlUR{%jy;I!1SEbBodEIlqMw}^vTo9W?d zWxqtnG)_(~6pa~XS;oyvE3`c2F}X#RDXm%yPGCHA+{fxGVc>Ogw(aPOUTZvqp{AKi zMGySiAD+Tj}0`3fHsUV7Qld+yl zl_#G-URI%gl78aEC6YRxdcJ_`?2Oe?E_eYh480gFg@oLHjBFH_AwPfV1shjv z!h@Y_=wl{_*`!Sa1fTAg5+Nif<0B%|?0X8K53#_r8*lB|ob6u5B=-Ad&oX01OY;)+ zM$Sx-`r{pVCf2K_mhc_K1HU8&XHEzm-x`u?01Y-x);vF}{-;f}n%klE4+yKzg%PpO zmA+yki@u~>T)!DaBdT{!8?W{nA&7elM4it+-t(rCH&BpPxz>;MpsI8%Uza|a7_shjOX!`f z>H(07wSO+bXk2$hI!=9|ppDnkIXQJ)=Cr;1Ne6ao=XwU7V+2Kq)B9VM9`Tac?5Cm{ zy+kD*W*c@!GXhi$*J!fCN~>Qyx@}G8rKzaEDf}{y{8|Ak4DgXF!EcOWo*pKcJa@L6 zy;!YwR7;_r^q%DYBU>;h(|7JP;5@>!zM!FvxoqJ5AyTH&HPrvmA$DcvE#K@}GaRe9 zkT;Uo9ar@|$nCd%Bz&wBt)ntOI0XEa(Mh6`R9&;oJxV&Avyx5#%p-hVC{qvP-u9^dPKf1odPm zfpERRSF~xM+b1X7L0T!)EBvlt=<3m7T&wq15eM~tW?c0cU1ys-r}&qiWJi?FBf;_H zgDeYeZt0ioq6r=e7Q43z3|A2ceb~sg9E!O|zxw^9LR^K1+G(60r;KO27El>UwdzZ*p3E9g?c~DMTZYH&Yh$ zKIhBpW10hv)@NF2>j_j_=h)}(@WK8k<039^dY!8ruGN|5EC#1(V zaOb6Z8(U=O1;?O7d@`rOl;$z60J`&hgMNmGM=o8f**a>;72I*|p)dF3(6L}+ly`2c z%Gw;he36NS=Axj{yzSrOCZkDcRaa~G| z5BQi9x=v5Aq}a<$)M<@FClNl z@_x!BD-jx^fyeSzYJQaJ9|PO{eYptvXNOLd2IpU+|G?ls@8|yJ(gphFw+}(_Pg>_) zPa$|c;QIO>vg9ix zYN>vhG5^!-&DR44VR}5LKm?L8I#lzs@%6m*ll8erPZBuP@5g0PE!N1;dHzy54?;|p z8wyP2!ufaliTv3@pGaPi^-7GRc&ECV{^U;CHg$s(+fx&au6r@Zs@i1CvrWY|?$9fW zPgvZ1l@!J^>EU}9Pmg}cTV@9~Og}^5f?!MqQy z$>HNWf%43C1zD zubP?Ssr!VOhTvoVvCCbLPv_ysnxvA_m!+@$u3~@S^d%yWurfzozAE#1MG!$`Fx4|? z{1!wJd0y<8G@WViuFztXeUDz)fbynpTUAyg=&wA%4Fz9D*Kvl@uJneDJ4sEDe5t_f zH4;(>^}NtKku~{Oa`}Ax68y-H9aA~ktU~&TpplwLs`*O(bAwAmZp7mOY8P~myfuHI zrQK{hFEq;}PCBa}Iz~;>TbL_&WH9hYf2n~|6aaVJ)fvaRF%HSI9ky9yt>Q+L$A+Js z^mruEYpD7BsLIYay47Q9E z_L^-V#Aixg6M+B7J5lzQ?)C|r52v&zL;yUk6cU(;FBN;yI>OZu8;i2aorfD_hQ8K0 zZ)2aokz`&dts5TuC>Ez@81sgq^z}UkTvybA=`!P*m+0{Lp)A_k4m+5$ik1L=-o3cHzU_LNkzML*{3UU&88 zC3ghjJPBlpHofZC(Y$oc41ciLLZMAgaDsk-_WwBJOkT&a2joMqqwY6XpoX1TiLq^x zZ;2DpLL^Gdm}97wQ}fwbtx6p2)LrbgpRmQ*ent?=sv1>qgTmun+n|#bry9x&#W4!w z)Fn0d4r~}LoXRtPIsZ2CKg;*kj8iMQcN(CoJ6WdprzA<@v7%Jxxl`Pd;%gCp&W*dO0L z(D+~07_YnRA24cqKG9?Y5{sIDDe}|5Rm@6^OM(ApJ|p5C=r3o$M{MRp4Kh%6UT826Wmd zNrsZLf6U@up;4$B>Q3E+#>2f(R7)nSUOa*25nvo198bPv*Bi!m@%9@pY>U=}i!(qJ zwSP$Kk_uhtvpTDbK(GJ&IV_*y&8545#5XQ8Jor){ax#9>X+OdUd!UEwAcxsZCQza& z#V%8M#Zz+a_Y!DnSQR$=mb+UoMYMz-XsTP#sEO&EYGBK;yLschM6+q+00uG6hYiU? z_yoUThb6`ZN89*|&)_E*jR_!n>7ip>^d(A2EKvh0OST%-l`2!f;I;-N;BJ3LkLaWQ$kSi;#Am8-0lFN?i8QSSqTt-dgSq>?o$HICJLZC z{{Fcp1C$*Ty9VIy${zwcOMB~=0w7oY`DwZV$GN3-%&EMoNkOyg@;8@VQ6SW~frxrq zpi!pXIec?eBEbV#I5{WP(o+7M41Y0~hVy&oJ9{J&jN!N?wL->=zaPH}nkGS5;aWiM z;)1`jjU>GS*5TiN0?OCXePqzZ3GPh24_edo>bo zVc=QC9bid4e7Y4ENq=}hZol&PS&!T8eF^K5Cq( z_wM(P5f(f#jkuqQ4}RM|7`r99NGiq+FMxW)4W2uNEEHP#dp45nQmM<~nP; z+&?>DUp6CTxYhAf-Sp%}fd|>R9~KTiofrB;o&*;kgEw^6>M*{(7uH3QeHL8L_KuQJ zVf(mf9_=E)!T-)EF5e>K7k_5=wB0{`p2YSMl*7TnrAMeM(UE(SA z*Tlg|qZ5~x^R1{AIQ{2La$LCV#Zsb}eK^P9Xp2|$Cx*SFwQx0Bs;drgwK4*dHe0gc z@xLAxU0_qvE1~%*{O$S?x>P3L$a}xu10728h8H+war&8;I4eF$+s&b~*1>yc;$8Gg z&?cF|8TS(34@bEN8EyUdj#|Uj>V2QY(s_wnz@zuxUlsU0L~!XHIJ!U&#}r|-uHPA> z+dI)1z23d(4-9mV3E{+BrP48H{+ua(k%TUl>V5^uh=3coE9GJ{HK9STeTnIyu_y}+ zsIA2Ah#-<{Ves4v`BPNbxFq6O=nuL+xDSh+B=kHOLl~1E&Ze@irUS%aKC40T3^0|! zDtR7TE<(_nX$~5?%7sRs$;;JcdC_ST4w7ZGzb}O4eFcV)jDco+>#Ta=2NWMg3pr-D zr`@cN;MB1I^OuXdVI$bpF3E=!@K*#@!=r4cOdZ*K6cIdl6dN5TAQS?Xt5_zQuj|D_ zT8ts|ZK$qkp76JLMI=X*WyqH>29d3PC*&< z+7q^Mp08-ZoOKMH{Pnu%ov#(boj<>|?%s*wHO*8nGTD|K(#XP~;&aD^CEzUfp!RO4 z)h?XDR6}*v1hlB;60|dvIVL-@qESOnO6v~jW~nAig%8^~OzrpXg$FOA$;10I8(27` zbg8deZF661y|C`{?|zoCA74qt2oLa+XluQ!$rZXZx!}3N3p} zKZ9Q?*O0G(w|g>4=)Q(XI^<8*O)ckO%mRZAYZWYtDjCF9id`thOAux0BFv zBrki(p;4|#&kl4lv;Ce3ubFB;Y*n7JV*ZOZSq{u|8`w~**`;9esRxqpHbr%0sBoHoN%DuK)vWP>*FlS8+{9Q6D2eb2Z?`tr7OK+g zib_m7&juUTXOn!;g5jw+qOrH<>FChdiyScFPmE9+UNr)LQpoNZ}8BKuSy`Eu`B zlU~CTUz)x1TBim!odv9{6^8y>lrXbByMCJKa)N#_{7S*Bm`cc>1wc{-|KyT!-(n2{ ziZ0kmQ|TGmQa`MRs}`W*qH%BkA-4z496MlJx|~k>Y$f}{ugh4_KlA=`g~wL#oNxVK z3cZo$tkOpx-EI-xU@s@c)6W2oMo+PM&t2H0XXy-UjmdApuU@R;j-mRqYs4>-!HfI| z{`CC(yK?)V>IQpjN{NU2Ul2ZyI_La-oH$8^n)>vc7;GOPLll zJEWAGXjMa**{uR~lRSW3l`Q>?FY8r*wWnvapnduYC~YglPCiN2UuJ8lQDhPhi>sp_ zni#;=m3Myb#(>h|3mC5!)GC(qDjpPlBs$9NO{>>|4B7>8n|VVR%XworD4IHeo?Lfb z5KY#tG{y7n1|y%~=?(iu#siN0u{HC^l|}c6nj-0ieu~W}lC*iys@Q=($&D-`kX5_y zO(Xv5i!%7)v+~QUhloGFdq`Y@c>YMWHbee}PdKMeKlCBWns#JHKHTKcDE{`=mq>v)^PZJGLv7DzqxIt-?fP zLf;GRcKfJiG7O}0;uQkZ&xyXgCT$<~xr1TcG<+XORRUk{Rec{oA(EP-R#5k@GFYwP zuFTEA(q)}&O#zK!vq;q0S*ES=eLqN4R8$)wSqmqTE8Q%#|_u!NBifqIu>9? zH(J`Mt8GT5h=)yTbna7}cPi>^ZvOju6F z%n~`S4XlB2#@d#>B|x$o0^0;z&PTmL48F$f3e-opSrBI{fx&GDF(#2JjpaV&>YYXR)iaZAMjMKq=5%LM9?_M7~BHrVUOnG1V zx;>W@vfXjD`r1$DP+{d!R^hh>V*9!i{!;)3;l%R6O>jlD5fpJsO5+1pVcXi?duujjRde9C)cyLXhGw$ACrA-OpildOsgJ!s#hE0Y&3Ul2LY=dJux>*1T&^GX%k1a1YU0yN@ ztZNCO;co_kXn_srsC@}qOkRt0s&vmbH-|;_AMI6if2dIgVt<=Z7 zX5U(svo(!_sCnnFV-h){9?6=%F;x^I#Q6-a{H1~}&7W8o8=~K1a|fCIOxO50CLDm| zsEWEBjZ3-;411ufDGT_(e5M`js97*^xpdHn2xZZQz-i^h2%0_bLN@mGj;6@oAT8q9 zxrg+#8k9^y?hO%cOQ(j4T9r!?a#+jA9V20uA$N#MT{Q>5GMIyH-(G=E&Sw+V?Mm9F zCC|W1KpAPrhZs2ZU@6&Cb8RU4tVu>~}`7!4 zD7t_Yi7@RM<4@nC##hm_-T(@=8)To-q}^mWFdKs6PzTR6?qUS_K1>ApVLgQ5|`80!Zu-TjFYMDd42BfdaDFw2({IlzK{ z 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 c(SF$_I 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
<)E<3qr ze5^OQ$H#5v$7yX4T{xFh`_OhH>wW;S)?V2?Yl-=@%p@0;Csz~^pfRBSzXLRuma~HG zsGS_|>vC$+)khg~+xDtmp$H!%Y;rewA0K&tN5W6!vyg9aN$7w7v`25VkhZlbf@=@{#3ufM-suJc7FEl$pxj2D1LlT^EJIzkv-*60v|Hd&K1+MX*s5H?u-=5zd`QG5~ z3w=NN13T2s1tiGf$*WXAEHA8^&Ftwut>UKR|Gto)`+Qj1LbBp;W>poBW^}eR3U2kAUo%^pxP`G%F$t!5t&AHj0 zdgzIj{x=v$;Bg#*pX*PL-(W)FKJDHAHC=9COXp9x4-j_U9{|}U;NUE2p}3X4AT@&- z)Ag;;_q^mVL^!8QZVF}|rv1Fz|MT~)xULIaTOSm|1t=$k1HKG5&95MfzEifs#pY4F z-hbSOy4wjWceEhoBuX33h2E;A*uSHlRsh&^maqydp4syQ->k`~)mP)m2DN{C3xvQ9 zzn>U7!xn=6kubTwRYG7)Nw;BM_4!{c0n~}ox{xOz`26tXKTs|BblpjyWrhmeEk!;8Y^DZL zz5oBC|KGUbD5a0;Sg_Wm-ql4|6;!BGfN}`&C(mi|9nio5(Y~>O{oi+CRL5Tftz!L+ z@aKtHB@e)XBRV3Lv;qGbfhGdPbI?gCHFQ_ku0reWTh;F#2Oz83fSUbjU8YzAeP@UN z>~(+trTm3IVV{vKvAVHVARF}Zmb@J`W4|;Sf0+X2z5d|2Slu`z;GLZP?#nL*IUQ6L zyUd@&!Lmo%WTW$pe_Z2V@VhEY5$NjFn(xsMebFgSU+BP_gMcu(*tF#@5;zU^sC6bu zQ@^Zu8Au>`VxR}y`aqvs6@mI*hYLfkzNrFP6#M!iB@iR{qlw|Z9ZW={^J6e?u_qi2O&C5Z5*P%K!iUh1+H;`@iVdZ#$Sti>{3IR0e|sw4kF*Y7?UU1P^9$M44Yn6D#WcSPbsfXjq`HGyRRw^3 zx6GM%d|G0v8<}8`s75GQrPmJZA~TL9fu9b6Z^91B;-;6rO0SEZ1wqB1e9U>l%8*yC zcA(abs>~QtmkAw)yA)o(fH!L!OlkiRyp{iJ9Us#*5$mJamdh7qNi;v-N$P+AG;MA; zAZ0uEQ8f1Y+kzlxKj=^It#9B-%<{b3vR6Q? zGyW{fJVpH;&)ar@bouph?|hhqb?-rW3`qXWi!m<31FoEB{_Vv;zj-JU$=OV**1wg>2oH{&z-WJ+N&6;wvG6==qUQQn7hBNDw*0V$UCkhx?)!JAz=LAvF{32 z9*$bAGMYtu{*69$=kr6yqN;j>|46AOk(SVNlGi)F90|EAFJAs`n+n--VfWw44EH1$ zSDglL4j)8IW1~GWxXqC(c`*dHBhENK3cLx-$Jf8nsXN*S+Dos$6|q{ZObVMT8raY* z!wJ8>W7R#S#zDO5_9N&1DX~iM!P$2e%CV zAY6OuDh|f^n@o!+2ui3A`<-`r+fP3I>uy{VI4IZbLg-z?1t}t$2Ba8#5}rJJFQ83{+!KICx8`UXAH|0Ks1ax8DZ} z8ajFbkq`^W^^=fl_CR}PG6>B*Fb`%i&?MxqA+Y`2n!kL@Gn3>E{oHI6ADm@z(;ER{ zu#?r5f)MFVD{QtNpz)`pS*|(uc>}?PMdOH>0B)lIa=)9ny`Dd0*ss%ItN!K7({hA` ze-m+aMFE{gpuVy(3vS&yjVh|Fe^pdnb2DtPGccICFXOUBKAOOUj$9;6;DOK#gjC+* zMJYVo{}o>z(Qd%u>Brj3Q%@d&(atTqs%Y+Fd9S$GC#pB(e##j@WxLr@J~M^@86pceJM12Q}w$Goal0Q9p zS#%z*(90FMUvymn^PX`W`tSsm=4eY3=OAJA#yq!{T*s#7KWS6R%JwfnHFy9rxC6~B zTVQ)1P?bTG8?JKh1?(3TNqN6_=oc4`^a9T$c4w1lw1E^Gq~~kzw}A0KkKkb7s^BV65o zuM%S4eUWw$^c-(MettRdxS~`uYtJ-H!g~cq(svF2GVFExe8{FxpeZ@4$;!GEE(6zL z3#`{cjz!*3k4!Qe9wiq~OULH%>OlHv=Z|Nbw_FW=K27~UFzeMu&5k*6Km6G5?L(g; z=`9Pl#?;VJWg?}Ab1OHFjRIv>c(^`=p&Z?JSMy41kq$# z40@aPIg@{@IuJLruLFa>913PDp5yX^n?IxBxidRtG5DZs+1-2?AzYu)e&&iO2a>9b zPkNm2loIMinmaFTV5Er=3=^ohB3eS}xfG2_Fn{wj*K^`%cEd1aVLXImGy`7X@UQHx z!Sq)?+tjDZt0>%hIFz-X`IOzSB6I)f%{=z7qUr&dYo3$_6WNh0o}R0d+Ouk0VI<=m zN}#F2CH71F10ABFafRqr&IXXObZim@MtH<1hjH zv+FY`FfGmYy0pFDGU`si0xFK4FJZZJ6F19y+t%O$`{EIBZF!}Q8foGywL!bx zvON2wvFdyUA^l^pd27G>ee>QX9BjUXR`m+W`RA0Lk+DFv+M^4xOM*3u-a=KuoaBS3 zK-_tv0_n ziyN-39nGf5Ol%C|XJ7{CreLk7ir}Xr2%1N{K*BTi({oF+1 z*w&A8IXj~_=-yRy5EmF-{buUH?_Y?&vRUe>hGr``l(|%{OiZpH2ZLpcx^muX2X&d1 z!X(~;kgPR~Q5a??&H*p~Y!|n7bRc&aK^#=tGDsCk(|!Jywq)Evv~ukd>SO=wXD4pS zu0$ye_16xAIN{?_tCWTMmsfhrp0H7@{cI{F_Cn$t0gC=7uPspd<&d|Pz5fB?E+(A2 z#J-ZGcXq|2@?^j`-d5=NkP8@v6faq|6Gxt_Wa-F=wgZcs)_n-rOQxs;Y@iWYp)rJr z0mtZ9@d6Bn8F@#U-;wnv_DRIseJFm;ood*;DCM!9vana+LsCyH60ti$9u_fBl!_%S zTSrencILp8z4S_zWsvjSv<$Mw>y5GlVa#cmmWnlbjS!mjpp{wxo$L6=leka11$N#7 zXV;}3eb_N?i&w)w@vSP3Uy(~}nei66N?wLdLFh{y>)2k)FzGH#lpP&#HWIGH) z2jTz%&$6~slZDM1+|sqtO@Zw=juZa1#yUqZc^^VL-q+4KHi}#bm#80MLXd?2HFjuN zFon&ee@IT^ppN8{z;pM&x%*qpqEm8pH64+SR5D9FJNf|ij^w=PvOmmE?0+tk{f=5I z6zixU)y$i1zZDG>pSgt9ypB=^n)9{Ys^+-}2ZF*yyX01+qF3%&fe<7?kD14sfPomq zxw_?3)(h*W^%ORfed6lCv~ty1RX94I;a$O}U_Ido;4TX5;ScX8DJGP!i<+iA<5t`n(CNI+UoH73I zI)1ibzL?-6bKXiwU}?4QeaUgb6p!^iN@h*imb-!oE>+SYh9Gi4C?J7|rF3hs_qw5d zHM6~WjUIQP*ZkZ8*|V9Yce7^L*Hdf!>Q`A@%nA5@y>iHQ29pGsc5V&9J4HAgW+c?R zZICMwvF%jN;=**4nDU6h_}p`zlVgkL#RPCfIh?1rrFUL5^q&RYb05BAv?U!}PIQv6 zVZCz$C$C~Px%&NkSLt6*LgXVv{iF&Pl1#vk>kIxl*#|bwPs3oUbsLh9flmM0$xtC` zp9dhK(_4%TsVU?B!HM?LJxCBV>TXiGNMw04J+8Aow4)!-hKEHQT#!c_lo?HLRb+YK z+dEg+fvlMdy_L4}(wxTKzZvRQjEOGEqGx@cxbtNI+V5>d8DH!>V$9fU31p z*wYRv3`Z%7neRj%uOM%5q^NerR58!sw{f ziI9YHD=&7uy!n}n$(uMwh^kxbmwF=2xtC#crq2Wb zeWfEA%(|I9jeog#U$haiUs|U~?mi+fv>`amW4(!9 znWe&6ZG@EWM@l0{w6Pe~A3Fp8W%U_r`SBPE?TjpH~w=7jt=x73w{bdoS zWC&zw63t>&w;wwG`1Yt9`<8YkVkDG@CJa=IP&{n#uhA*61BMOlbkAO+-qJfkFDiOy z&p%zMcVn%szUX6RGFM$aKI6bKaUd>B4#e3zh?@W~qjjHRi#NnK!_!1TH-`8wsV^E; zTCanfHPrPd=C@eg;fB`;$8vtIf>{D{rLe1e;L#ldG%gJ#yOx?q+^Cu3lkZ8iw-dLM z(zud+uOA96I=Ij$#@y59ZGYRXk3AntZu!`BWC|r;+81@&$!n4!JP^h z*d*CHMXwd(6*E)*E(4fO_Nd*6DF*)*TCgj0GpF^{HF>_5-zU4Us{($3h#yo*9?gZ! z5<*H2c@-CskkQ&Ckb!eLPD(hcdtU9jIu4bW2bw3G_b#LCj%z)~5Sfw&x2)G#)UAiL zJnnsp$musPIPe^`!>jmutfL58Kloeks+%>JTuqJ>@Hw|m1y5blNB3b9u=W%_-1#Kz zVrp4NvJjYHd1Ey+21hB%3JU`7G&z%m0*p_1y2WvbNNU|VV2@uvqTBO)e&#+ARNe~z zR^HaA&z>*F+Gwe<-za1gJMdwOnd7jA7MO$hpyz3Yk?Tv64v`g*8EQ29bT9C8F2M5}O*lhX-q@o(FfHNyim4ik@k3-*Fh^FP7 zcglA+c8PRcbBB1m+*6QuH)bx`1x~rP!h_ZV{AU}6|I}@G7XNxCFZQ>R_S#xf?IjKA z%UvD}koIY9q-?V8P>y|h$5O88Wi@o)1>iD!1wtw0Gvb5bW+F;>crz={r6bv}`~W8abs^>CDxjK_WOz?N^mkOQMeOK zz7-jJ3tOB(l0BokDUt3R!Vhkd2>OdJlK@nPOy-T^%72zn(Pom^-7QMHWR}y?12`xL z3^6?5ZuNvZ%49ERL0-Bpnx#H*{4FlgG#E5PT{=yVpXS^d_olLE?3KgsHuC`uD`V}& z;H&3Xk%iko$DY0lGk`wil9+kKo+o-&^|0c%lSvFt&Mo2SJsVN4Ixy!qLd8AjSk-A| zFG~Cb6y2`S`|<4fkUqsOEu>wfsc*fb?KQvZFWC0jLVL{J2N3I)`gImJdZ@#o zY}>@!Zzop9DD_mmc)9kIWV0NMHzy9P?$a`@BTY{Z*H4%?uJ5~drG_9QeQQ|}#GOgj zZTOH+mA(JAJiOY&rSGpYxG^_Y{eDR)$Et{w9R&B9q{^R)*iD_@bM5V5$FI*nsvftu zPR9S$-Abo&DGu~4x$R%ov+xtPcFpd=DTNzUG3C%?PrTXnDm*C(gO?CI0%?t&-SL?Q zEluuzJ3{*I0)AbcAAkRl>D|*}Zf`;!PKoR~{jb$?80v=!L4Oe8P5ULwK6^l;vs{k8 z7xK57f%d--;!D2tBZFRWGY?-Ut9*fCxKn{Jo0Qouqwcj&#xK|JGxA!=sXCXvT6eqY z(xIo9N`i?nkEU6BbWw=i*FrH)N^KtaMiJg%&HkfZu>4@-QsLm}`+!Cgi*!z$g!Hkt zQX_Jk9$=tmuQ26c4tk2_t2JF;oDkjvBaBr8T_D@36ik-Hosa$r7_o<~$rUiIG@|eL znR685c@UJbxXCkqpM-?{L(Q(ptc__p9tfTS{=M$kG)Q1=$@ef7pGe{1-QKW- zoR?vvVroAY_A{%*k#Dla{)*Y|?# zsh^ER-IR#u*?&DzQb4ziXzu$OjFq4DJ6V|KT>qL@`*CE36-a$YOP6JNueTMO0GKBt zE@Zy{f-{>*GC1494FuS6%Qo2=hFPkWQ5J0h=~mM5roVz^RPzSuu;TlD~U>AdZwmT%q_dV2*@O_IJJMlbbQHE^Ekadm*G=78#II}s#M7kwb1HR#^TUOOm9|B z?%d8lojyQ2K9z^7)5yZ$WhKYy_=faUsPY>q9(cGqZptZ$nL;KH@FG}R=>Bg(qHQ%` z^DoJDt?oT=B?&WyRK!SVk0$Q=x2HmgVmWk$+OqhlsCUuA|*Wd9shdoCNEy zU@t%(V(sWk)PfX{z90* z!DY=F#-QGvvy-F=fjYFZFDBtIws&&CyCuY&8wDNgQLGCD+gL8Sv)Iw{@{@ysTN7L> zkP`uU*h|V&NfY>ExS!HvFI~&GvZI<}aAkH6o+}nTI>DJc)8+YwhY{t-Ajb7oP4H-l8 zyI%gHG(K#&P=wJM*kjd)uAjyv4<<- z8Qa7RUTipR{Z{a3<3&wP?|+cCSwIJ#8^v=+VJ@3bNI#v8gHW{2`<@|xvkc!$$qS0W z-k zEBtq3{yq00nkbsF7t8+3*SnntFzg#>0GVsOO3^ID&G+AJMbTh+2ayA%4JwT?+bPgs zbT#Vz%8dB-CotG6N;k6@RFAsmbSnMD4v^+U(^HJ5EfQb=ty+fiVW0WKu+powr$($x zk$D5UZ#%}3gH1A@P+FOA0M(k7*}T>=^;^P9eGbj|U110#Dd?O3{UetGhLcwCxg3HL ztPngKPjP^W>9B{o>(d6SS3vK0lfcR5!%#FF4A1O)rdD5=ZGGo8SlK>AcD`Emulr3v zUm4|Bp6o+lMkyImg6@UDs(=0Y{iA*a&Xb&(5n(ey@a=K1c>4fXF8mqf$CK&_=W#qh zVIKpv>5Cb42x!{C{JOvNecW=Cbi{`{G#&t6I9I@Ic{;CY@B%WIlsZd7`jiR}!anP} zAc$s;@Pa}p*xL}t4S|2mcHk&|z{O!r(AL@uZr*=1AIEgx2<_PdxV5s#3{-i5GMo%k z4uRfIi(C)EQ*rZ_?FUOm!OVEx%on@h;KU9{xCGOZ+jP*05Gi^Rg*REdE^Wkah{O&5 zC^q}V04$eQU=H4^^ltZq2-!Y3)kZhEWbawiM)ygsSg{mPphTqX9!GJju-yez9PC^8 z`>K&AqAP;TB(~F2sfV`et4j|=*kk2@!Uq0)|M}9aq=9dIYZ;@MLM|OgB6u~=7iWQ) z*DHZ|7{YnC9z$JVE^^`6eS608S8(Q!klQ8ESLSmNhzi?y2ePNk##29dx7uOTHo3)> zLwx}Tcf&TXo#F5^5q$t0D?d9qmxB_c&J)>Nd2kGmG1VjSm!DCc%Tu7$v92ll?T*e8 za1>Bn-Yiwf`cw|Ab4!-_a=B1iOMnm$*bBlb=ezr&PX?I_zy$K$;ynOh)NUgC>@WGb zG0WA-o;}gw#2$rle$P?*&4eFtuP8AOUda!tg5du$z;^3@Hyr&U^VUUQnaAmu3rx)AZKm49tglfdHPvwxA7y@xf zMz$vte(j&%|5Rfv|0#BR@h_zB$A)qQW$8Axf5iRkAM9}k?Bz@G1+l;5HoyPC?sd^K Z!n0g1i`=a;XUu~Cj14UeXnOl%{s+MPTgdAbg8>Bl058a27ZVsg)hz_DC2qLH;B}jAV5D=A?PDMJT z<9iR`j4}7l_n+a;#XG-ofb-Tq?_SSd@vOD?j!;#W#XviUhJb*8AulJTj(~tdfq;ON z3pxcHdEnSc2>e2HQJ0lK$b3yQiGWaC>ng45YVToTZD)=^%O$!07cD2d6~x7rmP?A3 zlN0Rd$ZBQ{wsZ#DyRbT#y8?%R^Y#!kYYS_0v;Av0**Upc*m+pEI5aufX}QFC_<$eW z0<8S}9Qym$gDuS+4j!lk@v^qF1JiQK@UXH2k77^)n_4@#LR_q9xg>zk@(!-%cEE4o zFz{1F1Nfl}{LjH|%)w*K#|Zo>?&xS|u48VZU=4g586GY^RxV!PFoS}erjjBprzG&V zowcnw@JrU*)D{B2MbgR{Vh6?syMitE--^%H5u(kj z<|e_Suk4}aEMsgU2Yf&HHE!n4F4ho-gO}%K<$^yBe!|t$(R}}?nYo*_DbOJNsEaAs z?%*)T{t*+1vzfW`{*`;Ta!J#&ivyR!|8Yqk^f&Oq0StWWJvpcXUC459yY)f8i`(j$ zOFLRAOY@ky@VQ$m>+ zu(LD7{p-stAa)0@cW{j(@aA7V9ezOLyFP^<)v-2n1z-fntpNMM*MlFIGq<+1I%t{q z@Ps}1@Y;hbU97-n5cmDt_YQsEkB7bK41oZT`;E}{PyF^Ld^Aa#+rgoH*o_D60Eqkl zzxPXLIDZ*Qf97#=?hqwwCmwxSSw4P!c{xcvh>PSQyxhQcR}OldmXp^Gcu@%p2rzsB zB)fVZAeqqJPj)dx!qD zvN0&jEpMEFT~Gw#2_i{tQ^)mPBkzYctWXv;5;g5Ui|#133@fSP~( zb$p#dTcPqCo$A%lmOi$_^o#p-{ER6OWE_<-)zDOz7FUv2mi=A1?)zb8)^5NR zdmh!{m4Dhb`&Ve%Zx!%LzG@iW3;)dy8{eUGcKk5L_q!N#aRfVj)$fNcHXHzd#0A$- z`mNU3f7~II{@W$We|$YQ{-cwqs=Bn4yrj71@s%qF`|%a5z|jfzN9N$`0sFh=;7_ZG ze-EnTX%sj(j&Fbfu&Tf3di-g5E2@YCeAyS7ehst#cDuj<@R$2tbNoy_#{pCIgRt*U z3snOM`i`+xIL2Wg2QXydqvj~2Dxof}EGc(<2P^OKHTE38PrUuj zk1q(P+>VNM(~wtERXo0A>X*8xfdMK{xsDpuC94}^CVo~1n*yl_wmbd zavmWKr>G(e6u%r}t$i2{9Sr5;Eaty}iu*mSEvck>Yz_0bIg{fo;=h1~`&|)hA7g|3 zO`v?7MSO%5oU)3BoV?8O74x@I)E7VO_}OHxgVexREZjFVC@>XrZzikh6=yq731_gW zEim)<-%iH+b><#?YMvd~#N195;$rQ(KUdby+yed#VDhZ1H86Wq@tf23)@Ek#$%PVN zJ8Mh$+*;@TIh$W@5I;En2RPv3J+?Ub5drrP4*rig;O0NJIQS7e_YV&Kk2v6EKejmdQQZFx z4$K|Q#Ni9M08YCD!~yQZ|7L}bUxNbpavop%?7&hr62NjM&Yrr!t?aBkhadG0R`=LD zCk0=I1Ag!RC%A^)`{ZHm`kUK;Pw=}A&-{85a6;*ay`&4#sah2%ZDu^4o~w@R+l?9oW^{ z?O?r@18?L<3y}Pgukh;^QH20&G6Ame!4fDuhe0E}CxJKR;5+zAhb`^**TG$Ic>Md- zPJTO-;P3uzli#`6-!!@3^Z$n?xqua-fMr&`IQ9R!XAZ93TgvC(UHRRLKR-kS*N=FX z|Ary;$A`ziMg5-j_}AU_E7-nB;;SWg4iWzMp`P~}Zja+IF>`dN=Ra)XaG=3^3671! zCXX%Z56js8747u57?Qsb^?TW_E3+;e>AaG^9|_Z{oeh(CXa8(`J<{^xI6xvMH~MVD$W09?)|4w z#e076LE-EH1i#GfJY+rodN1TVhhN}e6dX2rd{O_SBIKV5^*==>iI)f17vyWI?>~V0 zZ<+ir>mwY0)E{+z_J73#;pP3>1NjajN1%&2zV<-AYx4N&;v-LS{>>i9Pm$mJwy6Ef z+=WA}_}4@JyCx6Qf`?5WTgV@#tB;QI{+l8HQzSRPK>Wbt{_^<{e}6sXzcg{!0zkPw^(V_m!1gW17^?U5YQRX)PW<|djQ5<(dk?;E~<9`74Uv?h( z`A~o4na#f$^?MP^aYsFzQ#@RA;Q)eP6!FpN`foW!o^PvzkFQgI)cKvinMvO#AdWlg zIk*8AhyNS;=36iOuXpS@cn*tY4u%@%PgAVR^Rs7=_NuCnJ??n{bwj-S@g zIjr&cufqNRbp?b!TAA|)Rx{u@@c;G$w|}vk!TwI9$9`aO0dq0<{_}(p*Eh3HejdW; zaJ{1=8(4o7?8hFOeB9sQ^3Vx6Bv+1r$OQbWuS(&6B3%A2OicPIocwPq!@f%*{q?x# z0>Wv&uWONcxDT@XhokM-QklF*p1S%!F5L9LqRGFM8yrNB{{cXM*W{rifBeyW)I`ny z4l2KPFa86l1k~(T-oEWT`Iuhgm6)L}L^7x|iV1yqTDvzG9__sX7{(9Sg1atq*%PM|bIQ1O{|9aTNE5vxd zHUV7wq|Q&U#vI>~m*yU^&&$dFZ;{Wj7qA?6Ypm`+K>?k(Su z^Kkz_c|YX*L0tL0$^Q>P`CHfK=YjH3SB3wtkZ>H|ZVdS?M2^5&;DOi79tiNjM>(tl zI{xm$QI~E1&j6GAn?=$71Hk0{X6d(Yn>@Zj*^i2<_qUk;!+V(v{LWtHs?OH-U}w+6 zopDW^fxj%_+bhbO0qmT$g|)e}%i&32w~K$dpFOZyBK*$Z?Ah{%w_tR)vUWAsa0Ksd zmE!IUb_AaD^@cC|BL}|e%``9aq#GPJH|UYW}pE(J(iKIGFvTXb!eP`bN=k@*G>t{D>(3i%gRy ze1qSAAoF9$a0?t;$oz_T^-lK+C+Pv^LDdDHgZ(FIZs6+2r=tt+!d7Dk=TBcE* zGnLz#4&k^(n`@@B>@QruyM1@5Y;beEZ+pOHc2ywj4pDic_iN9@4+5(R;{tQ5>n*wF zO|gur>XhuJb*Fh;CYrtMKfOr`{?wggYGc3M0`a@0ug4q?!bYSLLk>s4p+J%ffPWae zfMjS?Zy7z+wARf*kCTmv7!UK`D(`+HnVTQD&1T@E=Vg!Fz1uB$RjOiQ2gT4&5;3=7 z_NGJsg9}&GvB}dPt38r=dXriP5xLOBnWDz5nbWi{THXBY3)s$XG}{ZpUiQ|L-9C-jyPn@)ZuXI@ z0DVh6fLUG?1DE`*B3d*prC^#x;XGm!>Q!}ZNk0X7+sA5SceY}Q1Dy+Q%(1Pr@F9&m zkPZ%-ZQ;Vq)_M}+x8A>2<=nLU(B-xnlhoSxa>=&DcUrs=JNtog?~FpIh)YQY+sOvp z*D?aP z2qXMfuG|`&=3vb|wP--I(bJ{m_oBYA;amfRb2-A8bIYz($caTy>x7(+-LBmcP%acWUuR<^r(6MQsL$_jYckd1|FYd{s z$e@1p>t1ZsuV1A;>-X{l9qc97?PifL@|f9r??CRY%8C4?Pg&;`5Z^8MeJb1Jm|;)P zA96|x7F32LP23uk7;Y_fUW^y03DFkwLk|&MdesP-z$Vg1TxY@GX=b8_-IX-7IyuI7 zcB_W%|EsO5$`+|YlF7wyDoN7{RF@hdN%NLQ0_!a#BN9v$u#l=m&+#!nmvHpw0b7J< z{u9648f>Oy%|lv@KkYYi=d@_A%Pr&HvllHA;V)y%xqP=54!|g3hO)nQ6rt*@WM!fYh1JW14j0y0?guGiP{8h18F&nj6*!`C@&s&Iph1R1ZVgs3 zHnbxw#xs_N5GniJQWM*X8MgFxShN+CY@B{^2)bUlfO1f1B`Xe*KZ69rry!k81Afr8 zBDP&x3lKnflus99Z2MHcmVGfE?RqDngx~YWbOhB6kn`;N2B7u)*n66%sbP(mY5W@J zUkLN9=RZg?Tj@EJy*(WB-N7-Gm*Ioz&S~EXw?JdGXw20;sH3@yTzs{(BilYHf#M!F zP^Cl<3(<&via5rn;epO}e~VCAJoQxcpyDt~spFyn|H-@O#QeBI3g)XCA)IL8|3C1n z-oA~LQavVcxfq?C9p!Rfr_`b?3(wOtGJYC?Z{JHaWaYP~nCN1|M7QRHH|G3z)3x=? z2|6P!*OT9k50BD0Gdsx^<;be9PJA#kI=Z zNQn4$E9GMI(S2f9IXfY!ynzGL2cc*kU|o zAtAn!9}5MgBwhm~bVy&-mB%klB{4Jf^x0%1ugS+3w8{Lp7HmGgNqQ!Ijc{Y`jq*(l`}Egbz4iqU^ow1s zFJHnEUXFh6F&a4~yxIlZ(dze_dTtX!psm^}vYD|{z?W~^rR=*oQ}E1bv~J@pD9g{f zCLHI}fcIR7=q1nbUu;^1SKD`mJr~V*z*Wc{S;nG~crilPUJ5TZP?wu0xDR;Ryt>W! zsS2G<6L^U6gY!U-N?z*3QxQrcWHo%^Z(#Z03jVC=T+fTN3tRKm=_XaHeAy-Z+X(AQ zGUN*iaCIzD-eDd-YEUj5J9x)u;dKe`-mouSKX0(FWz46rJPYbi`Z0=4^fRevL?M}7 zy`1~R3j}CnYWoEo3fMx93nl&fmB7bqyfK4o-9^!DQN|!!6jIk{UjGjd+_mE&}S8Ge;v6U%=sxOnu2Akvapx6o|i z==s)=&*eVAi{-ai=;xY6=zGuP=Wolc_PIn6&XqQ1oZuz%`k3@NVIlVOP%zdrhyLQp z53GelNG#b2Ztt!26{UjCc#cN$ecBC;_Sjkf(8aXWuA!nuWbBhuJoB=bTO@|edz#}) z17(=zbm+&mHWg88Cr#W}B%*$$HtkPvKIjCNJu}3b-@JcaWnY81_@p;s*BAJBGsD={ zM;^G_?`aOtC9Rhmdz$f8C;6g76#CZ0c`4wmv+)U1gJ7%|*g0VzYi5&{TWwKHMP(G?xTzC@MmFdpY z-8mbrpqm9-i%nCzvCg8qTQ0_P(u|h11UeZyAGTKqv&zoXieE0Pj#Yk@?;FZ0> zKLR?5INRsa+7hp0`{@yaH3q?B?i!%87z10Ms*Ul{KSX~Px2W9?i}mrL;<&C%_tXIdl>*rF+f(#nRmxEJnSrvBpny+zG7Cr0c&y$~%;e}R zsfIjh)>KAb^Hr{6IvjUSK1{h$i<|0jL%-(*-4T`?&#Z)-hpfIb>dnrg3J4_7u+RTxC2w;TwtMNWBsv-Zh!=##6ba((OA6MYXak3$ z#}W)$Z3gU_2&k<}9#@i;ut`@3{rx`!!{%vvX7NP~68>yuycA3l)ta*FMr$Z$YiKV>Ullel)Be`dRxtJMmO zoAhXYwL{xL34(libi8bJpl!Eoz-x*Tbh}k_w^X7*2bC+NB?8d!db<`o{k<3zepHZa zge;ozy!M|SaIU^UHTiUr>3PcT0$SRWRlsMA!c+*+=(MIoi?&W~%q`v1gtkA{giUj7 zu&v||1@j^`hPdwRvq0lEVWe)Vu+9EC2_D9$2#iLt*rz#Ah*ZQG3$#I<0PI<3G$z*ma2y%XMIE-8yg~Tx+=yIXQ zf{E`Fjtmrj>)vd%pCymlaWvk)4GpsjdzT^p2BtW6!dbfFE25q zH0M)a(F=Y5?av)beEphWB8iEQZy#wDIP@>qMW(=ZK4;kgR_>SG`Z~1P_R2;FF3R?) z{4S$(6)o!Z9w-KyUBYEaq}4HQKntta4DRl@`^qXlS5vj`tSWDFzQU8@)U^jUIlpsWMXk(pB~Xwj?v?unlO zdy6ztQKLv?=oq*G^w+0KgkB1=_=v#|p{qNwCAE_;Z_LRSd%V{^SI>6?BE2H-XM9yk zbhCKRfy=dg(#Nys&;L^5ZZ>#u8s^mO&0HEK&cQZMdTV~HA~r^HM&-+ffZ=afZT)pSu}t=+mU^(ky?ob3~! zdNXzEV`vrfq9fMlZZm2uBZ~G3M@R-agRsL;M?uly(YceU@iu`vQu0{{s5kLu<^?r% zmBM|8Lx|dy1!pu-w98?vr6CLUG=OU&seEXC` zio9i4p1TANN+8RHd!%RNUbR3VMtNb;@-8j*=1@*}h-gf>FE-Zj-S85VXvb9r9>m3k zdUBmh#jbB#E14GZ+LYTyXrWR9dXa5S{I#dS*zu(E#n4sS8YK_Gi&dyrpcw2kPRYfw zN{?hB-w{(4CR%K*Eo|sPpXj@^@O<_kMHZ0AOTEh=mKs6Vv`95ng>pTk7C`o1_l|X) zj2-Ef^BXn&An`hTYXtN2Q;oD|01(uT!2!@sd?!#VM6rI*(Mlzgo;`8BntbOWR@3l2 zDQ2sDP!}cUG^KNc=*|Kb=`(z!Cp0(%?1}Xc!oau_6LF8IXG)h||H2F@Ur!}Opmcp5 z&!>WpBew_vMMFv#Ld!3TccO#x(Zn4AANbSOQfrsXIzJN4r<+e`K`!V96hR}{BlZRT zsR2>Yq}u){P`wSE$CHtZAo=+xHSa@^%;Lz@GA*mhVdFMeyq;6~O@ggW<-zOYYb(*1 zw67Of`i)3l?mjkPQfNZokNZnK&f5y_`BUaIM4tIgC;iZIDAI8dS|#n0!>#C%Xm*6b zRnUtsZIDt{l?m_WeLnD2e%S(i%!G3yK85%Aosw6sN;S}ghhR%n;+ia-SmiZo8@^|o z`IbJz>D{@f_msM^D?^caS+a{xESghSE{#Bm%xA=5cREwjNXRCbdn)^Wh zUgS64qSNzfFV18#@NXy)W}P<(M_B*(DC${*cSXziBrg{QBFVKijX*@y{u-~kD*CEWF^ z%JLACcv#~BWg^Os<8#sF1J;RHovo4mCkX}9al(0feIzjf8zrZ|1@gQ9qZ zD*wU~3Od=)yo{_FeIFCkU@hp4{sP0E9(SwZ^fe}A)_pjCsiHJRAGAf4!WUsbGtH0ek1-38o6<;CxT*9;&vnRB(t~RN`6g8q{dnmm=5k>C2b&6|hfHnV+2&+L0&ZdlrdyMBBlo|suT>Ck5|N-ySR zFJW{$toXIil42R-TOc&`EhfGd%*@-$C|0+Ltdt<6=iNRspbVXsILBcEtx7$^FA2Me zU1@>wk#8PaJ3+n?zN(z4-`VH+;lX>!&c|a_D9j+0(m_y;Ayc4>Kw&_(gTfuw=d1iR zp!u*(bJ`jg)&7^e2|O_DYju&tX?)f#c|dISX^y)5dE_~sXDE1>!9&DXBVDNq2izORKDCL}Nck77DJ^V- z%=4^On}HCk61N$jmRcF%SxB&IIAn5ndvJI1O^7(E>G<+w+mujfNn98Zyw4TmWibc^ zc#mS+sNrfAdL;aeCMgl_8iYNlu}Hl8#@|WhfpOI;GJoYu zAarMX(v#z_51NJc$v@e zY(P0boOCscE)*mkCBmKWv3t?-spml`;Mw`^?ySN-hZ3o4BC5~Iz&<@oZ?6bEG1U_R z5v|e8Baoo4D)u@l2bHz&c&0_mR!Xp-BzqA+^=Tht$Hzf5I1~%JxR*}uM$Q)ik%{92 z-hgXBfNNce*=UZ4J80$;>{R$p(Swh}-{Ebt^mr?FeGadL#Bv;foBq}QN<-p7!(p`b zXh+z@Ng_k+weqB0P*)%p(Q<&o;D;cJXL|N5TQ)6>>^mcZ;gYBm!uh(v!_V+x&~@R` zR~!SYlWl1?o)B4J1afkyR3xF1ec0aTSwHfWO;O;Q$*Cv1fb`h7iVSyx z`J;iOdU`DTZXhdE04;NANl=LFO4MMl?4xOg5j1=&WGlYKby|L%3h~#FK_=#~{Dc=} zyOnNe(ZQz}``Ut9Y~~slH|Jo+5UNlDiX6SG8f2jAtKJj~@8aAgQr|vp=4247lf)+` z=@#Q%uS@+9$v5x>{kAu>^s!`jw5nlYROM8TLDM}e4T4)Mgd#Cf|nykoaUxasH!yFF@a@J1*xU5B#6!i7F0cxRULbt&o? zI)#Yf2SEeR-ogS&&5PaCY$-v3nNqJMc+b9#8u6{YWHCT9cVWQYXR|t$-F#G;-H!7l zE$Gq5JI+~7Z6oKBlJ+a9= z_-U?uleKg8Oj4Uup*$3cgtH=**5kGxS`MBIq6?SC>??E|fGWGy?o>}ow5*#k_+p4J zmJ;!9vL8D3bENos?0|)`c?IY2({nhy(!d~Nejl%W*KccOw%-6uO^TYdz3{v;qFKk- zH=onLl5Vr%Cbe&ioMb?a1h)G#Q|c4MD{|_r1Hb5p%}`tv&yHz((=q$3h7!fFHlW34 zeZc#qTswLaBJrwRYQvpSgoyOBjtz>hRzn~26jc!2B`!jH1(8zsZ^8@^OLTRgS=Vy$kZBy1IP5KMDBEa#ojX^NBaC>aZU(;5w>cqk=~ zj)HbUtM2*-18MUTVQbH_Z)kK71f?^TzwhkrW~Z~Q60U}(kvz+V%u}=^p<+e+>=SpY zGAvtywL9#pNZ_$}r<$qVMc##}Fa?|y>AS7q-BTvYamXm-{DYTSf&|;f9pl1p#3?l0 z#~BxA53*uJc{4g2pTa{JVr|-Pd3A{IYNTE_{UHAQjk0qzB$)O3;xVfig$3T|H@V#o zJAvniQj!e|kP}izS=k+P%+<4K7xr5cb7}XLU%H3ce0M8Gs%K%=TY5OV^M&4ge5}1X z=E(-};5>R1ksIA+&}=AF&?b95qUCiq;7yS_Rv>-?0^QE|4{@N&i^ff+^r%U?rEvq7 zCPGzXoU13UBn5Bg)5--%k%?Bm!Kc_RWvMwqc+JpGs3gH~ysPFCFIKiSdKA2Ha2`z1- z8OmY)`o6#h@)=~dJQO2Ay~oUJwGw!vRCRo%cms~2^V%`D*7$`ZA~}1QYp8mJa3<~f z2&v~?C93Gi2=n4Jk+J};srX$OJXB?=x?Fiq-SLi3BI#JjJIW z8V;!3GOZ9>n6gyBatRYwYmx)hRkrF>avqaXCNRE~Hd8X53?d0Mglu7l7reJg_p*qX zr%_`bSq6sJJquuXCC`nvmkcs`mb&ww38>cUzon+6| z3$Ln$@1DtOft*M-8mb5?La5_Ij(6=Sr%Zh_T#G#XnBu}iA(z0&4a(+Zk?W$M>WwV_ zZ3S=ixW<)Lq9wBHX}a}8o3>sT!9q2pNxJ@VQ`9aRc!P?~k4l5`bRI6?QM6u|VlKO> z#ge2rSC}wSaz{q*j;wsQ;v>^34R{*C}tkh5@ppd>f6f=>d|a4nx0WtyFwbF-jm9V)3FS75TFh1qy_^F#;W--j%)4*3=X z%uF6pDa~yZEa&D2PGS{vd1X>DF+!Xc+M~(?!#1l3O{tJ~?zcyY>kF7+s5pZfzzLUfjW`e>UqeT_(F@)pzlvt z31>?Yw5-#AedcDaPikY)fiekl_{TuK5Ur$xF9Pd_#&zIeuq!7VAn0Y!@n7WPf`6@25!G5YtckPbu%dJ5KlSS@yaz&dPrX$B_?L;sH#Hi z!zCl!HJ(ED=l8M^l}6+wyPA(IXJ;l(Qeol%u&Gygy8$1wx}?D{*E666Mq;iBLLxZD?sl{RQ&enAM+eIwpbos6;Vw*9%QYarT~7-{UV z7U1PIPU{g<1wAUS%cYe`aoIxMJ3Gn#!@asQ=TLo`a4Z`7qGK>XcV$N_BKXXNt6aqM zZd(Gemz_GLL{L*BKnvIN-aufquPVIegecEjVuKnTqf&Q%$wBArHEhE7fJF^8=0Q|X z2)hHCVCDZ9SZ#>w(4i8*9TH>{Mx!`~(`=e8bJNTVMe#nrnk>=HCx{)>SWIGczOn-4 zJv*m%Y>f5l`Qpo4)sW?!;+|Z2bE(c^{)77(d{rGPJiET>=hxb;X>{lk$IHpY&p%z2FJ3uHi)=M z9`k___S6nyzeabbm%~LwbIAXgt^06D8OQF)#VQ(7 zGN7D+?b`j7Op9A%)iRHvLQmXaO8hoKiHi=ev|T=9urdzd>G@QQ=;5;Hupr_Ffl6c8 zld6JRuKTMXa-Mt5EA-$cpg&&QS(zFV=lb}YQ`f7A1(eORR!`cKybB;YCv~ZZzfy{j zl3)uL`65W&qqF2JjgcB>Wu>){hxKJnyHtK8v+mq##gy7>>;kunmzMG%f1S(0u zz@<=Q!#rV1-T}!pGK1ws7>klDzGQpt^EyvZF5otZnxFf6j$&21SMLo5R{p$DNeSmN zi9TOEwCIJwY~~GPKwcX)056-m+L`120$}m2M}v{&1fb(YYPDM!$<(u&HR2qiGtw*D z$sCVU3 zF3}p;B*!^-ic)t;5kSadHY^q)qQ#2YaNOuLS3BLw2BB{Gf*TL9Gd@;Ngw*B>QH&#> zWv&rcSyL{&4>RJy5MmhQk#SJid0x6;Uj1joEVoSckng6YI#TtYMkLk> zxUTN@M(SJ@k;K*HvI#mJ!fgg7Kb(Zq2~kF^XO@st*85Krli`6c=2!)G4FhSY$CT?6 z@er#18LJUpg@D^@n;rvmnh*4DOo9VEksN_89Y^Mz!1(Atpqg(z|9}8y-E9$z^VuMv zR5v9v_tp90Gg&%eb_sEm9FJCV@_OT>Ju~OyrF)4b?!H{Q1|j7|&5o^n3J#A5M+&aK z3*wu+V|D^5Oh)>4O~ZZ; z1_dH6@diLfbZqwvapTh=Gu63Ij*62-2bD<4RdmzFzZ?*x7_Z=x$le)e^N&!x8;;G- z5Fk)Ua;mD*9>zZKgdzjsEPfErN7C_4oV&_toB;Q&v=TxA$3A9-&Q@G4hS_rYZtM(k zQ#C?gE{NZwmz3z6X0rhenn1EMix<_~s9P{Zk|?uw{=(G`T#C1rImTFN6tEMU-IBq< zcS%C;fDHXM!{3QM+CvfdNx6uW$#Iln^YIJRpr_Vp%xg;hb>^NWEsy(=nqJ*f@N=R9 zk;UrKLe@Hf!YHlTw5DgukRn!BM^R>gBD|j*9dhsN0FXL25@ss%GFy769Wn7hol19ds7_Ab;C8EXp8VTv~W zmXx1IX6Y74qN5XY10>Eq*Ux_z2O2(&5}3^(Tjlc*pjVvYRk@6{w^Hrx+984MY^!VX zDd=1MLb?bUIOQmeHh@}+)VmF+CB3{d%G;AjFwkIVi!w}*)oD<8_8#XWf`(Jbbtl8c z=5Mf9vnbu=lqS8>u6Ci67n2%HHbgIWY5~jJ%x^!$s(`3$XBc;XHN4JcSVQSOORU%86Yc?;N6Ge^ZN&qW{JB3t4gbM>_ zowP-93|mJlw+ugTPFIABo-hnjDzkc<{K^YCnO=yM_AX#ugm(%zV^V={i;B6Z5pY@} z0@fup1n7v)WMq7oQucv6%&b1T4XyVDUMRb5VeG~|1(6C|!_qappFD<6Emjqel2%;t z82a%M!r7DNf(gI0oH*^V_GXhd{MtwoO+02tM%d~(-i}T~7bU@SaTQmE28=z}z-^HtYYz2 z3@AJ)#w51b`BZ7Po~;Vv@Fkk4yN-N2zQs^S}#=EJu&A1ZV66xXE#(sJgw67u`2nm zEp!Tz;9LAuNF9j4>gk^9M%A_|WUq(D16EPz*euW=AR{`jQ;P8Kr#Q z(&}#WUarhV+mSP?m~tS~iOVQAPY30BNc7Zck$5jo5D~`|S`y6>l#WN!FiplG$G*a&Vq0-$Efu$GVnyK)Sj zejq1YDrmmH+;@||J>=CbTG)gyZk!yrO$pg=&bs=^>eAg|KBYM`$fH0;x_m48(o2tg zqC(Qxjbf?7?*S1S>P=!Jw3zG)St|?=)yt9`PejA0a$ia6EymYmvU}S4qSJ^9(F1jA znS=2~E+0M#@|)kB>KBT9UtiU&yUfM9WWepl+CFz4rfVpPUn$PqcQXjeo(_t)M~gnw zJNA%p01R!b6Q?XvAfmkc3>9#ehHjTOHEQ|UR|)}&PErK>Lo>8mVy&bPkr5Vw5b=b! zd-*mLV;M_iO>B^W6-RKWgBr=5&|NIqA%mV>wD!IukTzH)pujm#;DS2McDe1Pe$WRT ziH4E+2Yt_J1`y-!H1-j#*S5WQ4~AtUnE~PITo?;PpV#e+!6gn2e$!o=`3rWSJ& zL8_-<6;u~qP-jfdE#h6s>?S2vLOlt#&P=#Qgie4|`NKVhS9*fe5H>~{J?x0)gBG8p zd)f3B=kqa)7y9XjUSgrL!a$B+(JAIcf`RT9B|iPhhI#(pc{4*q+~kY5=#=cNBrJH% zI1mGKy01gsNtCbY^h(u$G3=hnWw?d&#<34=MmQpOn5>v`or>p7)d}fy2`(M*>0Xnn zvKGYI*+Um*aTCHzIgbwyl^&iXJAQ|mmoCQid4zNVEsWp=&mwW+k_bD$9Bv|p5zn;m82 zsH=P5;#1(<+pNJ;(Oko%<~*%TV%is*9fwcRG*EpjpY1vVqlsJGy`b5E8ZQV?xAdF@ zKbRr>b_fDvd=bMgP}kHRM!GFTVIF)M+(${KsgSD^fL+heea$;;Of{Bo5xqtW^{HJb z$DLe8vCv5+A36|XFAyif?czmUt^)3O>Ao%?#R#GU0y zl-YU-+(+a3)kj0cvNJLm?{c^<%+C<)-z5GHh!pWDMq%Q5%P@T;8fKm>)yhh?Zq+GF zxv@$=+)j)MutVFeUbfr^)0-^`!Ul63RO_hG;@(?MtF*v3nz{op7sHwj8lV?fL!{%N zj^^DIEnMach)vZy0DEXxiFy^zO2vm@oh6J|4rmU3?E2{;f*xso#(=R#U!@d+5!L{* ziX7BG27~7Q{hAc~R+W3)@`FypO7r3G&2A~>v4=$774hBp$iLt`LTu!LdtPI4%Y5hzN#ny(E|15N>m?pecvS0*3d`E)||CBVykuBQ1F z4t;El305DmIwU?S=r%ns7|=H^K#J-)z=S=32|%}GYH>W0KZzRsF6)i)8-?*Ab^k$Gp#CN(LgAiV}i~Q2dw)7D2YRK#Ye~$4{?$t| zo=mx8L~a!&E%U#n||3^EZ`gPko1Zt8ur6>w09s6DbxgHIEiugP$&Qv-E!g(YW~=;t1=ygRqFi5fN6!rPmXfM6Y} zCL^*Wavm+(hs%ai6^ekGMB<{j^tu)ZazLQC`Vn@#fpmB=T&v|xfPLEXZHT7aKtRBJ z3pTR5;oJT3z5nj^XPM0A$2d<>TsVA!(_13VxQe}3XVF%l-itso%bBC?yf9xXwp%fL zQJ_IPL+h<=fv?Yt#&Tdd>Q*3L>YKVcRzMUI&dPrVdO{Saa#J67c+Wr80}OuNS*HLb z6FevaiAesWkp%!1Z|`5pftnY%`UIxuW>3}sa@L|MkVq()#+`f=2IM7F1Fr8}iY3|C zAehUe*?1DK$(?F&Hk4&k0Q{8FwaDo>tDX)U%88m#;>VAGP}HfCAcUoP@F3!P+RiN0 z_w4fo>H(+2ZvCR-NuTN&25uQS5sUIh4d@g)cywemMk)R=U}#uLoOr-9kEP`TJhu>l zWcHctCN0bY1i(Rx!4z~6+cbMPP#T?A9@|7?HY(sTZUX*pq%?-Ij)YWABcn$TSR$}+ z8dqC}Vg(AhPwYMbcsGh*?S-$7#GJK@+wE8uJdDvaKCK?~Wi_x6NZai<^nAOdU zr@RF-WSFy$3YT0fNmR8GiQ0^i%Bv7g>dug?njoI9G9#cL7$bY6zp4aXCu>4Fb>;F~ zs7Tm+R=2AE*iG4GIx;(%#E`Cl6m}rJb=HjF0R@&{+sAk(*h%$*`S4x7lc(EW7Wy(r zu9$0uGHoSq8~c9#1@md7YL`V&n4pAlHF_Bk)^5=I_%G~?I9|*zF`3_?G(3Y_6;4T0 zJXqFiG`*lyzd0e{9B6!2Fp$2AqVfcK(k(}Xk9EY5cJ|Q#fML5?N*2A=3zWhcEi8xC ziwf=D1o+D{9~MY6W8c5DH|VLz{>2t3bR!V#)`B8L2)41OvCr|{=0To#8t1R65dIz! zi$ZE7x<|rqsIb|!iK*M#abHb~A zj|L^1OE_RF3KPSKBxg9P;{a0OR{5j+wUBW28Skicj_e!^C+XQhSz?Z?6&ac6my&11 z&sdYR%eZ2=%pu>Wey^!og_s|Vc|oofRmq5!95XABh$OB`CY|Krt-(NnI&qIvd-c-K zB-i>BSc{~{`?&EsDWCMRwci&C6G3~6+eKBurHnhFjGa-H^7?^bIxtH>ksMS@Ca+pW z$6mK()3`F1sI&sO-%}5&3{hR^pyV|d^Z-kJ|BNptioMfAM72}V>~5wQ`HQcZrgo!V zXcHphuD6IpF-WbUpbkp=SlWDUeOP|Gb`DO+mQzh%y8tI-sl`nEQ3g-;FiCeSUcb~W zS-VCz<(7dLib<-!j#=N&ck{FNyPWWCHd17O5h=r8@(!rRj?1C|X9fui72UZY7r8ed zNlV9TwsBL5V;9Hr>poNIPyKmr&{(CE-0LHyZ*qHlGlnu3e&YIlkMYZt=iJ^wR3OhF z@;G=Yc?;1k!TMA&dTFH^fRiVH2Y~U7?>4dL!mrW%5L&lI`y7Qy1^FZb7lsH<3(-Rb=7l6%MxN&QSUzghS zK8T4yOhRe|Htr|rk!Z>qfE6Z;pb)E{ zB3b7=rev!d0P;aum^8RHLZ8az_2Ch74#@9O9yL5-9Tdx(E#|ZB*Y{q1xm}cia zzGoT-^=q+dxpxw#wxJVe2~@^+PY3IsAUHds^c=cYNF>I~uPS;c85v=j7! zu?7wTAuTs=sfg$$#@32OHd5~p6YH&sdCjF?HGtr(kBxXfjYl%WVZL3UOeAu7Tv~K9 zcD$0Ul-7}xXm_Z$7nngs`m6<#41RfrJ|=rjM#O`WYWlVg@+&gR0^5e*K_P4j@~Sa> zJYJwc7u6Z&Eq&{KuGL#AQnXXMGXB;5umQ(h`6)RrnC({GHepJ{T?O-^DmGr1;m3iI z8g|L?tMji&ODo`M-gYvkiIHZu`>YAIr)F`>CI-eqI5)`a%!-IHOr4)MAc9{pH*vjOGDz|DZ2mC+ zyzV~ED1j7p^JF?{GowNxSFaik3_PFLU(RmduzB{*3hkvKzC46UqL;bn)}3?n^?e4o zFJRDl^N)u#KJY|kJOvbzRy^gjlNy2=hGCMr{=$DZQl3e9nW_e@-Q~&0OkhSqCg+FH zeqbJIpV&KPrpBxXr77kF>q_YIf=!e#x5b!Pt;~6*Ve2659+>$O0-6kULPRA?>mJIa z6}u>MHhl<;g~gG=J+~(1$!`_Hp2hFemada^u~17C5qDr?ZRy3G1&wl4^SbMkj z{_b~wkN5Zf_x`hv-sn z4lkc2(OXP7y3;)A3OU!oGhaQplltlaRes;ELC5@dZxNva!~EO%-_Q-##h#Ra!)xMw zPfGC(l)PkC3~yH{)~y6kJ`q(2xwq}$f&0GGYB@&(JG$1rWGl_M^hMmW$Hs_}`ShsJ zPCpoEAZ zS$P%kVAZLeOfPvG#3LUpef6>TO~hD``W}kB$X55(WX?arvgf9ELyT4c4RowjrX5RR z-05^S{I{LXPJTwjuSqU}Kc6EaZQspM=cKLVfTgT)uM&f_>aUXw!UX)^=TUFQr5yZ> z=<|x&P&|7u1=vDv3qXH;;_-?&7crY9Pwz_?(&o-Bh@?jKzY1)<`OHe%tb6U{Q3ZE_RGq-CNaqIO7^p!z13SJ zb^-r!!&i2*i>M@$-!=fk9|x55%lSz_rO|v{R|?RXmtSomeNEzh=y6{xaYTKPV0Eb> z>T}-G#Y&H>IAm&vqkbNwGjz9m#7NF|K0q77>_q6AdD09zqC3-() zwf>x=ObK%UHfK(m4`#WbXYz)ok+g;+%;9;IcDolnu28^3c~%e2sfw9u$q?P&75p1| zxY76ILWfLKcbn4B1>+EVQ?2ubi$lMkpY8c+TIsqj43tU0d}(GQwl4g@x~5>|tk2c~ z;yT7@%gEmf1Pyw(W0nO0t+?ECox-C#l{pmvHb@(Yhk$DF>{#*5@Y$SNloU7l{B_$>5FVnY>x>2z-Jw zLO@?9feDUiOuCJ^hF1zLpH_m6Nc-l>3ajTzQfttI4&X27in$S=;U0_%Sh4jr78?zf zUU*AIZ_P2{c3Vyy`d{@Hqz5QZQaRAFabLongVWYTEfU~Tvcy0q(qp9SvdGS25SQVd z_Oqx(%N_Iq{}~`p`#cnUwU8Er)BQ;l%;%7v#JLPg5d|0CoSq z5x{z*E`o|F5kW!S+4x;Qfgy!T2y>j_p@6GC?q6E0X*f5=k$TAe0!|HV|BVEX%y$3c zx6qR^idRMIJx!qW`=Qg+=EI@(n-0`9H|>g_cS1cuK;Pbua9u7y#*Y((eZA6E0MQm1 z)Mg*_iP&`w92$?VeKa9d2uM6UpQiFGlVWV0IJ9S|Zst|LLlDx_d+$>2{5kTi1gG|k z+HE3@$&1fIPu*zkbT=HN(Z>1)JaExbLT!&fG&UEvUS9`FgfKCD)}^T* z!mNomw)tIO6eAsW{H`+%)y~Ifne?%z1wY=WH-ySQ$~SnA8F2fnMVj zrk++jP1wK#ArEmJTTv6?S4ypu4=SN=&^cX)lhm_fvLHz6XUOuPd#;e0O4bB)7aY78 z{mmZ>edI#)thjpw3`X=<0&O{Vn~@B@)BCU4UBFF_GFAy5B|CNCo6>d%E&;~#Ai`t%(-R}G1u)2QZT#0ZGy&U%DmxAYmIww0At+SJ6U1z$4p(0Bv zN}jB+26$qcmrJkN?0&az17@H9t1gmdpGLabUAZ6 z6)M#JpjLp*e``7&!0|}cGlH4wy$m)|bTJLZGay~3*$f%bgOTiL_PYerx{8sJ|?MB)Hh z0nYgY1>r^q6cmlwSCw(%@pTP`>2>Ih4aq--S;a-6-2BP3n`cgb6p6T5`&AXq?l(;C zRx@i4R0TitPUn;39j~kr){xt{Y0h1C%Y;CIS@HEq zlPd{jP~)nr_;e*xkEm0{Yk?UG4^^rOqZkaO+)QoW6TM$#-@HQ$P-JFzQ8 zfQp4wtqg9vABz%`GQri`UboDHSH3i>IP}fYp-uAp%TW0g$*k(VV4hTh%|wsck_36O zg!TyfaC5W+{4=v&$~IQSHoo`ne9L0Okk_`y)Kq}AXWsICX^EZ#b6j6K>K3I@^W&Sx zN47_312=_j%V+BjE>^`ZU@r~U>q^<9dUo6q`{t+=^PQf4hXtRndLwu>`Gg9W?rzOJ zuCbt^9(-V4$1BiZ%yTU%AW*c-kCNJxxF*I`l>O%Yr=4~4x+I}$5N=WDZ;p&vaQQx~ z8xSc?px$mUcp}>Na9uF&v}L%JZ7NO--_v8w_mE2(PWSIG=?H!N;n{}6=Wpi?(nOsr z!~VW3v6=cvV(WGlL(m!AX_;lNMnNwxXx1;{PK8dm@=w<-QyyUXXL570sU-AcF4n(f zCs3F?HG-{l`*AH6Z&YOHZVC}-bYKY}_bC1ZWsGc!ZZuQ|Rw`sZ);Y^S0^I0XKE;7P zq<^`}i}TwL3W<%xDwdJ40Q~bkBJ*5dn8u+^yUyU@;0*Ov0^X?Y!kLSg#t`7r8<+K_ zFZ^@XQ9G@Ho|mEux#(9O3Sh2r;KqA^{m_BNz|1%3YhMz8et{NO{rI9LN|xvl*UDTRV!1F1^g~3*y;~Lup#%O9zNU zDOESmb3U&wxz(46^kMNC?znX~c2wfd&HmdzcJ4S_0TJlk%{hGl7<;_!Cdm#VI!@5|RElB<7tofjxh#n=9oZWA% z7Me+rxy>Em>N@1{iad<*T{XZFeJg8aN6bsLF43Gcc`D|d8Grh}>B&@iyz)*`>Sn7{ z@B-J(^hc}`gCdp8@tX+W1yFswC^T_A%n~t3pq3B4en}Sh=mUNI$fA-G{jYv~g${W7 zG8$M-LUz0RidUj$JOsj8`l{jf>uvtJ>;V<15!_ZvV`IX~ZyEH}y#YKF1PgXs7CSpTKydh<(u!Zm^ zY)-q@XiyJAOS4V;BF6)}8~0_&tP|c&)Ek6=F#5J(&KbXmLATbeQ?r?Os6e}_T;y2H z4(Gu2f6F-#u~A;DewV3nkHjh>U*^B3BT6D{&~y6wNVJ-Eo$tJlW)fqv{#vC}Vg4<9m?uvyX; zb~S7>o>nyP&e!VyU;o++RA_4XVFDfu-92~dj4t2?kse_WatR+grds^s(wsE~z3vq$ z&q7RByijBAg{!6}#H%fMTJBApHI1d{{~dpl29PL4{J{Q#%nUQOP47_S4ujF*Rb@gs z>w|1HpVcD*O-4m%59bK@Zs;i~^W6^{GClFXp(9i9U;h=%a7y!q$}>KJpFR00vEm+g zYy^<}2ay~xKYPtl&Mph;)juiK{-W?Q1(LO}{}sm-5M7;cBYy%8VKeUGoHJqjU#)3e zR6_Z0$eLiOL>#-sCI20Nn^S3mI@amQ`2&|+NASPn1b>cI__tJ68MPL-*hahctkh2i zZ*biU+tr1m-7fdTzW|PTm&Iy_{o^`?;{6?ed566VAtVwTyxi8zuu_SfsbUt z)Y>whN(z~6od5SY&H~S&M~HceT`^yeH=GYYc;q|HT3_I?9Qn& zfsWyRmmm4GXq8{=<^RB&_DXf-RPNIab8`D6S_t`P5B)EA=oISLGXPBEIE?%22jQ0_ zX@AWsj<(k^|HKNoPZ2n*LoioKopSSuqld1r+?V+K_pvQQ5}rm)Lrh<`n?B~Z2$*gc z#yp$rGk4s^U!y@QeLAqc@k1gDiiCtE1RsN$&kD_+6<1}&ef{KcbfIhLki#5b4tot~ zZd7E2^Ifk!PMVdi=s2U2N4w;NlQP(EkncQAlQo)|cRm+o&C^rxOr}-~?ss|9(|Vg3 zgHX?wk8c z(E%UPmlXhA-uRv1_`fp!{d1uC57vuEXCLe_DZZ7(ezUzg`b3Zno|Wd!{sE0QCIv4j zTj|VsU4_Ko+1&+2GuUHnPFitqiLaJ@;rchbfG{T3ex}-^Xl!7`ZOxsle|lz%0(VJb zi3o@rD^aRg(*!gg8|5$#BOa$eD_aeD1bv;;9MgaLLtJW)@eyqXi%%ov2@3MXSvTS= zT{%HzK?#q%NqM?3>>|}LPArXN#e9TO#p*??Bdf}Ri36*RxdR)V#g8_)WIs)BjCR|2 zhU>|DMzA+*?9xYK2$DH!e~XBjH;1v{O?v$@X$%j*=u!f*hK}pYqf5vmciHd`zCdf> zH`u1l(iw{W4-|TW2f6o2DT8q8ja-7+sf@SzsXaa`6M#(Mr9P|t#Phd_>+XsYmnv!fzr7y_zwOr1nzoaUya!gDALRTj2_O3Tq%88@M)_N9C;diS zr{=3olAZ?Ff=Z}&4hNPvyrNIXHE{F5dO}=fn-zQLQ9K%Sq0D2m$3(c~iO-YTU$N~| zc>NPM;rng2+O7IQxOG^1T$0eqLo#RrJZ6kEc663wwA*A( z>WPZyfBNIC{Qlid4TgnA;+olqQ5tUt5zw=8;gR9NBguTsg@t(GnGx(3uAXz&A`%yK zIBG6Z6`hkB;IHpTY z#d8oA`=O4rFARC)9yQO;LrE5RhEhMEb?7xvlnr`+k%;*Cu z>Fn+kKcV43`p_07C1I0ZpVa~WjWK~I9wWV@JxL8uG`PlJo-+z^dVCCBb3C7RKzokq z$f?H;p+=8;0&VzLA3lmvI@^$|bhAx+_i$i|%w8YrQsbtKw;dxy^ppt-Kn6{te-=!( zqib=CPHV0S`~DAFA4gw)|H63@h}JZ*I(}Y}KuA=X;FxCFF}UF#J}6%d7T*FD%IxX8 zA$G|S)zJuiEC2H!E2urjR_{pIxj3Q3W5=ms@4|+^zL80kL}PFZBtJFFamm6n)d{9r zFMCdX=gx2*72)-9`N3V|G9S??HW&Bj89+f zs13RL=I6|#-A7B3`xHG>u76i2pPTseatrh-?j8;-@tdvg6Q{x>lU_D+a#;^B(I7F+ z)CSQ8j0B?C==+L8_x~c4f;!Vb+brXW{R=l5g7ZUX^?EDgwm;4~t2;g%lOdRZg3FZN zlqfqKGTiVtA)!Y8jR#G{R{zr<)U3Oz3YR@p2o|bA6!}h83ho>A)w@qnr%~`oVN~pw zhE#awf6~i;Ty9g(eMQp-LId*tT>&gf%|f2(MVZ87$n`iFaZ^4G9{C?{?H??lkNx(g zW)@7I;5oT4kQv$s;uBnWE+E?V4#4o*a1>3qxWMmw8erzDvCw}VYE5Q^0lV1Mga?9%PT4h+G-G;!y2%D07n;(@2 zEzVFiK#yRkZt{l$rF%FBKDDd<>ZAOh{KK0^_AlH9)$j(NSF`T7ZBVJ#ZP9o#wLv(9 z3QNT7lz5=(*)R?(RC5z2+}JL0*ZikHzH-RyFfL;V)a78IO<1mDHt&NOtbqTDSjnFI zTyKzwzW7*2gOR(!tv=iT|uGTd2wEhx&KKe7gpHcX~zb- zQ7jI(-C68aW7^SIm|4g4*p2Tv4&GX!LwK)0CRxqJ;WrR!OL`t8knqoJv?WIulI#mA z3)q_8uA>e926t0$k*z8-sYUC^!4^b^X_fFg6No0Jl4ocUh8t!5R2Vos7bljgO$*^f zGKcf^2HWvaJuUQVap0rQhio+&(oJ~#&KUtaxG0p#S6R`lWp&Tofo9pYK{x3hTmYxg z)3Hw_@R(KS>d${2Wr5n}S9ztBR=-4M33?k8U&% z3*!kTmJX2UUH)f&bqv9rEL^zi+l9irGH%g>Ql-of@|rWDXSLLq_C(S+QB>aT#Gyb? zRNd>+cdM)0$SX&$6)s_M9cka>A54~S4FP@+d99~As(ea6Hq z$O;$l>2Um6$Fy}alY={^>8Lc8<>gTh@SN~u5}i;$4dqQGqgcIEoP39^sY&&?>T~R9dDpYa1pfIQAwgq5hHK3Mxi6pZZ9Mf=CfsHlm z)sUxt3sjeqs&~j~2ZdZ{N*?SxArDb@b+#P*Mf*SO^WJ;2Qx31CqdK#?FN#lo<+x?t zVA~r|P$|T&s)suV)n+yK$$a?>t?_rpd5ZxT)ddy#E@03?=w36fKRPQ1;-@mi#QO^Y zhs1}M3OWEg7%eWfi9uhn^$Qyiil#!!GcPX1B;Q$@)O{~rC%hli<?lQ0EA&vn50*%Z&|zr54`y}^o3FhQw!K@ip7&O@Cz6d@a> zsY{s#s?>3WDqGNKs<*g^kC-PZ4e%+sj#qQaRBV* zaAUrDA61G@M|f}Nj>&uks>+Z|{Z}@<9pV4DyA226^31=EDc*G$_b)RpyRigZm@n_B zR`Y^FigMU$5C~3F049T=0ji6dIe_kqeNnT$Ig@!gLEKqXI$aYLS(;)$H`I3>x|Y~WT(ppG-I1V@D^JFCm@u#z*QBDZ984H>9-qHu_P zxKy5|6H%~ammxLCUf_f5L?8%*p6j;+#5`fQtU!d+plaA*82nc$Zl^7bJSC7a6V(wo zO7@!X*)WhdY9dVYv0wr240|8wBx1UmNEzr11wp~<5+-r`m;A~D9PSP6cBz#8ANDtr z2M70M2nkM=T-3j6oRP4A&~)%fwGPrB&#wOhq+KuGLlFug!C#$%^VR}}ch#|NxM4bH zfbO}g@W#hGc$}3-Mf&ZeouQDc9baz{M#%=vk%s?K6aF{a&o32VL6R-dDvfZJkAq#* z20ov7tFFu_y<5dycipa*J7p||Uv=)%Dy}^oNhfHSjnK=2F=ZHEO`Kaf_m^#=JOZ+m za{WE?{weKmN#r5eipj50cYEH+_kIo?DxxxTGm}Xy!ZT%Py!O{lQhJwzY5B+^`8REb zL$yMS{Qu*`f7?jNmo)JGr419k5n;h+i*4cj+pR}a!vBuP*0hK_7slUTrX%O+=>L>f zEC3>o0~b>o|N7e6T;%=nn16Zy@LI!r@!G}AhuNt&4y`IvC`D@`0crGO{gUAQjLt8r zVc(hsnnLft9=CUwd}Xi`DWRCLg~O{2#6Nv9*=h)JKUzJ5OlGQvQ`?olB)b+dBTEPV z`g>4WOzwZ+)tpYj#A;N%hD%mt!VDUpRLkVUZ528B&e8 zQL*o{?@Q(^(BQ896scJyd%yvamkB|%fd2Qq#nTsT3DoJ)`}Cn1z{jkbQ`D~L_UeUX zcXx&cH{tJmJt(|IGM;rXz4t!g;cjZt+X3o_cokOz3eWs~={(6dZeB~DK8WF4_r#BWwZ$& zgjn#wKpCpmwB66g%GLT23TN!A`hOhOs5kO5lEZEbzF)`DHSbIk0g+d=Y`5pRwoD> z(7yW;UV0yU@Zinv6VI#uzRuDIyRWuc%E{A?7|K&9TV-B#j(EkMqr!>t1QG}<Mw+Nx?Y$gZ@Ayd-=mEjH0BKkHpJzPu}{w5@F+YBbx%>-8O%2;ncW9YA1`wHcj`;fIDHtPCBW7awdw6JTNyK?P}>a9Z3!^Hr^6QM zbh`l*HpBU|uKb92v)n^Qt(zhQhzZuHgxVift`b7cR%p|^dkRC*7dBv$ z`gP0Rh509weiH9^b_kEEZojwsiH93$ILYs1LydwO^E-=r@J2!LzXXW5z(6*zR?Fpp zyPFid0$9CF1j#VO;MQZ}Z`nqXd_?9#fEz-XBDOjjQLNwwRKFQW=hal%kNEKruZ@&y zYlki^9j$ZIr73iz70wfB!zMr^?s_TtQa`QR_m~@2`fsHV#rw~u`Wgq$ZNqxThuFy3 zB?wwT3t639OpQ=!zcvo6tcf4$3TNk-fqc4^0~o5AN-$SszEH~io}Bzr*!8kvTJQDO zJvwzPGS|dOzeB|^w*xo=pBoTDPGY3>^twAsY;% zTm`PrGR2;5KrG3>uAo{%U*eN0Rb0{B0JuclugpvNz+VVj<u%#vnqSYfjQmHeHJf ztwvFK6gJPm;P`oplMNJ1!j~ShN*HdFCFxN$(Gt5}W0$dxy_gp%#Nc^G*-4jf*UFY+ z5$UG4OZ_WjvM=4GAv-!qb9%W@PXN7>TFrA-qY4nf)ZyDh^whD;`1R47Jb-|Bw%7IZ zWo0K5p1pm9UE=(q+_LYCM_xL?tebLC3EYAkALGZX*QYh02R3CX@N@^vaY;gG`KSC= zAVlRk@7}2 zfbEF7VQ)M7S>HD2H+Gp*yabS=G+J-I(tJNl5^AFQ_0;ZRshY!)7(Zt4DtWkPRsWJ* zcS<`G4;k;K_^oiiqoX1RHK%wZHhSOq@khUnOaWU4Pyj?1FygWr713?E&)nV>|@}SRfw4^W>l$^5^jGbE(S2|i$QKv zbvDBJt@=(j^F8Ztd=?Qq0sqkN|L|q^)=0f4b{B7CwUhp{*m3e9>;{Wf{*;GZdrS@t zmD@kQ4vj2)@!?>xv=9cUk0rK4hTHegv3V_53}ryDbp8{*`nazuFPnB1?KhEt&{?O- zuYvrXpj3^1Pz59)ooLDI(`HwJ*BW{Sy|%0LO#Eoa&#%L!GXzE%<;VW#xMi_-7uw_( z4Z_UJfos6|uui|E+k1u^KSOgSvI`&S0;8Jz3R-;6vDw#Ohb&DO5-(28 z-B)}!@6YTI5G&?v^)5?IMmgX)T*w>G8;m?xWpnc1GxjRYgYD7E(SP-l7vl-5MLLeOx6;|#t#T`ay-}jhO~Q6*?*Nm+=|U@1jAa*fk4$r*c91B zU1kOiwwHiWJ=3u2j^$>-1AQvhqsi&3DSM$INQe`Fyza}$cns0#YPtC}n(3hw#y$|@*W-P$(s<$EI z0bz#b>`Ff*!cL7m!87H`D^T5a675j9^mIMsuP(O+K0548wA0GLFG}^h-4?=7+{`|3F`$wtN%7u2N z;@Jajmu22+T)v>?FJfT-j7DWk_p?(N8r0Wc7sr5yn;OpdScGIzonA@d4uh|6tW+ z(Mr3g_7Vv6@%m_wSwauZpP_*b$L@Ldc^qrFGsol`+E)`{^lFvAZtX1|XRs&8<-&y^ z$VS*a6ULazq<0Ru4pq%9!`K=1Be#dW$B`b24YFl<_G1&FY|=%`XsL8@u!?K0W%sDI z1x!?bd`!qCeCM_Cjn#Sl4f^0r1K99iH3;JY;^VHdq8=!e&gVm-&T8RjTa^2e->#8< zLv}Bo$Dpr#wNbp7N5%dF1mtBoz`jCGb>idF{mRUGsSc^2=3pI?&=|=NKD(z@ONCs= zb9hJpCG@Ga-&Hqul@WwbF7M1MGM-3g4~2FEMSG*Kh;vt};cMd8&|PGyVdOqLi7>xg z3cg32J@b}Wt$1lqU*$8~M7A=K57udqCXu4zZ+nhK>1ab}Y#_TbpS1wSQWYW8rQ;r9 zL);Z!-&+H~?ZFpG}aql=&j0 zVKNS|+{XC3%Radhke~}qh)Ahy@6-s9Q>(yo-1@uYUhA=QYKaatKnQhA#DDbF$XuN4 z2PFXvxQ+f+&>TAsjT5>3Qz$h%pb`=zwT`vyFSQ>>M(vDT7c3j4?yB+HJ{`0y5QJy? zow5*bcd2>I$Wo)F73TMyhTV_~hl+=I$1}u4rxt2i673-2usK12m<&RNL%{&29$I_U z05($Q9Z%={?8^-xLo33G(MiUMp>NOLt0murIW~kPIX!L1cVCA7>!vmN?Rq9-xu2FKh382BO;Vdg@`7=l>OWz{!} z($WOTIn4=j#UOe?ZB~zkFg+OSr~dG;g6F+Z*LByq31KhUE0=K#P@Ni?keye=6dc|Y z96Dq-TYZ$?{EOg_AcA8_au~^vbs?~6P`o0}Fq&)4p{v5x7738L)^lK(Rwh^jtD4QF zj&0!%q(b2W$?!XFj3PGKdJs>z^xMlL6ZFy_3iqbBo|^yhQ3r&{xJ$ec*hVb$5waTr zI>qvl`%In49D<&1)g|bd;rpnZAZ|d$AS6=-`qp`Ff7T+&tsHm`b=N}(~jSqFxt+vsan)7t|Q@3hxE4gcHehXjvC=_ zvVD;tF4BTXM9~TT@7bUc$~3K0cG?^Ek|@kFhzQ-wYd8J72qFJvQB4o;JtRSqD3Slz z>$n}hrFx{e^TH6OImX^JbZV2;(+ppLib^^VeiWL=BXti@*&eiNBoxv=eK8D?F5p?g zP_?4KD#`{lC((0`kn`#YH==~gzKYmhM)KXlLw6k)!H>$KH@qz=iSbK^p^Ac;WWqg( z>XV3j@<}_@W9f@LGM}vqIJv|q)DeFKo)&IFaZbSVUS7c5I>U{pR6MhIeaJi^B#%-p zdl}e)$zVp|b_qD2-BiU$KcE21{fo$qFR|Zm4=tuBMITeM&aEo>e()DW6~r`BZ#u)q zP65c;%w5;T0dh`U^?6prNPvpCPDrC1EfL+_g^o+2&JZ*PD~5?KLg}vlbe6I1zSw6Y z36qj8oOaQ_@2Vnnl}w}*5d=fY#b9&F)+@`-73p^X+uQX`ouJ`M;SHTi#t~vsKqxzd z!sj)RG)sVTy;EKg*qT^2a2X-;ccUpMY74=fS`11V_oBSfUR95c%;u;%oesb1;u_Tx{@m z!ri$CVv~7q7UJ`HuhdOz=ji<^U~4FWL00M%=XsF669bm>gzL*Qtn1Gdf`)pCR!nJd z=OB}zv0}?G#ZmQAiXL<@B{m4{D$iQ8 z9qk<~cxxYFx920u)E+^!_j5MmC-K*3FWsBH(z5ynsG=GCW>L5#EccL-q#igvStOz1 z6m8R#E{E{Ukpwu@IG%fDLgTn0>MlMJsVb<3uEF~X>=>UK==%`Kd-K}b9`Ut=1+U~` zB%hq_fK$s6gZz~|P8{^eAT*0zRPxM8Hr1=&?>IMz3+Lga*=sOvyw9o76W^f<_sI@; z;8~Z93Z#tno`A%7+I=#nG#~(((Kow-JBKuuNC~f@>%OytXx|`7GP$KJJZH_XT{NKs zf@j`yi1OfFPylP3?+o3iqV6aU9`tKDbT&ih{a?A4D?7QDgC;2#_l0kZ)%^#qfc&j$ zTff0LVxl-3shJD7*EFPOLNTaNRlFVy%2==Vk>&eN;}ZgucV?=tcf9ug&MGi&C{)uRz)GLBX%A$!E$#7+oppJJrdA3xF`$`9u+lD-MShb(S6xRyw@h7 zr0oi>WwDM1QDXabE~N|j>R}IhKd7~NDOzU+6j@P)Hr@fzYE&Qn1~K5UhGp7GH0=mi zhY-Wm=XBgv_}?o)lYZhQn*;?oZT{5$J&VU@ZR7G*Ab^`Rb;#g+c=@?k*HE}@ScK5= z^@U&Gw4rXACNEF7ChYN>kNfi}v~#bm*Sfwdr0ldw*$XW68A24-E1LMSG|zZx=`aFC zD(yQyGBYtgyhTtmPDn#_ALRcEPUsk$&F!P{v!|q&F*QZ0G|GisT@FoN6Ou63+I=StM0Bk{uw! z;3R}seEAxD^N+>pfj*|kU^4TD{PW{+c?&goujE!ti?Pbya3@Jqex3RA60NLpE93#T zdV9aAWn70rBF?OYVqZ)nv?_6t6yB=__MnxToYJp>o`ZV0r-X#KV=a=KZF-L_v}B*$ z)=`7EEQd^|fLi=$0Ce`xxfD)KMP<fBL-m;zxf!v|fA`fwSHxad2vz)#( zcKY6xULFIx^rJE!(q^(1Tk<&g1rN@RKqJ!p*`x^BEZRs%{j(*DxT%7Prj2(f8s-+V zpy=W(eV^1aS>!3+jsQ{e9QS6gG^T%iT)-c8Zda<14GWY>M9s+OFdlAfIN9=A<>WgW z6)F$JE{c4kp?Y$33EThSBfDa{+>=#a){N@| zGCiGTU3T0ywnO_u)98!sw}nydnbkR0D|*W;Nfl&So8D?!>B~OR3u_a2bI$S--{yD# z6-Phlx|zt{lFHPRXfvV@G@d_`{QIGtJ0lLg%;AQL`R9i2&X0K~kBLclz8X_elYB{V z0?qU`%i=v^FBirVTih4DZCA^{78<^47W%L<>y=~p=|E$WKg&3sfs@*{NtZ?2{nv^k zvB%b)Z7I>U=L#!Ee`7=T3{8Y5d;9ex?^7O#{QYAW>$p{Yms7OKNQ0P_rnQ~~tMd<$ z@WUaVx|kMz=?xMZWso&M(X}rwu-8W^LnVU9G^avVEf#Tfc*!yuLWNY}+j4joZ?>a1 z#%h{?OFa*t4|7jDNGoRLCi!Ag{#dKAJvAolvdeo9czi)yebZOb4P=l+yDD3g^k+Cw|am-RX zOAE8sb-&F4Z)X=|q!LkrJz1`5rUFgGi7^4@?F65_K}==&lk3Hq%K&_=rbOqrQ<;Lya$gUKb`>07s!cLu|ObY`)%yu5+oYstlXtT}r03Nmx5 zGU+S~1QuH*zQ&+OtTy!Na9eylB1@$lMM-(p7)>M<&YEm91~$t1RP%{@+dsf&&v3<< zhDVb%%$?3Ej#VTu#g}s6+1({+WS81%(>VUzrB6G%6zKgMg1WV4M?PVBYaayK^4y{t zV(@n5GhLcnmlsJJAVP0_Q62gFy8GJmljs)H_A?NM9}h-;zQSvNqseM4M z=fT8u22G1f38*^a+TSKn+^K%3Kcdko{__h64;x--bQgE#HXbr7N9x;KI#J1M?Sm^h zKjW4dAF@1tkJTiY0GG1sI;)!O8>^7_ddvFlc||T=LgsFUekjyI=>NZx6Y8+c?vC%^$bs$MnDwQ zZr4MsCb|J(M@S(;CIq^|K)`itT@r2CyedfZ(b^KoR%fsxWDbz0|F&`RA!BG-;donF zRN&I7&g%QUZy*&Z;#6Yve6wPMnc;f$V6k?mX;no9t;a;yz~m5Im0m}+U#eQB4sjXQ zZ6)SkxpKE5Dl7+gsbd?dl(=}TE%0uZMdN0;n?)!K|8C0-^brsQ1(y|K3}eRQrW_4_ z_@&z#dORPzi896r*Zv0m=>mzYWp@nUWtRd_SQIwx7r7T}z^@7Ehk5Wl1-KdId>%2q z&X5(=v%<5y!bBM^y{mi}ca#s2@DcAnl#dS=qI}HBf*}}xFMokg?6O>f`n72KiESw6 z4;L9FE1tnu=lTj|$SIANnVb*H^r%7+Oh6xu0e`wg5NWyEb3J4=GKLRSZcKFG)k|rC zw>q(%;@-W2s@>i3kH^$PFQ5PIJM${A`OMU>bc+uukHngojD%j(EXExBeEg&*DAL&K zk8xeEejQ8`&4lxEkp1U;YZi|e(Tw!E&8>M`KXD{w(&KCLCOQ2TW84=`IlXan z5IFv>*9u&+9<{O69+G?6_A}oclR0Egw+-co>BVj%!RP0rEIlAe6&)-mn;vghM?9GL zc`z}m2{1DKKp`>!q1-eQ6}Pi>kv2fp<^>I}u0WHfq)Pc^XIt$c?OR3Lx-6{8)w)X| zsOmZ zj|kuFA$ZYfp>ao>!L|{Hj=?6-w-N$ZZc%xzUc`oX6ql&ScD;(S{(P=GS>i*;A#U05 zm!ROqLoJ|4vgFUHTx+WMd2YV`A=3|-_BY|R2?K-65s!HLrrhmS54*WW?saz^-YaG< z+Wf$gQ*rKBYD7Pjbqs`_PAujdcu}Ygxhy`LIE^@Bk~WX8Iy^99OHQURV+hxCPNAjZ zgQ8HlMzwuZC7Hq$MTQ4^4%~bmF8^J*93e)O-fZZvKkhJE6@~0!U2VgXwz_Fb^4VhU zq>=*>Y-tMeeSF#NU8YZ~0GOvj&*L2ILN13SC#Y?`2v|voT~nP+%LXDkkE<# zxcKZ?;Yaa`j{@<{WjRGSiWG?y3s8=H@qoWeoDg5gF;x?_a~%jdkdyRbdtUaZ>Xn4A z+eG1~B#P)XnWxw)suErx^*G3P^+4Q1+%KGWZ;57C4mNdX&ss4AA5uQ87Eyf0HTHsL z&zHu^!IrKD-Q9lI8zHT$7U3?2Ifu>Iu6K$WA`}XsZ zHiUL%bO@6+;04Kd?CRY^h~8~YP0`%*rT2Y5^w?FChQ8A##&12CQUurDD`N-GD1uC= zUBf*Rf_%&A-9SZ53V!71Dcf}e_9GQa^v*Y^65jr1+QYffLTQfGO0vZ!6AW^aHq;Vk zcAfukz9Er(cP0OipMdxtM{wWB?ks6PSn_@ea-cFO8lupju@m>@mS)w zlW2VEducmgi;>^4)Evg8e=gyZ^UhgF(k|b6Q2moh1ouui5BLId4+x#k6PaSJeWKYp zx}PW{_HZR2rT6H?Wjind-rbwXo%s5ew&V35jX^1UqV*L#u$z}sZ7ne2l z3!|aZ<5~<;LnqNGQPGbicZ`c7A`vQIXvy#Wu^{v(>fO^Q;#m;F+ zXgNV?A#>Xe3jB^jJP2&(MP#m+_89DtGh}6-Z0pZ0k2y4Lbe7FGp9;~xng4FXIpVo` zoN1a0;PzcD=}zw-TmtOPC=i2`Du z4<9D1%xAO^S`)^}!uluM;>u3gMcflYBiLY(I|~*_=Aj%=RCQBOJp|Y8(R^E&KdWb{ zJJ`d1m_75;Jl^d)3-1-E%8-cwJ4G1)by^mu`nsQiAv~HbB;-%V^c^(%g=MHPJofYg z)JGY(#_0<)pzr&pU>y52GA^3!fqK;zjIwq@n1QxEo(n^A+i)5TuxnwnP>?%}4eysZ zq^z0w4avxOt-N9FM?5aTclKTydyj3V;f~rB7u+44kG*0k^oJHw#q8>Qp5cdGn25Gl zxK{|z(|8=@(esaE4#r&t16~e@rJ--PVRrM~g`^mdwE_6D3FXQoE)2eu9Y!nz-jtD^{LY1>*>xfP7)GlTypEeSOUv{I4MOK^PC3YvVDS-o%2zRGfGt_(S@lO4R&sostj@i zjYZz_oRCWp&blw?md4ni*%L`oINR=#e3?E@;GDpr;Nc4zXIY2SP z5xNlEel5!%agIcSv;n}GOs23yiq_qhu8Ah<;tCx0x(5^O>TN(Ktk7g4(|09m^x_a$ z$}1pdTK8ayqSj_DiS|5WX)MgAngc5Ozdexje}5pAfM@H63Z~I`#gfh>-1nCR5g_~#aTslApZP$husH%FRbAwn?R_htHc*8d zb1aIqVNUqhidnSo`wI}y*i821+rX%L0a-o3B~RHvaQ5-4HEBb0m^$0e*3txHs0{NC z-jDn)wQrDios*+GiaOY5@G5WI!)jhh+JzGf0_k=~Zo0^mHiU?;HMGE_b?1s(M5&}7 zfSoMM>FybP2apG+SA%z~e~F$#Lp8+J6>d$mr!CRwMeb*#MC8mr!5OxHH5#t8R`cQQ zB#hA=I^+P2IF5if(0YeLzWi#}3u|Ontj+B3>*|oern>;h7~qV!r2eX=g*j0&;TTjt zZPOTA_rfol@SV>mj+Wa|&VQ*fzg?ReTsNRicIL1LQ=L}ny|!0&;m(z>4~OC(Ca*@-q#r2;}P-8m(YTf5_c3IN%YrAS2XGd-0 za47r!wO-`?><}4%Z4E}*6fqiLj20fo;Z#{i;vjEqRj+E5*xs-K#=ix3j3FeFJSF6# zK)v?7u|^HT-Up?pIsndhRCyCKbqTY}|(>GI6N?Gw=`Se>LCIPsQ`4|Mh$;)qe`UP*#W1HRj+tJ*V%xL zXf@DrFHLt%0=f*u*ms`W3sJ$??PP@fyf5ws`1_Z@Tk6p8CeN|ePaMZC6xfihnJY)G zUE>7LNXQf`vAGc84q?pQ-p+S)`puBDuITKC%37l`j2O7!sgolJp3}XFzE`=q^6$UH z)gFqrc|1d?`z!fy=&dlHpk05CiFmelNUrB9$sc=(ip80cH)*`bV)84@+4_@+b#f;? z2l#WrTF5+)0j{{4Upe?`O}@0M3sO_#7d*4F6W9?7ivzeUD}9nN*88sQZemmxUAwM! zg)d3|${o`I#)Xzxp2c?xIQT*wT7sp+c&-2z27#++onb?|u__=pFOt&BlqI(=^@!n= zxlcq7e!D-2+Cl}u@OW* z`8MPn!luEHEoA5w4~?=y=S#3v8spCQg1lx@4SOfJL2<)A@c-nwI#yC}69Un>8MJECM2_!wSV+1q|<@1+aywIPPr#CGGq{Wqs_!Wk*5 z-V!6d&`VG*{aA8{-1|p?A3GLTm#Z5}A;X?ag$ZTgQI)DnwO`qLln6C^Ka$;v#Qg2&QQXgt8S-9q+%eweszjnLFs8(%1J6R6s?x z44jQFqjgX}uE@v?q~_iaw&RCJxd7DpZM+HT>;O(|rr%fpZa@95Adfw;<@8kaPgxE~ zKxEl6_>ZIXZYEQZrO4b^uGx03y0e(sc=OTO?{*2EYZ*ZP_R-<`Ip{)h1$r`TXz0j>z}IfD?4&6?j--YO?U8-(xeMAxTykCmjf`M^!u5OKVpG|K!z7k z*?1TSrM-cb-`_kmQ!h0 zbZYj(KD1Rt2D9ZEOl5}seKas_j`xLSMag7@SVX?Yl&1ozP4fn677bn`LH+^~; ziYj`C-2klYx6ja-YRjY7<{5<0)~y2)-#yj13bK>^kaPQTFO2j<*30rtnj8yWO(aUN zsr)TxJFTnMr1@NZ6Z!+EAASJA$XXC#2vUR+*X#10Ye8jDt|_WtEIKd>06D%iW95!& zxI3R(&d)d709bM^?I-N=%!H2S(Y?wgj`t*Lwl)E-sm~u~G*B5)9t+ZcC=bjuQ7Svh zI%KN8SQ@#KbnkwcZy<8xTMy4Z|v=%`0fNue>JPbKkcX6x}gg9B4DcObZHy zn5T+VS;-B}skmPh*29TX#RDc8PyQeF-ZLD|wQU=Y5)maxkVp|BM3?BICNg?wh8aQ1 zD5EAy1Q{)T^fCm|4Mq(H(IqRQM<-E}=md#w1mAhd%6+eOKhJvK=Y6;D$M@s=x2|mk zS2@q)JdXX?_x%`ESv~w~opfq~2>Mh!?m_cj2*X+Jc++lIQ_5IxWwfN&35;1bLry|eWk#AM+^C3-Gm&f8e4 zNO#v}Pzb0RFQons-QkMh*etQt3i*2&y>u9QZO;Gk+WP#XD`Wxd(#ILUt{g451sLvR zEQioSzS)uMG?Rdm)6MhP-pf6enP?gJ+ z$`$nNRt-Z1K??ykYdenx@c^4+%n=Th6}8)coZbD*!&Rz(o6w!5f3_UROJW&7Fi_}T z0CkSyk@i-9#|*5EN&#q*F9saqq*Ze~2_2s)rw)Ilx+$}ssHDopPWfl|`Z+;<^=~J1 z1v9v(gAP6TH1(bty1U$D_N#m+Ki#CPI2jJ2xvMw_WO3^WlJ;%M9E8&D=53iC9SM9I z8{ne&mUn9jZMhR55%^ftC9iJ~xD0{6F-V)Z&=cVyBqpljKRl&kq3(D%*A1pe*P0r< z%$X@TvI_czdX7_xJ15Sb`4xAd*s3B;eeqiHmltr6nFzM#i}P2;E_$TGZ?b^p4e^in znFbI*1(^oS?Leq>v{GL;0f5;?#lE{+)BmcC&d37-zKne@zs#+7wB_LTq^(u#$C}1~ zr(><&kgCzyqcLycPi$S6G=}tD0cY(VsP0MnYzbx96X7>UCP*|O1$L%XV1A#k{HrGY z%S|4j?uHUc#oT+RpK~sx3|Ba$xJ-X^oBYZQZu0?vN}z_WLImhzjbfP2E{xv?ov5ub z-VKN7X8sbxx*jc0n8v7kkM1Hc09~8<41nc%KUnxq9TU zXU#0ws?kYs`Os@&_Y4+)VQ&?#cWKeiDv0??h8lpO4P(K2bOz!$PtYJ%g=>kQPXrIQ3#(8H`l_}<@KfJe}W0IO98`dymshqnWN!L)~dhk=aizjD>3VNHH4LU1HxD zG1GOVC9#Tzd@oedRP+c)Hk%3<*1(iHhBSt%|7@9fivGegvpdcRX~@QgDk zN(JSoyo%nB2#5`&qADAoy`z6`@Xn8FQ|pcsoI|G)0K{p!8NbAcZ})=B41M`qW^ zZ*+Y!q|gKv0Zquu}iUjqMcF9A|OJ(#gI z^5W9%!8^R76#MHvgt>FNWEYat?S*wCDQCKnyIxjjuq%A0ZFj(dyOh&m%g`jdbldyj z{y*OX%|xC>bBcdQ8I>2*-?nAi`nv>wm0iCQ#YdVqfPt_xn0RtiTJ$O6rpnX-yx@M` z#dVtUgvl4X2zBjF8K#^sz0YgE*j>?vR_OV|AEzZ)r0xYgFAl@25-;TZ-5Tq-`auy{l)(M+#C%f{i-;{xjXZ%zH@w`uRXcSXqgss z@>#9OmvJ=o-YQr=ugJ-eu9yVZUTF$9=joLBrwj1j7@CHi1qAnVQeXh*K7afH?YE&W z8mN);`-p@vfNYq5$MowZrv1K4c znMwGki;)~L8nkmcE89Mlp+ZYtxkj%aMK1ey*oD?|FE>~l!yAY8L*>`SGviQq zklAzTMBU6O2$1?)OuhcMm>O{L@b{flnWD&2I&29yhmGRQKVIzL&x;M7{QWW}Ab9_s zt8E4r(qJFPW)o=AT(mc3IiTaynR@fV2Sz7mwsaR}@ri!g)%Jh5c;?&(QpIv}9PZba zq^2ApA3RIBeUC(e9lBECHlQ;0p=i1VTL1RY+F0DC`p>-xt=YffMf@zEDMS|&{vH`N zcNvXi^H7g#kr50foU8wIk+gq5ZQBuuUt3#k|DE$Zcw_po_KkM05mi???}L}nzT%Rh ze4sS_MEV)7ONN%i)q$Ek^$!=<%IAV8;)Xzu@eBDI03JH8aJU9^Pg)LLIVGKG#xnpx1)(mhw{PR6QVXE|LRzt#uFqH`JXQI zq5I*O+R@0}KaII~pm(0kQu{gg%GhUKdt$)M&`~8lXkUe&qEJe9Q$2O9Vdm5$h6*W4 z>_1(knXfhYw=Kk^{X)HI160a=-#o3aJ>#S@_U}w@fBmDt+6dj=-A~j03^l{lzt-&S z^ZpbZ={X-NAjk*^7j!zSc6YX`D5z+z4LVeUot44+y(D=@cp>%luY}Br@1pO|O=+u$ zR`9uiQS6o=J+AlHakBre!Pa;OxCG+tynBUbA(TSqY%cy!SovDNLnWX(NouJaL+jj; z(aM)?On13Uvd<*U3^9~`efhAqp$ivtHRa`jahXLQ%KvWJL7}o|v%x=DW88Zxy%I;k z5%JmmAf*WNXNrP@_YcalVd=Sy=yk7+v43X!Y_cliuOZ1o38%g2J6kC6y+(Jep%K?>L8l$AYLQt!@F;}#zAR|%!w4D4WW zJ^)X5Ilw*fk$ScL_eCc)t)!;^kD>Fg17AL=J;;*tH+BnO!t+|)K%pkgj5%{^ydxi3 z`fveP)=d>aeDQ9N4sQn7+NO8bcTbRtw;uj}@azWTexA3#>q5+}ypPLJ{Pm>x^nSa6{|apT-?_YYRn(dC zuc!9!t@LO3|1qykjeaAw3#8qPr0I0FbwA<%Pu*yF)!Ggqhz^^()J%e2^T`3AgUi|u z=$4}dJmSz(pouWwlck@dcG1`Prr@_LC&C}&7x!dNQ;Acu%u-TcR`D0xJfh+<&f8TU z@=E@W!0N(*RcXtk*df{k?JHcjDTBv?185Lu$TWN!@7u5Z*9!|N>=K~ZmUk#^zlLx% z^&rSw2|^Vr0ST;eZx`53xMsa{)ylDi`1sBfO%YJ9bMeV3=j{6*0Q+>S`JIK5|O31qKc8$k6| zsmT}j?kvxEsgc}F%EMuxNMG1<2mPu_Fz>cu?W=~m&A*C2Mj1}N};xet%K=sQ0u z`dBF?hhhsLnQ|3G0?(S9~e&!M3`3|y(9^l2<7EMXoL~j5{k#i(L>aSv>Vt$K z%w_@*kH`IDB4ls9dv;Q}C6fwpgEP~amajeDSTuKd{- z@I=@u^}+g#345=aa+~_T%F+pP+4U3Hp}>mU$FGcqrnMX0+RXZ-wD=vGxl>zhA<{`OJ(jn3@-}k@QQQ!Xcb=o1{DAs zx6uczOHuktpP&xvuELI9MACbGU!7t*)`WpcQ+}yHrO~qk<`j5} z)o!L)$)%(*qaT0PyF8mwA(@$ohsLw`8od0o@9R8Gkf>v)K~HHAnJF!k zjlY1j0f`_kC{da;W=L@@+=tY5_1H3Wy3o5ra=kwJ@HR?NrZ0 zNSHkL*YSyEU3wi!u?4z16_43bO&gy(gO*B77w?KrrX?ZrF-1i^CA}=cNLP(s+CfFo)z~m`E=ot;>kxoKAoAD)$#n5sC_qAh8elSO zy~f+hpyS@-3^r~-6N-iySkKB!j;;G?9e5k0eSSZ89f76fcBwyiUW5xBYzab$&b$Vz z>tmsf8BnP}wgQODIth7#y~yb~zJZ*lV7K-c+J`?!30yVyAcmkgQknSIicr)U1<=Iu ztq^`ruZMG*%JyvoC#0A~6_wwP?$m85xP%DOc z<_P73H;wrc|0=R%oUyYO!_-ib^|uV}y^H7UHt20u0HdGwL)w@E3!jUSfYlk0@D{(E z>rLyWOOz_6ab~3IKU~+WqwQDB7;z98#DowE54ElM*{?>3>EkL(yOP?+ zRC!PQU@kf9WtX@{6l{Pzt-LpD%9#D_H|Ox-26*QiLX?sR*1n`vT8Hw=XZ`@r*#*jsQoIOW@`_<@v#ucVF}#SEaWmEh9ySr!m0O%F!( z`$x0bB6;9(l>I^lmnYAB3-Ns~(Yiw`Y}^(x%Etvy+!*Fu}s3wh6wc zi{A=M6x4-mMoUr|rPk9WAk0fI&4G5nmym0H=~o{7<~9ysXfiCU-lwIhgI(|A@``Uo zY5v7;Qls9vwj7!HK#DlP(Rc{eCG<-Fqq?NZ*vi`6gp{oC3{YWf&~zsm2{+*?CWOd- z|2!Ci^9h5z7abzcGA_M&=UCL5Bj`*hmc8DFde7-HlSTYBd29rIc*;kpD})VMc7TN0 zqfOB=cYxxI>=-uaV|2xY{XF4Dt_?#IG-rHmexT!2wT)KHsc>;QYkmY>Wsc1|V2aZ( z0%n~mz7qExKU+8IZz97snUx@pL=R)?9f3G{SDC;9H*7I(oflHKe4m1&spV#~rUqTH z@%?TDPQ}DMMdz}_8IL?2?TRnrwB=xT8_BwelS~^wWfIFSb752jJ4%dFa})p*+Zp)V z@mDOy$Rquto@Ynr2x^u90Vqtj7vE>KnsU*4z8?;}^^{jsABy8gf6$iEZ-g|xw^WIjL+ zI!g1Yf%)L2rYXv{##&NPb*K%4hSb~Q%YyCs zgWShVuAm_Aw{0kiE3sZ*8XNNg4%qR+IDuw(g%sk~mJ`Kfk)6OC7GZy_n|K?x`2 z53=J7b%82EhfUi2d-uXXw$#1W9^IGn0C1{)J`H5-bzPBa9ipWY*N*Q!7_fM*p2~X| z^*?ys_hM_c7zJ1KuV|N9n@6gMV`u+l;D#JNK#<~^6yujAR`ZMGaI?eFT6)r-(7V%W zj2el#`4bbcrXGH=WgU}9j^j}@8S4%v)R}FHFp-uvNhP{o`v!lLw)meXE)7HCM0e|M z|L8A6z*2Fn7ESk2%X1v`7^kA&zi%-?a6SM)aKuDi9vTb>QromseCn@yHpL3WB}p0mihZk0eE`-x9K z)u>CMdTLWjEIIfF>9)BP7d))*+<3>jgCmgcaYoX$Kvw6&;G~kjVhU6erf0jLX`N@8 zW2y_dxvW*<52ZOxldLVpWpmi5j0TJ*CZW>C&tmJUxUUGM(P%_%7>RcTD#}VM5Q20n zQ4z$W4=DtA5Lg6PLfIL~cGZ&-=Sm4^6;AigD@syC235K4Nm#^Fx=DDKY9xbVTqLB4 zJIjT~rJX5#Ti;y<`Gfj0z1M1>!7 zG!{hSgmE^#O0j@MZSgHqTXdGm(2rFqua62+-r5>?{ zyJ#9+!#xXMy+Q1-V1s4u&6(Ea(3&&3REFX>N$yFwf{U zg;T|fA-TldhRa&YhK1R6lc(GUV(P16zJg&56`$THIY4Qo=!?O_Esi!e|C_{v<&?ADX05K$U1@L z0}4(C?8xm{>Y5XR+iHaA5p*Is53-W`dADUM^`J9mD1Th=Zhmj0mWTb`8mUqGZNTkw z2LgTq7VviY(Z^aHmflI-Zuq1S$+Ib%G0SPqd^P3{%lb>5lRo5LZeKvp#+P|CTg5pR z7?@zAY6fn(I$bf&)o@FohNEN@TVs#6ukcUCPr(IYF=*B5n$n5~i>s-M`%RB^;zYYQJ8fsclUfy3#Ago-XN=0NAqQKk(%F}Ry~>p% z%^UWxn*#JBYNwnghEf>rw)=9nGWRH^3g7d7Ql7T$Snp3UI>YZL+P{A%x- z>Zw9n@;YEw?6c;aCQ4M?xWygOO3lx5Ojw_19XP=T%Mmy#LfU$c@QRtw-PYaanX?3Q zVB4sFsa^H8bGVhf_k_fdC&JnLVu!g445^HgBOoiw=5&6SETwJh%$!2;%lQ6M1xlk? z!{aEs)NbOk_G(-KNQa4+SGUqcrt@A<5dF+sOn35D%M+X{F=3(_L6G@FT~IFTC;#3D zNlFjd9>fTrOo*={E$pq9Bc`kD+i&s}=5IHWoIPGndiXZ`M|&qxe`es(TP&aa$L%q*EMm4gda|3qbaP zbd5}dP@;#?2SlbkTa`hzY&?QFd%=4~g38G2+1f=!t?O5)n6`=pN30@)-N6LDPrWh= zPI1G>#F@@r`d1{BKie6#^$if{bdxQwj}{Eqlo!dihxl1Mbsb0CA5Yk3B!v2DI@-T zjgac2&$A51=UCX>CEOCD_U4M+>U&nuzMgw#TGL8b_R}My<#_Mi$kc+G66;F7pg3pT zwX)+JB78lgjCdU1BhuTVE}bK&xWbwud=iX)AQC2a7WFO@ABd1FYqc`@<}$c+b=%z` z0!4_HT)XcOXr9c`ta&n#=N_aXN&o~WACuHrJ`qyM@$=j1e8@G&xZx;O55Db)JPomD z@!|L*@dt`yC%hN>rc+68{PWatb*i9W0o&ZozgEy)5<9xqAvb;6@AU$YiEn|Dwg_A7 z=zOk-Y=OJ3?x=}Y0()lho&(%)O;^0{k&{$R$&q!EYBl=|SjGRV?jrg`z&oH z8{SvGubO(_9V6*6KVlD@5c16l!GEYVXTu=U4yA5KSUORqn1A)G00hsR| z1c1C44~tfPGun77|-7y(7J3&G_s}no-x!vZ)G@J6WH6@+^nsw>GrM zEf+egl5k~8J+>jEs*poX_e#*HCa439ie|w++aa&Hq3#IX)}pDw_2m{B37ycSpSLz^ zRyQD)nG)FL+9Z2)c54QeAoWS2*dK74WUcOr*0=t>{T|*~rR3J0Zobk^+o;e!iPX@6 z?NS^}pS{nYqyb-pxl!Wi;O8sJw`bkhWH0Dz5c;+XB;8(A>UEdQO`OR0Scs&+JbBr6 znWFU7O?l)oSWB*BR95`=o_EQdFIT_cj*=mB^=Utn_AVWM$1a%Hd|EdK*@ccofRVd> zA($`KM?3i3B%4^%a-Y8dRNBr$T5Sgvz7ao|!bipw4O+%KBd2Xt>< zxwXS<)=B;TyqPuma-v{llbr3dJpC-qSFE z4(3tAkLlwI25bq^4Tx(ATEO^cOcB**x_dFJ=E2$x8$u)nQYj!aRzfkwo+X&`G+RRf zi7n&=eBHlr$sk`g4?#+kTi~0>AN5-3F2~>FJKGfBMH*t%(B;Aut7g{b-|Kzdxs!dE z@=~8fFoT+qCY4c#8SZ=Ergp(c(rqZwuKR>dk2_8JiaLgje`Ih9y^C4C`iW~bn0Q#C zj|e*?{R3i^k!?k5qR*R#K{~5lFQX2;cW4g|%5ap{oU&j};uIc=it{M%6S`B+Bi`=- z-L*lE*j9L9uax(5V?T7~U@Uior z5?oT4T-X&nj*Ox2bc&RyD37X5CoM%yJ$JliI<_MH9A%QY(rX&D2`Z_>7{%jl7yn@3 z)xn+bx*m%YiSOx+I4sR<*no0cjK8#V9D#- zpl~C3Bv25i&%jjqf~JNc4dH7@u6W84AIMN#9lP8)kaTlRIQ!B~vRM^dKAL_e8mZb5 z(_Sqd3aMtD-JRMLV)W%oTpd;OY@+Xqc%13uzs?Z};&0qfAfWWs(_h1jsl;5$b(q;!=j^E4+i}Sf`4-8$ z`XhImvu49#@mg{nS*bj2Nwxjp%!u;r+0x5n)^5j8op~bkxoopmyERFZA6wH3K<@b6 zC7-o3wpKT7CP-c8DL0SEf`#ii!mYgY?N?B9m$-y6DAv4ade@VI6HU3yc96(DU=d|- zvR?e>Ds!6HO+{LPgUOa!tMXV49Uxm(8id_!^492i7?hGJ#pR(Wp)9p&k`-(emr~~1 z$e_WqIy^7_TjvS5cdUIB0Y8|r(o3WJ zSzxXn$Idw;XPV4grd|+&gXxq z8zWktq#l;JlpU>`K|5ZKFY2gZeio-<*ytic)m@uaI%pnrHS*ZE6X6Y23GM#93PHXF zrh**d&2G_Gjf0$Xbj|v6l{4z5<$Oiv5nJyFYhzO$jz*?YiCX4FuM&G?DM>@i&CENg zYxjnBRjntcZz z-`Rha+Pc!%PpUj;`Z^v(lToVrQqs%ijUaOV<AhyxQmkYQGaD>l2;>#vozCLxsDn6Fk`I)M@#e zrdCH%2NOr4jbx0KdQk7`OM8KC$2C7Gs&30&wh=E#(3pLMN<1HT`VerQup3x`_nX)Q zORZ~?`YE1XBJ4eBmxNA)BZVUTu*g&4lkbtcicL#&UZGYJX9PKD=OWTtSsSu##YG|` ziMi9DF6hGB3P{k2^IL1onqeY@*M+kluX#^(DZEINB;6N5#$V#<=}&y`PnxdxW>Lu( zOpdK(*D*|5(_JWC&855lD*ssgrKgVO&+P-4D`VK3o)bVsGFOj8icpDHEFfwcsLSd_ zw|2wd`}bl+jJXR}hrDKo=CG!|zUj#aFIx>oV7~E%IOYy?7YZ_KAa_jSD;kRzZTr{Q zU}JgPBO+^$3kus4n%pA&Vpgj&BDhu7wsN=hhESOxqp@QInD`oj5KI5qi#|K;cvMAA ztBY^`tIj_n5ZUv8yh05!a@;&VH9SJqToevp2UD z_(IgQ6Z0CMdFzRD_+1c0_xbu%i5Q;&GXu z=DH+OL_#||`nsp=u8csSLi$CvD+V3@q&$wnv$|8(#Wz$k;Su9p2ExBmc@l6kYPN&1 z%*exdF-^A8movroN`ULG0mDK>r<#0}JK0+f0Y zm+?4mlTz87F564Ftw|DXuQb#&1rlw=4?3pPpm{t7B)F^}%xAyG(Xq3R>ghwK;US{N~Hba2Q=Mci)2DlSx1BvD|3 zuu_FN+l3DdUD@NO2`=nT+WlQKwgDgDIb9H9XqxWjVE!`2Z^*|;oYy9O!>k|MmR_4S zlb}9UmHMG`t(6+amF%h%MU5I~-2R>6ggSi7Opn*L#-}UejuKS|kh#?5>HB~A7xIXV` zX|M$5hU|vE-S^>gKo~PL4bo)jN@Ct_0?&rEkKjBi>nLCUVBl@SrXBJ!I7uhHWIeen z1LZ3ATx%NBhB<8?sTrjUa&B(XI6-*O7j%aGxwz0i+`O93gAfPU1(X)H6n5-xrDw06 z$Z)q=*H?M0vl-o#J+@T%II4}W)<$KH_gWBVo}H^5aG~}UN6;T5ovaw%eCMy@rhb+WfzU7G|Bk=Q8BYgGv8fdE7+R$3INh`I1HO6V-D6mX9*3MPGs|%BN>ufy0(A@|ENLc(De}zt_WZ8eOvAv~%3iCLSrH7D`Du^F+c0Vb9m#f2(#$6fVzcB{Y6l1Q2(s&bpIbukHQm$A!o82|OK%B%YR{IW zDn?Y{MKzCMn_=viIe`lhuN)_31JK1UjcJ|lIT21~fD9J=o|Lcx=}yCIv8a5|x*FT| zrYSU8wXkE+>MN%F=!LWFd0Vf=L4#AvIx}wCrR~jL0d(aL1j*>GtHN=5IGb0FEWjh6 zq^DmggcZhS&*U5ekGsWgO_WR#=V_I&mAa)Ojq>aU>+n#V;NXyGSd(m(a}qgc2RMxh zh!pfliR|Q*MMKjUwMO*gRWYMyN>g+VoyBuY8!bu*AmFuew%jmsxs+6pzq2kJxDFbI zD;mSB6lyyk|qs&Wz&)=TO?3{(ZTF`3g6$IQun%N@_vmWmX} zu^x%A9+~;wMoTNh)jmpwc6obCV|tlLb4D$mc88BIZ{@C7fK5{3m-?7J$D7`+$ZhMo zs@(=X4f+Yrj#8INhrHZJhm{*cMgteczPa-|_Ut4g73GL(N|e=iaq882k&>%4X=%}s zvybP%Ne>`()oH;&4Y5yUOpn`Q>}fLE4lHy;JYa$6xL}DFcyhs+Erm&06+aiPHHi1>B%PA~a>m z%BzrHU$ISWOH$bU4@`b?JZ!d%qC8-K@%4`0n_S)Zz~)cOf^ z0b98_g$0qkr9+A`n63e6!qQnH;Tvnbzo=L#Uv*IW+@1>tphv~d_n0&|ZZ|Jjqa&Nc z%QUjN=a8dQ_vUjC-iHi*&YI$4jJsYyqqufTaA}lLal(R^Vkk1EIoeg@if$t-+^dW0 z%pfJDb`+t7GQGi6Fa+q}`hlrN+v2|UCVLIjoT6UPACTFSpV+wh615jzVNG|DDKnbr zZ6o!tPT?}4YiBERRwk;edGh7E-lR#kg~6ujqS=gXjSZ9hTTkqk%|L|oP3wJwK$`(Z zMXpj6E-8I}q$A%hIjc6GB-CC}szm?o0Zh-nRU+h+6Mbq0lXhK>Kby#h((W0>n9Ptw zrOYPsy?6_j0xJ_NUUL?xUBA;8k#?eSWw`Ej1CT?*>JFh9a<4xx%b(r5J5oRq1g&1!-1xf!!zzSD_L=;mymfqP#}uq!M- zlmQd7>xLyiZU!xDHCSkX$`9ZH0#N=w5>3Xaj5Q9#M8j{W-T(?@-ZlwIWt52%=X-a3 z`D9&uu!;M=ZX2lBjaX9IOXji7?A9$L!*?&HVpppTox(0?CnUEqlmPOTymdln#pLv- zvSTO)oA*{cH0X4XfgviRi{IibcLt`lEP2JS`8Dgp#2Exf^OEBH` zfuuwJPNx&d{URbu*&m(n$%$FIWLEI>pw;<@TyqN)al>MWOmwMY52{Pa1#6B;NE~Xj zy|P?6D5`qf@{`S~W%1`gdh)?5D942BIwNh0F|fVmymVUf)Th0V^G7VK+ArB#0xVA( zIGR$s+69EQV`n&!97CwYrMLdUI|WR6ep)4h$Ha9FHEKC2`60^m9Hl-wO1?h%1(b(fB@XGvp5A=Bsf9P6C=w4`jVZ=HK z9GQKx6t@8IEA8h`%4?g(m&U!PkGFO*2y)TLio z^+jQ>SV>HUli-2_6P(qPFLfFd?+rH3%9U6525AgbRkCmJC3m&Xch)EX%dyREqoC#J zKqMiFf_Pgv(XAAQ%b!asugxzL+wx6I?(td5z?Q)mr7Z2(NM@3fYL za?d2#?%ghwcgKpz6KZoM2aJezKh{Bu92vju=ut~gCB9yzRKGi`R)~nSlFYctXrK^J z9iRg6Qu@(0THQe*T($zY7R_S>3$JdPBn?{p;B#i7ns81M9OxP`D$+Sb#DSrt_(_^_ zJ`GklG1}xI4WlcMdg$tgS}^bx`UttJZ0H-l8$68#K1RMekfRX+>$kcAV#99c^kJXT z?DD6#^TVWc?_s_K7=;U0e}C&6sSRw<^Ndkuy6^2=b(Mue!Xb>dODaCv$h%n0Xjten zB7z3RAv|upU~p21AkdADJu$1)JqCAlRcE0B^UD&<(Gjo*_Hw%Ck?;JC%IslP;1_f+ zc4^Hz0zbYT*9;`HU4%+iQX$H5iaHBoG@`Ae40@~C7@G3fnhTW}n&uo=PSGq7Fm=+S9ZN7x^sg*S`bWraxDn1*^lfpn*QVU9pN1m~$_R z6{C+^A1pGd^tLgn>OL9X-V0T`8*gmZs~pi86U4&7)CQ8K8?qw~_y^r%%J;Yq*2B6l zso}1-p6Pn*#MLXUm8s;0>m8pb!FR_H;T}m!W2LlWUde*F5sT_^lQ~v^)&PvfC(Un5 zrdh<_Ug?+7J=J}>2gHJ6OZhQh$W?-@(S*iKaccLh>v0;hVp}<8v4%@C-b=coZ42jH znG4TU)|QzeSE%E)`NINre0>GKny(z01i@;>0-R{*nCz^a2{xi)w=y~yu}ZwjspyMyC9n;B zIn#wD9-d{u-~LX2VYQ^22oHMOmk|}0-~vWY8k2_XD2!IJ!q0qC z@3<2JVJ5vX6!uX`H}NdIg^^jc{Wd;zU3F}UnNEx?+9gY&sAsl8pI3E+ExpSIM&rC2 zO*nwdg-nSMUNX5+`b++bwc~tJ&r0qnBgq4o6t-5I>w}1Ung?9qJ*pQ!Rg0IG0>pc< z-A0-I+hAt;ZsPSviH_za`{5)vG;Jn#*Wri`hhH@20+K{)io~rZISaS}^yEiwgFxT= zg7?YYR=IYgIs#on3sn{$ER$zXy1@8hoddP<4aS%bsj!r9#;61CALOR*w>3W=2ARjF z>7v@{s1@2tZ_$d0$VI?TrA67yZkPP9m@pIQOD3G7N5#>cG<8;)TC*NiiIN36Uj73C z_k7>XH=rWIQD>|ySD7>U325(raCE-M6spA?AS0~-Z*L<({=$a8@#Sj^rKxFHX<(c# zx>tgr6#A+mBm?oe{Vt?mS>yFH)y~W?gfGYrrNfwl;~6xJNv5y3bCyLHddol6l5&U^ zref>jal%*IeG8wT8KG}}9{nf%ppce~d&rl)_BNyAK#0C>%z0Cz@`w0>)a*v!Q1=P5 z_L|RLGBu54(}&{>>9dLZ<)9Wr)Kx-+u(v=?ttM1Ih-U*h=K+B5tkhrIDxChjoaX5m_YxRI=!Pjb8+29qmM&4AahyGDYVIVJ zg%vLmUFej_m6lmS-Wbr!yjox*TkaZW-Pf2mFMzAX=?&PvknEf$EP7(u!9?M4!X*NO zVvLtYTs&|r2s0utXbq#$_DZ@zrqMSqZ2g1>xrw)$^?Rc&tXNk2UIvQ$+xfg$=I%%J z@;v;MlmPOWV!1Z&JSWTI(YuL1eN<^OYTH(CaeG=G`=b=s{cZM*mXJW{t(rt@U|F~p zr3RUBCID}gM4CM?KVx>}hTm=oj^%KQ`6iBobhW8H+>~AiB zJoTV@$}y|&gT{KfoMT?oXU;}s!WD2&GSK=d$H+EgLGSIOD>9B_2{K(1AxRXsL>Br@ zg|@nNPD4q2h5F``-k9pe!h7=xrpnpJDMvK?f1E0x1FGBnqXwi$NwKTRQ<>44SBQhc zBG^)LX}0!~;br}x`DoXoVQTwQr=sMut(&0TEPM)OMr6%~To4+tF!MfRjv&@IIeYWI z+YMsAT@jBTVYUq=u?aiE8m&BKM!X3K zlbbbeJ-dn-Wf@Lx>5Zl4V`@W3zEUWdIu$c7I!8BTk{aUF2fn`IPa}aSfuOi!IuFr&a-3QW7Q%abZe=FP7cldOdcV910C%aVg zKlB~Gg_t=*zLz-RF3SyW@Y%bG6*=ciK(<#Esxo|LYWp}=mFor#npeVbp~p7>=WB8i zZ%tJN{1qRpYb+GzWRIhZR&yZ*!I%#m&?Tt}7*!r>aS1N`<*Q%nTfBs9Ed})Or>c#p zGlG>F`4`@#|7-lWTxdIW?mkwrxRN2O3G7rCvm@n1$$f+B=czyeXfO^ea z0zOm)hGFhiCiwO}eXjFCp{M?)inMF1n=m!k4WLU1+qV3-^xz-$8L%;CS~EICsWoud zSw$W%ZFI`lxx#*f;07@k>s$)hv_ZY~0>D84(YAhUay&yq<5mZLQs8^GmxQ_UPKh8D;_R9&+GxNI!~?taZF8RwVE8(|Q|ct!!q{e*B31x6eFsrDT=NtY8h8sr}=(kSUfb5wf7Y z{^*^5+d(1xRW5HxDZa*L)}?uaPF^Bl!nC7?Sx(vGALg`i@y=*%nhEe}r+Z%J@YCG^ zj>bQf{Q!qcX)QbWssz{M*Vc9`K#U#%ug1!i4D|_=U!x}kN{L4J_<-ze4UQm$qj5i^ zJqD^{V2OlZ_t!ZYPA7wKp90g4zkp2UbX~U!Z2LSPW0Tq-u&x~xPVYO>WKsjXW=DYO z+N5z!4nO`IolxFqK$AVQ0p`+>qw|r+L8R!vj{|@6HGROWggxkeQ|)HRy~g zb1{}y_o5M``wD?l+Pa8|j55!t*kwQm*jD5g*_i|W84pzOZ0r6EaLgb)L`56;o{`Id zrK{=UyZKu-xHyUm5E`n02r={NVY?6%U{jAk@<-fwS94l#F68CM6mP`W0F4&#VOUm= z^pU%zau0C!0bBw)#v=<}n?OxOXe@OKQ>B)GuHL~|K1 z<^-&ICTmS-nbxX!wkqYlr5-UN)mG8w(~PG6ZL`bf2Ng`_ZO6 zFvI|+H#2v~j{nOL<3A|Me|1(E!cYQ=4}L6O4;B#&O=h}a7s-8&tv#Do9d?4@Bp|J+7LPzRkAQurIQR;T&y#lo zc=80`L@vmf?EsU!$ueLl&Dm(Lukl#Gp#;7#YiDyq9$IFmfa@?-Jm}^MSwrwSpo0fK_H3+6Mw?Q|N1AiZSWc9h+@F@Kq{2PKksAX9i5aE81Fy4Gqy><0Fhz7PArFvxl) zSs{oL$Rq+e+Cpz;I`gG#%M(Dt+XIZ<*f~k66%cxVJo(%d!7~CvOV{l^&BtP`ud9H4 zBNo@Y|7u8*1z_Rmg}LVfA}p~AP(z2IQ6Z~t|2L`-7k+A1JKkf4HfXP|ez!lKGHnnM zLU^ES8UQ0h9e4GCRA8AU3XGHa3hpmCrwWRV0wRt%$1b}wkC&@{9&-N#_Ft(X)fZ@l z)YLeTFPXY<3BLPi6vhYK&kVCqLj-fen7pAHp-qAV4+ML8%2vEi)DuALSJRbsnQbty zNh@F64pg+hk(eRy=}FNf6gEYnT^tV7*3MbIMPwu&hVZi^-yRIk5WMmM_#QxVcjuA+ z(W!f$vSltiMQ8^y>8~2C@u>oKXdOVxcOk=uricCgzRouM2}2W9I4%G+u^!D!U&Iy& ze>J&c_oUfQE|A!>Sde{kR3jt{eDzi_zO_FR>l+*?C`L?`B?5U#+gth zZH!@G*arGm$czb6u78HA=j1SCM5-6S$f}!+#HfMS#Bqgxo967Bx;5|u$Cx<XGe3g_O=|S;i?@qsXwViBqgIgp(~kA{zo?1h8U8=~0C^j%P^2w5 zt9kv0*3ot;qr&N#x6)W$Yx2=j+4{2VTMA$pgcEBw%OlMsOR+Z&^n*sIE}o_ zV?Fp+Y<QUsDF0I3Bv!~$cPGm&0bDEz zR>WT9lb8v!Psf@vQuxsxu@&}H18)mSPm4L}gm*!){a>wO{?RvP`5)HPaK!E-9Zc=? z*W|kHpTSDsR^jLOXlGPFodnC(5S-`eU`@$!cch%d8i^U1X5!x#`tcmCw25oZR~N3I zwGLVC`(xG8%pK(~|ft!BuC?|S1pr2X@kV9n2e z#kzn%Ros3uZtnGLV1^6t#!qW818VTQjPT!2*C_5?Qt(;kcLQkGgBBh^*D_KcNskM! zh3prG?i|QebKHrXreF5U;4%AXK`d%V3i;U90>OST2zw6Qk-NZGNf6#(#%VnbM=y1+cF==VVPhMdTI&GOQUB9gU>&1e0$)J zbD<6&zs0CjxHRToKhP>H-uS2S(=g;CId5-IXVInSofmy@eUV}z{`9SJF6}90xf4?3MEf^2hkzwgS zv7&c#EQlZY`H}zlxDc9b4RQS+YVJJnQxe_Fvw!+HhE5n(He$VE+LFK{NP3;YT~1~C zq0_b8{C_}-AK6c)*DP&>2hN)boh$$R@OC8-b|jV+Z&`Zz{0MmYr~qe)KP^=37<|3k zJU<45KH&)S8UlJcKPzbdfXtGgdQH4vpNE-osbQ0Ki{dUxef`3C<< zsmPGHBMlD;8@ev9X*i~Caxj)A=+rd^^EB3m%=Pa#6>DhAI4d#H z)Rs(Xhn9&Zt$pveTV%UtTFc0eJ&hmIu_j1ItHxg8WtP|{qXA_0sV|DxIL{==}S-Ar3YW~ zs@ITtxsTG&2^+&d_idxWz;gl|m{@R^OUpaCmVaM5Rrsuj=-FdSqgl<0^*@E(W3>GH z!iqDn;Hm;%Y+w5D$bK9qqP)Pgf7yuuD?v*~7||0~2wj?rWDJej12xXezfalHH2!bi z{#u{^&D($XlOw|=N&n6~i<|rgPwFTW9Tw)V@8*2}HdTG3^2Z)Ly8-LJMnklieVH=@ zheL5yfZ9qzFuULrZW*t4Ko+}`xH5FB_>*WEZ~d+k*D1rTK@kJB;e{YT)O7f3??vgD z`qfL{p1K|mLa3CE{I3Ub>BI%pu`w87zCmkf{h85b+uAUG?VNM+=|-hbYtq)+$1x-$WdGTvx3v*D~(CQ_rN-0h;@44gqP8$e#of=hZ6y?^KOwgJz0Nx&az zK-f+XH@HDth<70Eyjjm}Cc9!G7doAEK;g~V-AZBkTIt#YsUPSFo*zD-2V)Pwu?yg# zUvXslS6{OpUR^IulSjPCapC(n?ZlJ!_{=*?T+`Wj)L-~0dmjxGFlr~=)!gja=~%6o zbMEDi>W^Ketzmq6=TNsMDFI3U?~p6Ed0!bs0ZE?7EFFk2`G)W{dCzTkz)&o=gH_mM zeva_pRs8vHEIR_;t|W+9yvYas9{UP)AL>Z*6T2?SQUKaAJwAV+fI2}N$e@^kF0A{U zf|o5RQq(RfffD>c)LMI&KRGuG2#z<15Ch&aWwQe1mGqV}&nXs}EuD>Shs03_!0hRX&aDMmm9Pueb=+N;4U?I-}IdJ?rfTb))TE+Mwxh0q?ixYWh-bl z%;nB0h)g3OF9m5NAPqU$KBCn)9M=(kPo6yd%9*Nyl0II4C0g@ZIRy}HuV$S zFs&jD2=J3mJ&^XywS3hKdqOhUdUmqQ7K(o-tv%Ob3pz)uLbvjplwY`Y7>S34naDt2 zj|mXw&jkti?oE8Ugn>v<(lN28Hb) z6VpqvL_K@Esu}l!0@Mf26*VwYgH-iIO2>*^m4}iP5cW1Je$ifFJpr($c+j0FaeFuK z6NiC3qIctSR(L~yolqLO+k7l(7$?ejThhSkvF3D(MUb2_RY$S4 zoq`$2IgNvM$ZMe=9TT{3x{kFJ=;h(t;Dqz}Eqr$axwUqXiNBlp@ntZ3DRCRIp4I8i zeW9JTLi*Hu^V{!ycX389@qfB}FY)@5ozhVoTg!^-V&|c%yW`MSNCsd|H)w$L4*ECP zytul)CGO}d5VgArort8I-hd#Atq#D5zBCEUU%^&n-~wo2(|SFz?Pw9G`0ga$bbIMG zWZ{JM?j;A_TF#$I#gy0zG}CBLPBeT4V8@`;ZNg@h zoZ6CddMC;|jidgG)gRjnYPX2loCisIy*i8&w2g2BQb&pDELc*osQJ(~uihB&Aa;D? zlFJde6Nlk=pnqV)@*A&aO@JCbfwv9dPuqu*u1?L?jS1Htg20k?hOUr7kwY94SD{VY zIV6Xt{NPXn=^SXlUA(vNbR}0$iK}&CNLrX$vv8(WTlkq7?qHaZ?l+L7i8}04qJ00r zGZpF2$C}hL=$SUvh3vgjijG&~G4M^48DAb)zwB|w9;A(9!iw%Zt@OxkqPfkX3++sFCW9ct#fOXoV9y$FLW8_p*8L#QbgQTdB>^Q3@W^K9V6ZdqCuW@D*cd*HU z(UUy5Zl!o2Z2e2}@U?vR`Var^h9N70HKLPa$9a8{avOgfdH0{lH&iUl}1+8Va~+PdKaMmDeS@;vdH8Lg2)`8mX901HD>_lb$C@U?p%k72+b zUEJ(&5w4%3{+Qd9;F0Kb_V#&4hySgjDcMK4Y+$mYX~Yqz9E+6&T| zc1*SBhn&B&M>#_yS*0c0q@pZ3TBzDvu+_QrENxBarLUZ@VEbT>tJ0iQ|FB?Y0Y@3J z;x_Nj?0x8R+qNzDB|_Z2K{75=H|N}>@8b6<)vZ!)83pz|-Se{vC+=i8_EmZ2egz9X z0d+t*&>a3bByUrtA4Z*6wax9_Sv@~0*y$d;jBU==3ow@@== z-I9@ml%7zpAxKk z_7&;_$QQGpQ@Sri#Ac$spe4(wl&`jI^eG6384SI7xN~UV`SG?qi?9Kc0>Q*ESFVHS z2}}yv#e-Yizt8sgeZ)KBw`qX&JGJQXYzSm-#*Xd`%GO=@ z_C>zx6Qpn2Kvn5umITP;UXtD0HtTB^(R^uR({@^hgkm_ek?e%`e>k)4t2tdT#lG`i zQg8~o*4lTKG&8abaJE8nr>H?iYT{s_h1pn3rqOWnTa~!z$}*58t3)zw?CRy9T`J}> ztR@8;Fca3uF8kFE`Rlrw`UQq(Jb*-3$`QsWQBa*gB^%#Dolv(1iyzexStoi&Js_28 zQsR<2XZSw$jZQ3hr1I=Zkb`|FaB3cQnURU4cAm8N^zi#PpJ^56^-NDcPAO-*I{FS= zl1jJ`H|Csg&rd}cOjQU+-=t^*|6E3s&m3hpb;I-(Ff0iLFk=1io6r6*;w_9Y;%_AJ z9$i=%BZflQe?|5_?fI5Tdfr@;E)IEI#H0Z|HbvgLDg5E8cF;w!bW4yc2b^9ycYN%T zeDJBft)krgchYtn5(hM9+EAlY0X8l%FB&tjES(`W*VjmFm)%O%0N4 zJBu7CulHvc>D_9WD4Ti%CwZ=pBxhJ)b#LU|R=c8S(9S1f;84(|NTCsW0;v0xkYZ$e zfIGVpx$=3O>1|=ogLT*HY^GsZyutOjWm;fw)|{sG@Cshl3je6^yOm4ImTV2_>h-v) z_!mM9SOUoY5+WAp92S>1Z3LTui_BQjc-8HXBIRD9D3G%>jIP<{1icgE6dB%qe_*c{GyVLH3&PsohJknRugZQRw{(m#Y}s z?JN+29$8;Z|BqYcZ#$v5AHB6}xOr`u>l`=lnGCo)>bABT-vHyyNyF2V(D7miX8&B^0@^eNAxK3YJN zTpj`*lS_;}#GN;!ztr$m8v_kO%<;pq))>lzY1*1sclMSNcf@xfT8eO1`^8+amv*mO zZtqrV&o!@gT62EgfaP|7X;zsx@|b{A5cSsGJ?R{?`~tABqPqp9TmQ1+`BzLcz*)mb1EvZooER zaSd19^GVg@@@v-8X@eMjV?^_CP$Z)g%5^D*d(Tc5oO^k_ST7Rkw@v`D_s|(k@wu0b z`;AKSnG6cn^@C!0xVdW0G4_WT;f6=(RG$SHYmKQ^@!sW^gdz9oc6vg4X^vsB)8s<_ z_n{T*q|d;6c=Y>1M&1%!#XEB!;h-1GY(U~QO&by!Iin6*emLAw?3`R+)7D5j7*aqt z2I4{I^u@H4mC{BfC3So}CV(-TbDeE}$!^Vp#dylu48!8wxuvip;;I!$T^B+VtRh+O z+O#Kd_fBk#kYR1!kfSfDHE(r7hrih?7V6%oa%%;g-zR4kdd*lhh18EWr_X%>NRV22 zG8w!JVYq|{YH3lcSF%$;Y^4mzfqXawEV>Bs zjJ8RnRx0-N1SCb>TU$bokrXudrE)|WPtn$x_{}%-YNqs-XFS$Wdd_P&0Ud?MrXb>V z@Rm;-*n}H>CuZATWXdMZ>pz{o9!K4+Q~|@;1H(C>b;tV;!*O9b)Q?dY|Ax}OKAXb% z^llGCvk6%HXq-tU@(`1Rc>9r3@HnutIRHxDC~eLi`>2)^5K>Qb?(IP-aPzNhqdKP>%}7{Q&sGms2A< znf`(ve~LZO)p!wCNm~=!l~I^sHN6nJr4RP@ct+lv+=-6DjwI!%anL?j8h(o!%^`L} zSBM(_;;6+=|7nfz^7S|@A6WCVsk>(X;J%OSU}?vw)2C>qhjkdJD?NJx=L!(MAxadv z?iJj5x`1YE)J_Kd@2)+{k!BnBoN}loT1Dsv#rTTRD$2T!Yz1F<2l&EaC!Mw}Z?6af zv~kSXa6uD0xbO=;_f;RKxM}Y50J-&2bKQ+?)Y*^r;67Ct9HzjnoDW~VH+Sy75A08s zI(mrn=wJZb_w6YB=dApF&06ke8N~>fYyf6bRL9O-z^=+!74!BN+I7JNWF`v#JK@X) zuA>EV9kaMikN$92C5E!r$5uqD%=11^S4%~W;0!>ZHV zgtl;#i65ZT9Cq@u1}yKtO8VRsZLp~VE$NzvqQDJH2m3bS@plMtq-#lWE&CFz=Gxo6i}bmp+>7@A$Gbjv&! zeHXzH%!RZ^{e7Y5qpjH=DgH3&9MT^vFS-t=pW`7hvr!KDlngG^$YDL-gv?GGs2=s z>>Xr2-k1NiG1O@lC)TC<>>w&&BC5|h9fFN<2{wkp-H50^K=c^6_PCD;DTHi33lUt6 z(;!rcobRi?S-3^i>R5UABY7sE_08J6y1iQ);F*g>jRC6L{ZAd@0qcNc0Id3`uBP4U z<*g?zplP0jfi_5|kfOxv!8Nu9%-@a16mDnc+`@}eB=6M8hh5MPcC4#(_L*yy9_%ih zB6_I4t{u}K9tzkV$GgV-SJe!fM1{>2|q;KxhGp%~$~2QGjJZU>{h z#`0`2{~yj|2F%wPr8{#^8L-ac9~j_M0ApGFe|rDCno${UX25QIeZm4fMRnMFgiT=` za?8F`z*9gHS3WsdyeuU!5%#6T+j#Tu+QScCoA8IQp<=zsq3@{ZJw ztWAY551pEv5Yur0@EGyzLWO3WT-eRjYO^E+D_GVfaV|q5lvLpI9?x+Dg1#=wES0uE)Y|E| zRm|qGhN?_6YOEpk;p)yE)yT`Y^E>$ve&ejTlJm1bdX$o7e^eD2ms);Mfq$<-v6H#` zO$i_-&r|>)nXVQW$aHRMs6NIV#W&8T`*pG&%-O(bC!=plj_#XP1w)?4Spg{GT;EOE zacJC}4|YdryZn^o*_CE;5+gv`kb@hXqp{M-;P*QMSxFXM8b~$ZO|LL>A>rnnYa92r zzrV6A+Wcv{c4jVz2)@W6)2^#zQiT47S8BS0aEa$LW3V_oOcp?^&lK_&iTp+-2WxYH z)LZB`KW4IOJR6oIi6dClitJF0y2A+U^BIo2V$+y#LJZ;?#TZF9K&I@z>Dq_r>$`#S z{4G;fxhLlvDqSXqck84(#jlt9V&Ycn zfOT_WWdlMBOFrQZ#4HqIJBmC3|+x`HeH&?I=AxwSE~`_%EE2Wz*A<)>;Smta&$244yQ z#s|3Llmh7qIYW-#Z8T5u)(&*h>R;Qidk0Ozo95PS7d{=CwGRqpT*tO@wB8C~XQ;b~ z&jNIYDB`#SF|Ot=Gk`>p=LY3AgH`R2l_~|u%ZQNT%X;AO=NB8@K-0MRFcH&OS{^7* z;5_xxYr7^BS!I{ z&2FcVB3F+PM}d6Jbc^^z(i5kr8-}JPc!&vdqrRnZ5F%%i=Xb_O%|6n3b`G-cU3Di(kIBZ@ zh90^b_rHZ}vt%qqmLyHykQphF!f~l#;`ut+e5eYl<6oC90y_i_QKO5+e|#((-)fbL-u=AV1S-LoqZaxVrT2D zoZbY;GJLE+?YjrVZZsFSJ#RfGvx|;!?RLU8fL8OsV%|@$B`!~g!m-fj(h(X~kYChn z^Zoja-V-W~2ydAfkP?75IJnFnvXSrKRroE|_}*?1*_{`22>k4^#>8NQJu_ei-h9cy zON0rUbhD20uuccc6V+P2q&FzX#o+hYb(ghGD5oYGiq3rjuEiUt2kdJUKGLLe+yz_g{N3 zy|gvp#g!zUVA~APkxK=Q^rh)k2TB|3002*)Bdjc8vOuKbe zx+EqhHcU5UJoK19hiPZ(P6Jrk=vU#vg=4jM~s6!AyY2BQm~U+Pi0#BA=POLUT(^{Lf1B~lGJ zH}~7r(ComGw=%~I7YiR{3AR4cK&~|xcv4L{Rv{ceJ4F9In2mZ*=?RQX1!ZaYF;Uxg zmx{TzVrPq8iiV|bnH_sizc^6uR@cnoq#QT_@wYI! z;A@LPZ~H=%M7*h&EwoC47%Q)6g(Cmi^!fdw1{$+TME>~MOVfQv8oKXAt{xGc@Jl6P zEtjsAMU-+o@n?^(msU}bprJdvF!vD^IE0(CMoxG@QKdXZhwOU;I7-g753MR*$^|hN z_bpP#1k+E)U+$PX?JZ&T3RL8X&6lB)9ov93K_?aD;4sxYBs4qX5-a#sLcRVgdo#Gn>5KqJU-Y?)_xp{VhRux zY<>zx?J6VqUGr~f+UaQpU2KaAJUEfOnJAquR|1*LQX)1!DonlE_-gy&TWiMmKtMRF6vlV$f^r^z z!CmWt*Y~!qBPg1x8id|{YnD6?sNHJ06eo3j1o#GZA8 zStpsoF-YWBLm}Y9j<2*q}3;mv}3xWhM;MZJ_h>a7hb^jIPLba+ZL6bazXJP4Ilf_rQop!z!x*)mxs8Qe|?ri2Lmpx zBA{F;&kNwo)n@={Viji>xT_Xm$#Q^Hz};@t|9Ko-c|aw)5Kja3m?+7ET$S@uf*&}Q zEktkkCZ@4SQETL9;!zPCclOiwOT#<@!(4N6_vTg0zq{FWT;&Qy61OH0x-wDZv&x0f z;7NvUd;TlHug0Th{b^QYK%YiR)mHm=&|-8lD_*t`!m6MU;7r8M=|8``7Cvj~_Tk!I zeZVv)z#DuLe?#(hns%lYBz323FSslLIK4p5NvJ5FMo08-MEj?|nXxnYVA|4k1ic|r z8wZ}}6X2|r%$WcS4O#%IYG)Zr%-)P-e=zwj=Q-mhzVooPob!N31^ly%dsm^!#VVt_ zINxCn;PlHKoJMV|B~3qg8i+~y#HyLMFy9i09sJ20gpMb+&Uwrb9@--6WVL)DOl}i! z%+3N=HMcT|2?fA5|B3L>CB(K*?I{;reH8|a3-h*LKfOmpgVGPz_ai7OiQov6Vz&ky zhC)cW8bDarC4um1pdY-0)|s{t___F)$GnQ@_)3}VvIfKH=mXYdbyf^eE(~DOnkYxk z_QKrYN)ThodSJ8o@^hAuj#Hx(tnoNyz&JkqOr~~bWWo7{ z9knz0tIR%j6HNu4ZK?kXFt9~6mpjm6Tk3)yK@!Mu-dcP24}=jR_^)OLt$te2pBLHx zBSZnLVLTdDC#+3g0$LYykN8UKbu+T(GQIdYDg zn;EgiJqwYLmzkP~{k_(hREL~1&jMA%TNbV`?iIIf@28lD6cnDL4yZ_S^S!sy%JRK!dGk!Xl0)lqb{Q#KKpw?4z+)I1{__<(Z}7@1XUe zPUiqruoF=|Y%`<~ z>ISHydGmV}O#~LUB--LzL7xll$;-@KTZDXIm6dCgy=oJ!c(nOnm6+FVnuEp9gq+wd z)4$?FXk5je2eB%*CMMNqC-5>RsM8bzS;@nGwGMrBgZFW-xfAem%_!dzc0JVn0eLK`5skzjnX8AlRaxEY6)cEpwTgWIyqNLt-ZM_%+ktj4hUn?!r1OB+$>@^Drm!k!+v5Fl&BRAX|mo@>V20<6vhlENj1z$q2 z*`219K3I-6Z#zVVrqGZs1>#Nq+MKpof5Y+%#fXi8uaD+hEk&F{wiF2B;Zi0;mW!`I zs^$6oEVPC^<*f@*$&_$8SpTT7nC9ELK*4;SFm%luQs4(!dg3`Sm7%ls9Ab#o>6Y9d?{fwx^=H+B)5Xk z@|PuLqoO|Mnhe_WxC3+^&$vP)zlt)Bj)mJCpeB|-OSxzgA6xz-hWh1H>@om9sO^K{ zI%KzUFoH!IhL{*ZRUe;~Dvq;c@t5?UzI`FLTAV5QEi)aEfc(eMNG7y`&(IVd80~G{ zmy&Ig`)oLzx-y>GH#Cs?gT{eS;Ge#jU;}=mS+KJVasgh_mi4MQ(p)H)o|)k|^s-B% zhn4;5P_2eZOu)$R9@ytEyMoBs`L#^r*qafkoS z4D9^?R;EvZQhyDum(^X>=kIYRdH?2$C`N)oZ%ip>K_+JnY~xjb4Q^|QZ>s&@VNQs|CwL7TmFA)ekDEGfwdT^43#MrOi<#{vjxcfWdRPm=^7P#5uq-=L0I$0 zEmgVmG0=KHb*^#$-Q`t*tNqwIIdE{5-+YOiHKr}vB(9F zA4ImfY%fU?-HulmN+UExh->0s8w5EJ5_!|mauii+t$G-0E zz@}u|=l?)5e)2zXC&3NScV>T@)T-C6iqzmKT6MiNe5hHYVnaFO#llc%;Y8c(30K%YCI+<$nVEay0}nNN?uI{YrBO36@zj6@vC5vSH~;3Llml2tt&Du2 zvKo7*uTBfVIriB1St2uuC{!tAlj`@UH0~QHh5e zaC@pF(#)fYy65S=U2!WOm9HLH zV`xDZci4Rv_v?n6A*mymFv6mfhN2H>%P?y#jEJR=%F*h-FPAF!OSLbeFOvH8 zohx|=(-dD_A3s9ii!mqNNOn_mz(9 zc;I7eLp^oT&3fP7U!lIkEisUKGG+Y4ec{uyi<45#dpF>cN@xvbPoa@%h|X59|BGoo zu?}l0#Jp9kZnCJ4xpW}RU>ua+lv7+#B`qRYf*fUsJ|u0Z#y?|yswI%{Mg>sJk6@G+ zb??0hy++;hM)<1C=^m{1Zb#Ec<=67ooKq!>U)4H$>er>oW4WK zWCGQa?Yt@7hzh=rX6tIM1NeO)A#V+PFa7zVZJ2*Ckpb(l6^jerh(Lg~Yvs1)l+ zO5n?__GJxF06tXt=C67zPkqGN2Rip-A=9cN-;Hg+@=85n5+MKql!GkIe<1|HnYD!& z_g|4f+#z~eE}Ye1ES}{sR9{n|0R1@cCxE%z*NS)cQe4R0H@ep-a>c44akmi8t=8*m zfO_6y7Ht*g7F4&8g@|wsj>~;!Bpj9AwXim{82HlLjm%7`e8785RI@V1r zUAy_fQy*oef-opxp8o~_l8aLQo?IY8tKTUXHiGce)Ab9|3@9_ep%o|cO@*0+G9TFZ zZS()l+aVa`9*@Qzof!Z~Isjoa!g&6NgnMt`fd{SP!`LYxomwEVN+xW)K?cSN_(m;7 zj(vR9kV>sZ1TiS4C}_?y>WCD#x9h74&HJlXYK+)Fg8_8!x}!9$#E%_%oG@ByQO`XG zC5Ti9deGKD5~m%J z4pf>JZo!b*rrhUo_*qJ4_u7 zKMCm;%WZz&9Stk^;=Rck9;Bp2$mi`S%xL@Go~=8_X#xeL66(WcfPOd5-wtk_c8{ir zwe(0u`fTgUH_2UCNP{eiL7H?4&kJ(THqf5DVQ{k3dP{KF0UbY7aPP>cW9S$(@^QEV zYOM6a_-9qraB1GB6?tRK@{hHObC|X;GNTGQ1JNT#rlD5CCWwi>`(va2dO79U`x?Qn zA+rU;&dlWF!js?5WZ$|mGczd~Et#%e+*~EKN88A>c(A4CSxe>3sm9`RUyrwY{{a|* z|8{mgtXnF(7(FAa!<*nu{7!;{Wl7wS4D4PNTxyrq@$TZqUH~GUlZ^4I;h|VLd3p^-ff$gmo*mN7G%9sls)O`# zF8J=ErvGTn0HAH8?_zGUL%L<&Dy*C$JP8F)bMKhA3ceTO>%0rJ-ex$6Bk2u0xY_Z* znJh%ME_;OCSw(iaRL6|=#a2sDpdkMzo-le zqOLTiwhkaI+PQbR>hv%AX9%lk(U)OPHhOE(5 ze;sJ-@>zXD^LrkBbVGl*WXd8$>2$G=X%gzDly2a_o%*R!OR0?>aZ6=rf8&W7PAm zAaXbLE%I#o@cz)aKw{`YpE2!z2gJ3JQV=U>zc7 zORYW;Ly1Q=ow$qA4(@)}n!Q^3OQ3>B>Tz)5ni*a~&1^h|9QVs?;A zoi}U@IV4JYM9wH3Cq)UxbLc^NX4gk&+M30fU4k?Tv?~N{EWbVa{udWO-QT;zwoo1~ z#gm}+DW&2jId{<~8FwOvCm$Gz_Jc&<^~dvu4tDrfURrIp?gQ{eo?6rkD8p!l^PuB z1r3~jU&|BE?v!WGEUpE$(d4L!w4`2>o+&Fy)gz9SB$GXF7i&{^E|5j~GIzw46C-N8 z@YBQze$g0>(5Z!{rbUrJ>XbyXRK3!}8Der9`Ha0scp>EQJVKl9F@KB^;69d z<5xEIG4_oD(6gtewcz>{-&6r3{gP&JBSVhgPHO5V1{Vy6Op~0*>iR={Yvv#`I1V{f zS37+>EfG;>R@{xvLY3%#HGX5Y=>(8PC`?!)dzu$VO2jI!Z)t6Ny4Bq!bwqrpKeR}R zC1V$Gj9G5g*_^LZr!>N^}O2#+?+2Ont5PGC`2y1f59xiJfA6(Kq+uU1+=^9*Iv z8{ckl8^;sws5re3T6oi_UTT#Cmp*%U_sf#YliR(U#@`{y^iWf9ESGY0%-5nrk$7rp zZw^#XQh+dIHgXvwJT#=J#IgSjSx{=k^Qy6vR!=MA?de6VF+b4TX0}*YrADup*>Bah zLUDeF7G<{wo7`x`=_Woy*|4iO7o~X0cV0wm(lAu;hLOMq>ee^LpS=ezVy1O#mffa; z8`tcR#Oxe5xo!%INhJ=~VYu(v&8)?4|G{4PIpQYJ1~6b}c4#OCyo@Z4-<@#KpuxaO zqu&_)Ey}0s3%1T5j}Z^?>F1}+se=0@Bje43-aIY!Vc2L|~@$O%@@h=_ad^bc92 zxgqX9UAclEdJ$ZC6s{9m-VQ96k;=XEM#&t?RH;`6cmuyxKw}(}U{(>CnW>ea?v4Nl zvb66U&^EnQ{T92RVTv73wXSkrjxi9FIzSxEKu+gKN^4nLQRJ=Uc|PK&QzC*h!IH-C zbw<2x$bF*^(cjU`L=%5g8;(LoTa`XLo^ooBR}yrX`BDh{K|TEC zVe>Rvf89L!T=z}HyJ1W8q&{{Vk4&fJN z99=n-QWC#Exh^&Djihx&gj0h)91Z;q21**$R{D0D75UG&35!jiDK9j8lY2knCSn%9 zCr9~Y>!%NP`&r}fP+utpv*EmsD5!{hbsjVEUeDX#s2<0-oybu@m5&~tKeifcs!G3f!~uWj;j;oF&wQA>H4uB&EvvO zl9`TH=u-xC3Wn|&OM_ZbZ!cZo*Fb}_&%qy?0GH3jyVHiNvlFk4}_GLKe(6xPhw+?c3T8gZApxR#Vl z0zTkSKv;}UlSr&deq(f8WKgR4ed6wksp$g=y}e7*_8v{!w1|dxpjW!{uyuE1o&FZR zj@4%NK%es1ybKrNM^#31z&diSC9uh^m%W=ZX5qG)_4+IgS#-XxVQcE%lAQ0OaVMR9 zlbGlx=nH4h>Cpt@`8<^aZU%0fpih!{RyIgaC~iJ2n_T9D$=kNo9+Mh-wDxe7mDjhd z`C$g^Vsalz@_X;ab>ra8$e!^mYqLSJ9pF#blS*{nh5IZX=RcCAm(mtRVIvEtTIE0o zVowKpRYs=Td;7yX;%^T)+lx&i+NHjjku9*^QDsZ%;h9-YqSs7kE9|!>km-6(|0=Dk z_u0k1FE^R71?!&RU!kasbeWv{S$G>b=tz7@Xhn@K`)Q9!;0tyBkt>=+NECJi)w34HLc!uYIo{1V3G*3#0_jL8~E0CC4{j1a9Z;W`)@ z1;ZX%iMx&KPT{3IMY@oi+Vmya7$G4{>xoIkn+39tcEBuo5sx=p=-akf^Vz^e31_8x zl5~5T;yH~s1+5q1+U}t4I{gXv3=1`={SwOzJJJ&Ja#+$__6tHgpq}KV6*=WS?bt9z z-P_6PNjznMEVz5vTkU;(*!|WGGiZrY4f)5$M15`ov+}*=tf}mI*_d^79tT`0)TuDh z1xUkp*1OqC#13SEu37W_aG*Dq9*>~;m4!$+4RG*k-a5J?Ga>ONytJVBEhvmS_?fl;T!H861c7n?qkR5agdL)6Tv zO1^zxU;Xs^4?tJG*XPK1ul6p_9dofb_5+ql>G-lia#{P(CfH)f>7Pd)@dP67%W;*y zx2H~s+V5F>AmO}2#5hm(CS#uKjYv7AAX7SmgzWKdKFy$-9Ll{GLE#bhNKK8Pk_MWD z(IFXC{mZk^z|7&u7jV7Jp!tK}xs?PYmj=+7)WRyM*yAflhMc93d1mIdCWmRaaK}YH zOpDd6IQ1wywIyc@@J5?^H~)$$vMAnzL~~kyUs2YtC81!?6~Ugrjf2TbYO{qCbDs;8 z2N9Vh|6r0nEc*>h(6BMsqdzZh-C|SWyBgc)=LTksct%lX+xd_3{MKn+h$vDHa1{Gt zq#0>Px#OE7pVxT<#P;S_rubkAGLq#6I%yS28D*eCq`dtRUacyUUJ8in;ulTkB(21v zBgMDscxzhWeJM#8?b=Bz${>`f$YVVHs}*aLt*&)}g2TJ3>vv`V!RS`}5Tc~$YQ?5= zghuj5$oP|m^sj3viC9~zkiy6r60|j6E8Oomni-Fchra4)74Zt8cGp|B@Y0wGr@a#W zjiAzd25|dz+5#trUV62S8I?db#VlyFgn6#*={&sqYVc708BsyS*e{#&2Un$N_7e<`)+~S z&RL6~^^6Jmb*YpIvhnlwoo}oodD1IZvAU&zP{kxtZM(1GC#hX4sqk@sGK)s*X$%D{ zTvS+7SB~iwCcYWbAQMK#JaPMChmTY!82%=qzV?mm;)TNF$ziSJ4MfH*Y%10gS`z63 zRAVhf_O|XWe?-kI6vrZmwe-~?;cV9%+;_^8iHoyMF`{Fl$xyc%V&$~q7T>(%ct0tx#)VRJx(+f}^JNVbl^T z@TN4s_ZD+<-2K?&VW$`u7dFtWUeusme;Xgm8#^6YUQw`^Tqu}Qe%RyFnNmPU5vTRW z_{U-XJ7YffP|T2>mDN!FLgYy-_Z^j)nKe`DL+57!W-jK)vZ79b^?qOqMYb2IFN6ht zn_>b^fu0b_zk%4PS0YObPJ7r{<=N}P3!02{1N4Q3tV19WID)SoAeYV46x@x+SIK~S z6(!qmz80D%iD_)hiKJ{q<)3qk-YuI13=h?w?XG9#C#LQ`lqdc%QlFw#8&qYbU#_wJ zdRRC)=3?UpBNIV?>9_OpTdlKSAVpfJVJzt3VT{(yQxYT|#Jjf#pY|40d2mRmb|~!@ z{xwfsW1YgpXAtW0aIb@aV1%*?Dosm(dL&-!i2#|gdL~ZdI?;ITxcj4nGEDmFT6x0j zG@T#%0r9wa_mQQtC(a^v++crvj^(}Sew(nr)=D=(5&n#;LP$Zqh=bZ*+J4R3o)m^Se}2EmA8j!TS3)+JhA&aBF@?GO{M zO#_7msGKT4IwEX7v@)@rX9dHzAjst~o$`5ZWb!Kti*=^|z>HFYO$1KKEI|%f`oo$!Z{4nT5iQz zok&M14}OEBf&Q{2nZkT>T3CD&(^`9p=fEU;hgvzg-^VLjU3&&m?2As5iMM)pnl8$b z5BpG$2_(rv+C)l%eTbLg(kYn9?fcI^>4^ImsVxFVy|&T^U`Fj+vlHo{QDpGpAds#Z z7a%cV0SCubsfNq5|CXK^1X}JLh4wKIp{=4_M6rbP;5)Dlox-l&PR{K*)=(cmY2Cg; zN$KWj`>2M}Ys+g=q#K5y#>a$ZdyVAhCah-)E9Ob8#;Ba_I$UI8j-U0ftNmIA<$4VTqE%2QRTS|6GM%n@l5EGU+y;`_!U2x#iDrn%;*5QW++7L04JtXJ=;qEB+^_i z0Ey3cf)(FCgxM&Y0jQs_$H%+`5f|p^)c((GfkWU)i%_B7!W1wOmm{VwQ-MN){x;oZ z#lY(pP+}P7@&lzp$gld~f!7?ww2z4S3{Ir;9G}+&s1`eUOYriM8#Au0LG)ume{#ht zX3otVCV-pSyp26#2j2a78OTIVfa2)POzL+3>3iXCMBuQ)gdh5M6TZ!}e?8*Fc1(Rj zg`|)ACK`t635W-rw`(0a-!LuAVurQ`klA*Som(#glsb_{U!OE74Q)H9uio zp55rKIqI(FF>p_(gyUBCsaMAiE5L3iCuE<3w5fYh%)d#SuHwQWrFE3JD`ip7+Zf-0 zs&Xm%)0J|9njkg?3h&o=QtKbhI&_x0+nc3oKkT)@M1(`ZKtIT-ckxvZClPnag3Mqc zbV>V6sU&A8PWb7Sd3?TfSpL5`T=##M!-bc*!70&58c#PU%z|9P{$Q1x+%gE#45cH4 z8+)blJoW~0N|Xc8yU`p?0GO@-D!7YfxQGW1L_j4`6+|kj^E?GZ{iqnWxB{w7I(CN} zo`V~t0CICZ;HZYZO$HbUlsLlP1BHWmb_MQV*o4>>HIVRWNYhOHpb1#Zy29Bws8%1# z0O#!qK-G$vHpnS@_Xe!WIB{nWi0pm6+7G+<9PH+NRM!Hm=?uX3JwbSI0Wz1IBTY;P z+@S)H_8Hj6b~q&w=8Lc38o6ItiX=+;Z$*ZG9$>|J)fQ#x=Ip3-N{9T@W26p^njJR9 z{9hz#nI-*Mt0BW`1>yzn@B3tCJNsylO{^Z_m)Qc0^T0|Z6^;@C-Pag-*X`WM}Qps?LBD5<_gvO0ZwNX*udNUk{IKS_Y@B04v zo$GS0XpisvJoj_o>t6R-RbrH(@T5BFd;)5iX6#rU`5aT*=XgT|FptXVf8w)X2;b*c zGU&?Th7rT%slnaeTLeqQy^CNR#BRuUsCq^MO zX>Nohn^YLud|QaIyEngv=z4mE*C5iUc83;qoMJ zyIT**y1}LIFi;YIo93oMRM|8Eq&G}jf>vL`oA0dc-kxb z;}aAT{~{O_8CLX>2GnaCWd2~3-UOtjjr?D6`;OcDR~zYQYMxQr|4svH7D+%h4U#m@ z#Dvrhig>fx>gWV*+_~&A?5!aYn?(C0%8&PXXERw%o;Jgho7(AN)eXR&$@${h8c{rI=8yFd2O4jX{P6j~zO8$*)5RpBLQ z!u*j$YwbuWr!}-P_r@H+!r5yPD2qCs_CYx*~cI(K&P@a(`U+bk|Y~Utix|?xRaZ z+H9B(kmzkMhNZmducm|?TA5J(hh)595)*k+X3V!l&tPP_3cR!l)*- zGD3_M8tBupE~%JKW&s9XM{C&0JI$q(Cbw#3s+F#PoXN$C+uHstgD;$Ztl45A`PUPw zW#t&_a+BWAEbZ6K(a)mS9J)x9C81n+d!cSBtzk_v$6a!oyM~!-tr(+FS8N`~zrPxZ zc>|${wA}H*-f$@jZASOh%4(AhxBve8qJngn_N`e97g2Yuv;B)JX8Y$!gSLH4!8{&* zoKZhqA`){02zDiH$@2h3iY{5=AU~_j0jewJ)^`ACw7D_8>f;*Q?BN)fp1bbVy{w;b z4`QIqBLst(XEVGHU35^KCS9P-Ip5O2B_*&zcPfuwtLXXr?y2Q#R`T5Zan%z~B@1!k z7Fij!XPKzXB$uQ;(P0aW;SoAt!l^i=MazGop6F3X8U5>~PW+Wpg->T?W}`G$T3&uQ zI%*et(zKKJLwPEXl9-IwJY3*4jp40#ao+Mto=Ret#Fg{fxjkwQe(Ryc#Jn7xRjfsZ z{hpuS2=BIb1BLXM(|AV^eha+}j9FM>o!TzHoMz3>xv6-uW6k1ss46O+?dF2MiZg#Z7mU;Mn&!}EdNE2FQn zf*U0^A}%GRkHJfN&RwbblkOcJ4~POLiQKy-gv}G!#tDt{e&3{}>u_Q>U0fbC`F8Fn zl)XcuaEj3hgJoCE; zeE+0C8;l6DYlj?|_`M6#jh$8btCoHLN&k7c$3?vI$&*#Ii3e}QSA~MZw{P_QPl2(# z9^NFMj(fcF9&MDQ)Ku-y`C@yPIi_~iq`9|_u@-$uxf z&2lce7vgsiQdo|vAneH#vvi0qLB4%+`EciaO64Z(XkXzI~y_2c#-!;W`sA z1|&BHFW^jj!AfP?wMz;Ihs}JPfX$%?1HVt*CQh%3|B)j(iXY-LvYSb_QEro@K&Mt;H*nRJ(Ozo%-mx2Z# z0@lb$gEDZf8@_v+2n#D&^~^he=>4%f_oZov0HS&Ftbk#?iOFz`@yx|LxDpsOmV zFejsAoyp6)m}n(@WaI{fB_)Y^x+T>G3n)36XwiMnK$-U)E43us8Om|(;IX~4%uMJ+ zFHV%u{CSjl-H2E`dx_L5F}V5{ZY!}OZ6&0~O$Uv&`=NDr59G{60UvG(wnIXv=F;*& zcB;uz0BC0+`KhsccYY~q-A-F8ULOcED5Q=AK?9bDgN4XMmPs2fCS zhwd?7uRCe*rwQDN%NQ6t$HR)0PVqgEn4@Ef#nm02IbY6gXxBnwLGa7o^PBT0DZM#6 zUcp;yp#AR49?z$xJ`SUG;LB7210*yYBLGZ&P?V9B+>Ej{CpKqg4Y7-E5C)O2w@nyC zet*NhY)YZO*evAwy}W-9Wg=@ zz+~ee0*Yopa}TtVcB6aL8FUBB@GiD9$ZX;>XUq_W_7ow#IWkm+jqmv`kr8(^mY^ip z$d)j~yHq>-oA19Qz8hSO+GRiQ=%1s{Zj%aQrX;s3O+~wG9}NnCfE|+F4zRGj&U9NC z00GUX2S#0^Amr=ys$O^ItXcNR^yBw;K8O>C;!5!n3T>LCb?GwDtOl`M9l>Zw1`p67 z`LiTPg)(s*q_c@k90xyrgus3t4`Y(gP`ADqENRkP(052u{p$~9V_LR>?0K3DKQWgN z<&u-oqfx<{6(x-B;e$3V)c|i4O>mW$fd_YYHN_94xg_*YJDY}vypEqf9Ra?vPKr*{ zjvG2CxP&Mae;hP#45z98Ojnx7-=7P&WsnTC2?GgD4UJWG&W|n}Q3PB!laEgfQ9wH3 zB}7p=K>G_vry$BWXz7;tP^hs)ziKXYcD$@#Ct>6rW8%tp#ir2uBnYLNu=){2g%7(q zA$S$eZapCjSpE6i&Q%jFevq_bEek#|OL-rGOmZcU%kB>VZw_uS-hLT&x|od@ zL|g(3T!K~u&CXvaZ*QJ~O}F#;6wj{`M29rv`RvC@h_b zrHQhtUFoNF@nv)FHo<;%Ec2PTh2%eQcy_K@JF%<2?AY&Cb70n+ zsJ1zQ=ciErnl2a)6Af*ULE6#1@IHA~r1MeUcGXAyZ+#`cq<_bXS7{({XH(dztVRj4 z5AHurcXy)?x=j9sIJ8JU-4BI(Abg6HK*zw)P$`3mBoMMO1ZZ`{>lj=9R6)jDOg2g~ zw~Dk0q3D{zD?VQ}xxA75a?USaG`d1}3Kb_<_=gYsw)7K?axt^K^WaWa%2cA27$qeA zFs1nz`co=1XU?=kOC|8Bz?ue&t{8jS?aY-~hd&4e_Rm0Rx;HyL_v)*v*FWE3EQ-9V z6}oIxV)KEdR*5Z{j5g^2B#^Z2?2@7e(F9r!^PMwj*F~>iXRNgNGbR3eFwyZW{>_l+zyJG86+AjJN zt?(6mL+^!O(l>Dnm}Z&H80vZm->V{Rlb3LfuX;zMe}dB{Zo+Fx4?_r>29%8K z!s|c2w6j*H%eTL6!!VQ}T}{-TsA+F7XAq8Vj|qqq9iCf&WCPX|bC}j}ZH$pSfPthB ze!0)vAlkYTDZyFTm3(j+%$SS3XDbx*-V|>-bQ}9)*kwGU%Yc442XyVroa)3Ff+wC5 z;BKg(aB2bO*BvoGTauY$6BrCX7$;nryaRu9IB}Zz)_A5 z&aGeH-KToHK(Nt4wi}K`6mh^XmgXikNol`ZVC2gzm6*WLfCFsx$H&MR(N8#Vp8=A+ z0fd!39qe!%=yazh#2xkJ??ms@gka;&GQcR0DF!oE28`66OY-b`(3y1?ie1|1t?1f3 zDfRIzxM85WS;^L5lvc248@zyI<~Sco$x)<*h4M!_jYFCFgL3hiR>F-3kp@3q!j7;vhalu#j_(;js^6DQ4wLS;htJCb(O&EzLgX*&6Ff8JN zo(&Ri4&51LAZJC@1)J2qF_)#%R@H1Bj%?(kj>P2z)2Qx{)QNZ929->Sk`nzpiOos$ zIXU(3(nng+_OKP`Sh!{@lO1OH?w_a(a@5`GPxt39qQhQ+lwR|wE(Ajw5k01+0`xs; zEbLrV{Y3Ss8m~-~)_cY=@yF9GF0mJwhnt*pxyG+!HKIZUbRz=${lzz6-EAn;%#@Tv zhOAMve1l%i+Mz2}C0=(~J+HLxiQ#Pbs!Mp9D?V%d?dgEXH(G=?Z>^OB6XDrrkKAzp zy3@5;Cx+anD-BVhPI@~_MR9lgvF<`bGQF<7aTEKbV_rwJZ)icBRGo*eeqqOgd8 zX0tsnnb6a9sq;;|?D1R$gOjP|*=b#?=_XlE-?Z+17Dm|iupTaaYm^8dp(xh$lL4`OqHsnBqbjd80^Mt4?vkZ(wXSN zm)FV&yTiKF2U=+PmP|X93=e5JpR5a-Uf;L+FfA+??fnpF<&9Wgc-{qrOr5l}F6qvi zbI<$&dRycXCMh+AgeV$u%nYSEZr;k&j)u&A^D|FfF_Pji-&E;Pe!%#cLsdP7Z>umw zm^1(3)9Ps|Bp(^ymXqXt(|GiXua5l&PJCk3mcm>KRzPKSluR$-b%u`M4I9UDQ2~s*Whxbcgejk#ZiUMcN%sn7-1>?~=2`lf+`uW)u8gkjL^)da1=OUt`mzTUKfNrU<&vf*{2=A}M zM@URzSF3dX>qw^E)s0gyMx)rF6V{?^1qbtRlICMfch+jB!KdtXQ~QUSh=I~9$ylZR zmtC-5Ei;8XFv_XZpPF!vcM%faW*7IZc{UqnaX1yFiZ5U+xD98FlSg+oMdW1Ag!G$n zLc7Oji_i3yy>K+7WJj%&38~oqnX(wv^M}oDZf@l_xmkyLzP1bDquTsTQ$8*>(N>Ld zmfc5#5-f>7mf zrY5$KJ>Z4-nxT&xt>LgVEq7p?cS{&S#TM0PPH=auXbr1svp>UzH zG~DJN%%0b@WJ~-C$jeV}T!;EydaHtZ1q1P*S5oS?(E#~o`dQlG%;^i(+FV{&=V~U~ zeifutnYe4#SG`}E6r8vS=LLfc8#!ydeXqI2&_6}xsMC}gerlOJ1^M^U8ECJDU{&}W zyjCsXJJ7CK3`s2u`u9~j>jH3t&XCWgc z7L>``Llm;x)FK6n;=ca#LGz?k5Rm%hoAp(%6S{IPH~Fi>LqkOgwos$;J5VBsY?-}a zRA+P%g-c#)I+=*^)c=n0fGc}WjU#qN$t+5|a6!djmX%dhc(?;|Wvmlu=8Nxp@_3xX z?j3caD~bGex$~@HN@|^UCJwTC4x3Kx=OL4cJ@QH5Hw`cwsPt-FHSK19DMIn`csoyl zxp;+50|maPhP&G&8)+_0I@ z!5%DQ5B41g7G{TW_V_*mF@+=o6;5tSwQsWDzit!(jWiS~1ugX&M(d)+faG)ye|&P$ zcIMo&%#5yig3boPmP02EE{7dirS z#ZZEbSsDcH&B1E8q58QMLR9-Wd+09^;|TbB(1x<#AgOooPFiCn7G+*b9)$F`EK}0a z3nqr*uKYXZh?`V@d^+-4edVd6*$~1l;FSEd6EpT_;eQwIp~*wIu};4 zu;1dLDNm6Ho&ib707D?c7&CO$J6DhT*&OL@>K3buiJ3?KMEy-RVZP3lR?4E`-+Sx$ ztPY4n4DzWsKq^}GFC-np7jjHuVb~rD2W8J^IM9W*C=VxbE}Ax1a)obMjtz}q%S6e0 zrYJ%s7^Ug#Ep0yk0NC|QHMopP>DLLJUzv{jY#W)en`eP5$BeIk_|OZ3%jRKX&CjM3 zls5{n%6)FV{|KCrp8!`lnm1J9dcLsE22Zgc>VCArACzJ}II;xh&E#+(+p|%TSqx>_ z(Pa1%6BCtEqS&Y<9o+~i8%@_DjhC%8ezA0OEEP^N(NsdMeSmO7QHD#~b`u4N1y~U? zqlQ;6U0Pieo?X9Ig_lhKaN)v*j|V{B{FL%SW%9z`BMi3C!EnA!oeCXoY~J4gRMIX9+Y zZf*lXyqcv*56^_`v{ZySQ&Rl=VFE?>e1)0tjt_5NVgb&Y#RG!JSeX4U5GDe#sC1bF z4Aro6%5w-}CYr|?mic;5931ZatOCk@Ph7aunsW&W6~BNo*O7dg!$Do^>Ghc%g3Ves#NXM<}12okNApx1t#piM;^&|d%v!qlQj}` z^y~ya`Fwgn|3{_RM-}TREths0rfeK}@8jp^M|LFBr&d*)kU=;$bt~=&caFa~RU_c( z=A6mFQKnQZZimE!1fqe|Y@{W<>ulNh*y!UNt91nu=W`ysb-S+2BK`7R=JDglrMO&v06Ss<8*%HxGk_gTU=0^6^2hoD#$~$JIB*Fu1RV(6{y^N356$k^d>$O21+*jt zT%*^g`Uc!yrEjX~G%vm88l<}wlNo;q6=dv1aotgQMkKx}tFDu%-Z4cMRU?x_u6g1J zLKk5zQqrlaA6ETi2`sGyKlEMy)#lzwTm%<@#Vc(`?-FPWz-yF%GnzDoNT_h|9x3 zp6q*DiXAeQAzYwrrLebmMWJ&;IO2HZX<3h0IrsQ(lS8P|ruS?#R4 zA)a^430y+FdjXfn^Bya)VnBbS1Ac5&6g&4|!+fjB#Mtz-bK1Vdlz=Y!vodq57@Vz_ z{Xcalo`xLt;uLM}rPxRJ_^8{*Z?k;6*5Bg%1fnR9?j#@O9mv1;@6B_4n&~lA^Hkgm z@Qdh-88hS-k{wzc80xC_Y<8q0?FOtot1OPOzv?@MUWXL;FY`TZCD+$r# z@sXW7#7HDQea(#w0JaI3 zW=)&!`V@s0Gg$BUk(&^Dco35i^ACK&6)W#jX!1uQ4wHuoimw zFstV_sGU^PhtPO!gc&90LWc6EJB#pd(&K9n^HTrt*XLU^d2C-x@B%6M5VKahhk=#L z=5g3#=25n?R_STtGoiF4NyxAZc6pKRuE}DWeO7x0hi9N3D;1g7Y^7W&+gh33;znsU zm-YQI5wr28YF|pGD1%Frd%DbJpoVv`^V(r#H#n>{e*K7Bb5riN^|kJ|Q#Pc=Z`kR2 z+83z#@!;S!5%znh)uTMr#(AzQSihdc={3#dm0;$dPr!eDN-aBbJi$HL6pClCjN-y#mgDQvP#LgIcFO@7boNb~eWCfj(p8#P+Ib1S&)U)WnOVFQo2 z=&}bzuzRY-*UG(*l7{dcwXEwe8$64`->B(1p(#p z^_3hhpq8GL$`~ES?Mt` zBZ|MUb}(b=X(OKUrEUPLP;#!&t<$OH!t9eMFi$kSiW0yOIkb(3S!2rF(+MKfD%8`( zmK2`#@gqm)O`@PY(Z3=-RUe*bAzoF=!%>F!=|1H-$VrovWBB}H-{dhrzD_*l|Kb98 zsG`Q2a!m-WN=OlI5{f`ow!4@ld_a-GEw!q3@_0fiW3EJvtO)?@qhu8Zkdsg#9N5-Z za|F9P1VKg{NYl{k#@cfhES#lIrq4u32s- zxpNQOK4sXQGCdqI z*ox?X0~br_gN)TZfd9!}J&!vh4CgZ?8H(R2no;SGHP({5Vc90K|3t|?**6lRhEYVA zD*;keVGzn5<<-pj^Tmm+tLQVZuX7KBZmbDHIgB-R!D5h<_xq3s4-{*nj={eVpk5-< zl@7@1pG8i84>K4Y7!@HpwazBC0&6|U1Ve{FsNf^4wrJ5JKd#e)>)m?m+6=B?PCsm; zn%Z4rQsIEwrcI-k0ncx+4Fl0gMmlbgZ+AC~KI7s0uY8+*oB&Eky?+l_U;Zo%NF)ZY zn+mIJ(d*hCg}9Hg!wSEYgtmoyTZFMLq?w4Js_HKO51%k#to$BbPJT#-;9J${jQ+eK`VFJP6J=tXK_g2jZ6JlyCnpSmb66oC%HpHAl z60Z>nqw0XYy%e;^#8WE}A$9I~NHWA% zmi8a)c}lcw_zyefeSkHR21Xuqo)o*aDx{-rpW6Ff-$wV^b>K(WX-O+tZxB7XR>tq+ z;AJ!iI?m?^`7!EDI|>`D2h9!uY#xAaPmIh$hRY^rwj}HG2`%tXRcvtB!`@DylK0eK zH6f$cLhm3Mt_u!@iFL}DCz_?5RV=;@N>hFARR!XqR993kceC&)G_7KMO< zX&=Y1?qw(XGA}QW(0CI7PjGaKbR%?IE(iSl_{P|^o%+8+pqZN4sXaYC@!2|z*LP6P z?Oy>#RyAGK)mJ$QHME3T;X?V{w_J`m$p$c2Vv;B-Pp^hbqxK_%=xkB98vcO0aML9r zBO!H-IE6Ou56*{TO(VwBjWDF`GFn0aCxT;J(Qla&dEHMKG=2yyavY8zFyvRdzr~PU z=92{!_v!7}u_J$I9k@-FWxjQ+)GxXGhnANZxtHtq7uggX`nBgWhYZ>a(O~ZMv;vf8 z4?F~(gz5x2?vh*UR@8V)zjRR?Et4-YVYU0*8GHWR9*RQb|avNi%qCP$|MPOe=OG?)!Q23+%>7z(nF{O8DLAQX` zWe&YbDgcwa1VjW$(FpW~3-|}2yaX(4M#$a`0hO;?y*ic=HE$)(-{s=MjsaWz9VWyWpZ7%9wJ_R$J9y)l4=r-Tfq@D zr<<$bje~!ooPus0jWWuY+5H*CFl+@g9{3K z%7B8&1g3evfw+Nq3vG1uKAQaDe0$XP<|WM11;*5p!WEe!s^;7y>J{?Ld{^A}JgDSL zzXm*POl#NVoO}*ei;6i+?LfX33kz?6fTS=GfSj5Igkw;_R(;c1TXnCjMaauCPe^-% zM;T<9NqHW42>{c-cRgU{VmFWq4G`}!EFI(rW>Tli9jMoyjGy5{r-|)s%umijN6gb5 z-LLA)S^Q@76Spx=csy8bJgfQA0ZbYK)j8`-Pk3&BW|3NT7jpP;oQPAdIy4NWip$TM zHLJic*jfe<$BNvS%#-6#-#A41;x;Eq(wWz{mG09=w|4w4@L!#WY0uBckI&Pn6(S~P z!NLsdaRuX3Hd9=-I}0L_p-{{6Y(?>{v#;kA;89}a28hcg`lSc2JRCfhJcxzucY1X-2<|6yV&h)f-O(| z47_}oa_|%Zq-%4CdV1z7^q;}_3jL=$miz*L`g)u3J@Z{#8ZtaR>(`h{WGx2FmdM02L)6Q+4zpFGJ+^W@NiPE(PvKKz@z%=c^cyk!R1b|$%9p)Pe-cGvN#S0$+g*#SMNKH+Gn=K z=U>Dw=NTdym`-;>GdFU!xXJ6IlCXIT0en>j7KL?Two@#q7s-S_WJ>oXDI15L9*oFR}RNj!_ z-|uFgyhG$*R%(o#dpNk*G}aR)wS#jY1hf>`-C*NEZ%CIvh7XqDeC`$NA%k1vq~<)W z4#BSqtybM4N7+_s<0}S)3XiS_q0zgqyw*nl%6`VvgN0~&5`C2qid$+Z3lzNmOtHut zktqkTQ1vxcPUuFetTSGc@n2hx62qnf(VY`FA|vP7rgbgHdN5i|jfKPBaP?F+#(P4< zSaG=hY^O}C0t0wWI64Irlm-Y5=Yt?$!2f6}PxdHd!KN}tbQT=K?9pSm-v{j6HVX35 zE38V4R`;X$DEGp7y_E90rMLjx!D>HuMnXbTPHFW%_M~es3z#)t{he-_8*k2#cWYTI zcTKx`!k6zCJAf#=IDLTKa)L#tOVDnc&u@JLr26U*EYfC?!E@U{=#~`h&}UKQUY-q5 zSdQQ!19;jHA28-~jx+$H^?|IQmb~qU2(s?u^BY*qA&Fb8R3IZ%W=eM2m#&M^ORC|O zV|6LwGG#24J%y(=}$K#T%gOJ02{rK*}zndzWh2; zf_vruqoP3F1V)h%YU4ysMvCE3Wh_p{^1Z49-Ehx1UVh&x$FENnV&OZtmy{lu5Q4ADnMwSU-K26Ist#L8+{m{SNb4lX+LV~%71)PpcnS-(9pwpy~@%*2v^M5U; z8^%IO;zB2R#g~8xA5Kgi0AN6bc>3}qR6~xtopW-H$gsFb56>cck&vg*LJ6wa0M^N% z^v=hkKCtReM#riVby`a$`khhA*)pPVh;z7oUYBJ{Ux7&WpeUNiD}cGlSo}S*4sLlK zpK6Z#Ob&m14X=k4Da0r^YMl8!z+W{iEo0^H>;fgJQ>Jf_U)GM6r@tP=gw^7rm@rsW z;8?Tfc^f7PsvS)z-8FLvchxXJ?#J1Wqo@qSN^?NHbCGy+jj@}*8hQGBoj6PbsccmK z8#~R?bgyjj2fygPNtOwrWzRYH+Gy`OPxhqCVChCvx77Fyx%q~_z_7$h;|wDy$S%CS zGXUG?yO>}Q#%cGyc+E>bD)9PHFnY})s=D;`rCvb@v~dY2K55B)-!pucXv+={;)GDE z$-87iW|uApz_rQUwDH{~aA@VM__-I!>II!RQPNYcB2^wEFni%|wi0nCY*>gx$aR(J(O(~f zU+$PNJk7X%iE4eltwKDTiA==EweuHllwS`+@-g(;e~m4E`#6WsR*W;vWDz)08|1o^ Qg#R?vHgC*Pu{rpE026zjtN;K2 literal 51409 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 z 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 From f3318e2a300c3ea103ce07117f9c268c1d348fe3 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Tue, 13 Aug 2024 11:29:58 +0100 Subject: [PATCH 13/48] Added SME instruction FMOPS (S and D) support and regression tests. --- src/lib/arch/aarch64/Instruction_execute.cc | 64 ++++++++++++++++++++ test/regression/aarch64/instructions/sme.cc | 66 +++++++++++++++++++++ 2 files changed, 130 insertions(+) diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 210976dbd2..81fad91336 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -1948,6 +1948,70 @@ void Instruction::execute() { } break; } + case Opcode::AArch64_FMOPS_MPPZZ_D: { // fmops zada.d, pn/m, pm/m, zn.d, + // zm.d + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 64; + const uint64_t* pn = sourceValues_[rowCount].getAsVector(); + const uint64_t* pm = + sourceValues_[rowCount + 1].getAsVector(); + const double* zn = sourceValues_[rowCount + 2].getAsVector(); + const double* zm = sourceValues_[rowCount + 3].getAsVector(); + + // zn is row, zm is col + for (int row = 0; row < rowCount; row++) { + double outRow[32] = {0}; + uint64_t shifted_active_row = 1ull << ((row % 8) * 8); + const double* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < rowCount; col++) { + double zadaElem = zadaRow[col]; + uint64_t shifted_active_col = 1ull << ((col % 8) * 8); + if ((pm[col / 8] & shifted_active_col) && + (pn[row / 8] & shifted_active_row)) + outRow[col] = zadaElem - (zn[row] * zm[col]); + else + outRow[col] = zadaElem; + } + results_[row] = {outRow, 256}; + } + break; + } + case Opcode::AArch64_FMOPS_MPPZZ_S: { // fmops zada.s, pn/m, pm/m, zn.s, + // zm.s + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 32; + const uint64_t* pn = sourceValues_[rowCount].getAsVector(); + const uint64_t* pm = + sourceValues_[rowCount + 1].getAsVector(); + const float* zn = sourceValues_[rowCount + 2].getAsVector(); + const float* zm = sourceValues_[rowCount + 3].getAsVector(); + + // zn is row, zm is col + for (int row = 0; row < rowCount; row++) { + float outRow[64] = {0}; + uint64_t shifted_active_row = 1ull << ((row % 16) * 4); + const float* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < rowCount; col++) { + float zadaElem = zadaRow[col]; + uint64_t shifted_active_col = 1ull << ((col % 16) * 4); + if ((pm[col / 16] & shifted_active_col) && + (pn[row / 16] & shifted_active_row)) + outRow[col] = zadaElem - (zn[row] * zm[col]); + else + outRow[col] = zadaElem; + } + results_[row] = {outRow, 256}; + } + break; + } case Opcode::AArch64_FMOVDXHighr: { // fmov xd, vn.d[1] results_[0] = sourceValues_[0].getAsVector()[1]; break; diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index 55c7b945f3..2fad7b900c 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -58,6 +58,8 @@ TEST_P(InstSme, fmopa) { ptrue p0.s ptrue p1.s + zero {za} + fmopa za0.s, p0/m, p1/m, z1.s, z2.s fdup z3.s, #3.0 @@ -86,6 +88,8 @@ TEST_P(InstSme, fmopa) { ptrue p0.d ptrue p1.d + zero {za} + fmopa za0.d, p0/m, p1/m, z1.d, z2.d fdup z3.d, #3.0 @@ -106,6 +110,68 @@ TEST_P(InstSme, fmopa) { } } +TEST_P(InstSme, fmops) { + // 32-bit + RUN_AARCH64(R"( + smstart + + fdup z1.s, #2.0 + fdup z2.s, #5.0 + ptrue p0.s + ptrue p1.s + + zero {za} + + fmops za0.s, p0/m, p1/m, z1.s, z2.s + + fdup z3.s, #3.0 + fdup z4.s, #8.0 + mov x0, #0 + mov x1, #8 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.s, xzr, x0 + + fmops za2.s, p0/m, p2/m, z3.s, z4.s + )"); + for (uint64_t i = 0; i < (SVL / 32); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, float, + fillNeon({-10.0f}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, float, + fillNeon({-24.0f}, (SVL / 16))); + } + + // 64-bit + RUN_AARCH64(R"( + smstart + + fdup z1.d, #2.0 + fdup z2.d, #5.0 + ptrue p0.d + ptrue p1.d + + zero {za} + + fmops za0.d, p0/m, p1/m, z1.d, z2.d + + fdup z3.d, #3.0 + fdup z4.d, #8.0 + mov x0, #0 + mov x1, #16 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.d, xzr, x0 + + fmops za2.d, p0/m, p2/m, z3.d, z4.d + )"); + for (uint64_t i = 0; i < (SVL / 64); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, double, + fillNeon({-10.0}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD2, i, double, + fillNeon({-24.0}, (SVL / 16))); + } +} + TEST_P(InstSme, ld1d) { // Horizontal initialHeapData_.resize(SVL / 4); From 81231dd15754af5cedf3e630857b94b9a2e77813 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Tue, 13 Aug 2024 16:17:04 +0100 Subject: [PATCH 14/48] Added SME instruction SMOPA (S and D) support and regression tests. --- src/lib/arch/aarch64/Instruction_execute.cc | 82 +++++++++++++++++++++ test/regression/aarch64/instructions/sme.cc | 62 ++++++++++++++++ 2 files changed, 144 insertions(+) diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 81fad91336..a7f2e99e4f 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -4398,6 +4398,88 @@ void Instruction::execute() { [](int32_t x, int32_t y) -> int32_t { return std::min(x, y); }); break; } + case Opcode::AArch64_SMOPA_MPPZZ_D: { // smopa zada.d, pn/m, pm/m, zn.h, + // zm.h + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 64; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const int16_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const int16_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLd x 4 sub matrix + // zm is a 4 x SVLd sub matrix + // Resulting SVLd x SVLd matrix has results widened to 64-bit + for (int row = 0; row < tileDim; row++) { + int64_t outRow[32] = {0}; + const int64_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + int64_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << ((znIndex % 32) * 2); + const uint64_t shifted_active_zm = 1ull << ((zmIndex % 32) * 2); + if ((pn[znIndex / 32] & shifted_active_zn) && + (pm[zmIndex / 32] & shifted_active_zm)) + sum += (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; + } + case Opcode::AArch64_SMOPA_MPPZZ_S: { // smopa zada.s, pn/m, pm/m, zn.b, + // zm.b + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 32; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const int8_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const int8_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLs x 4 sub matrix + // zm is a 4 x SVLs sub matrix + // Resulting SVLs x SVLs matrix has results widened to 32-bit + for (int row = 0; row < tileDim; row++) { + int32_t outRow[64] = {0}; + const int32_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + int32_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << (znIndex % 64); + const uint64_t shifted_active_zm = 1ull << (zmIndex % 64); + if ((pn[znIndex / 64] & shifted_active_zn) && + (pm[zmIndex / 64] & shifted_active_zm)) + sum += (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; + } + case Opcode::AArch64_SMOPS_MPPZZ_D: { // smops zada.d, pn/m, pm/m, zn.h, + // zm.h + } + case Opcode::AArch64_SMOPS_MPPZZ_S: { // smops zada.s, pn/m, pm/m, zn.b, + // zm.b + } case Opcode::AArch64_SMSUBLrrr: { // smsubl xd, wn, wm, xa results_[0] = msubl_4ops(sourceValues_); break; diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index 2fad7b900c..535b3514f5 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -338,6 +338,68 @@ TEST_P(InstSme, ld1w) { {0xDEADBEEF, 0x12345678, 0x98765432, 0xABCDEF01}, {0}, SVL / 8)); } +TEST_P(InstSme, smopa) { + // 32-bit + RUN_AARCH64(R"( + smstart + + dup z1.b, #8 + dup z2.b, #3 + ptrue p0.b + ptrue p1.b + + zero {za} + + smopa za0.s, p0/m, p1/m, z1.b, z2.b + + dup z3.b, #7 + dup z4.b, #4 + mov x0, #0 + mov x1, #2 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.b, xzr, x0 + + smopa za2.s, p0/m, p2/m, z3.b, z4.b + )"); + for (uint64_t i = 0; i < (SVL / 32); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + fillNeon({96}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + fillNeon({112}, (SVL / 16))); + } + + // 64-bit + RUN_AARCH64(R"( + smstart + + dup z1.h, #8 + dup z2.h, #3 + ptrue p0.h + ptrue p1.h + + zero {za} + + smopa za0.d, p0/m, p1/m, z1.h, z2.h + + dup z3.h, #7 + dup z4.h, #4 + mov x0, #0 + mov x1, #4 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.h, xzr, x0 + + smopa za2.d, p0/m, p2/m, z3.h, z4.h + )"); + for (uint64_t i = 0; i < (SVL / 64); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + fillNeon({96}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + fillNeon({112}, (SVL / 16))); + } +} + TEST_P(InstSme, st1d) { // Horizontal initialHeapData_.resize(SVL / 4); From 7325805588415cbd66198d0905aad9adc613978b Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Tue, 13 Aug 2024 16:29:09 +0100 Subject: [PATCH 15/48] Added SME instruction SMOPS (S and D) support and regression tests. --- src/lib/arch/aarch64/Instruction_execute.cc | 70 +++++++++++++++++++++ test/regression/aarch64/instructions/sme.cc | 62 ++++++++++++++++++ 2 files changed, 132 insertions(+) diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index a7f2e99e4f..230cca9ff4 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -4476,9 +4476,79 @@ void Instruction::execute() { } case Opcode::AArch64_SMOPS_MPPZZ_D: { // smops zada.d, pn/m, pm/m, zn.h, // zm.h + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 64; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const int16_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const int16_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLd x 4 sub matrix + // zm is a 4 x SVLd sub matrix + // Resulting SVLd x SVLd matrix has results widened to 64-bit + for (int row = 0; row < tileDim; row++) { + int64_t outRow[32] = {0}; + const int64_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + int64_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << ((znIndex % 32) * 2); + const uint64_t shifted_active_zm = 1ull << ((zmIndex % 32) * 2); + if ((pn[znIndex / 32] & shifted_active_zn) && + (pm[zmIndex / 32] & shifted_active_zm)) + sum -= (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; } case Opcode::AArch64_SMOPS_MPPZZ_S: { // smops zada.s, pn/m, pm/m, zn.b, // zm.b + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 32; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const int8_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const int8_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLs x 4 sub matrix + // zm is a 4 x SVLs sub matrix + // Resulting SVLs x SVLs matrix has results widened to 32-bit + for (int row = 0; row < tileDim; row++) { + int32_t outRow[64] = {0}; + const int32_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + int32_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << (znIndex % 64); + const uint64_t shifted_active_zm = 1ull << (zmIndex % 64); + if ((pn[znIndex / 64] & shifted_active_zn) && + (pm[zmIndex / 64] & shifted_active_zm)) + sum -= (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; } case Opcode::AArch64_SMSUBLrrr: { // smsubl xd, wn, wm, xa results_[0] = msubl_4ops(sourceValues_); diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index 535b3514f5..2abc0c944c 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -400,6 +400,68 @@ TEST_P(InstSme, smopa) { } } +TEST_P(InstSme, smops) { + // 32-bit + RUN_AARCH64(R"( + smstart + + dup z1.b, #8 + dup z2.b, #3 + ptrue p0.b + ptrue p1.b + + zero {za} + + smops za0.s, p0/m, p1/m, z1.b, z2.b + + dup z3.b, #7 + dup z4.b, #4 + mov x0, #0 + mov x1, #2 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.b, xzr, x0 + + smops za2.s, p0/m, p2/m, z3.b, z4.b + )"); + for (uint64_t i = 0; i < (SVL / 32); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + fillNeon({-96}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + fillNeon({-112}, (SVL / 16))); + } + + // 64-bit + RUN_AARCH64(R"( + smstart + + dup z1.h, #8 + dup z2.h, #3 + ptrue p0.h + ptrue p1.h + + zero {za} + + smops za0.d, p0/m, p1/m, z1.h, z2.h + + dup z3.h, #7 + dup z4.h, #4 + mov x0, #0 + mov x1, #4 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.h, xzr, x0 + + smops za2.d, p0/m, p2/m, z3.h, z4.h + )"); + for (uint64_t i = 0; i < (SVL / 64); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + fillNeon({-96}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + fillNeon({-112}, (SVL / 16))); + } +} + TEST_P(InstSme, st1d) { // Horizontal initialHeapData_.resize(SVL / 4); From 5708c568d7c6b9820fc8e343a8589814785ea7d1 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Tue, 13 Aug 2024 16:47:56 +0100 Subject: [PATCH 16/48] Added SME instructions UMOPA and UMOPS (S and D) support and regression tests. --- src/lib/arch/aarch64/Instruction_execute.cc | 152 ++++++++++++++++++++ test/regression/aarch64/instructions/sme.cc | 132 +++++++++++++++++ 2 files changed, 284 insertions(+) diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 230cca9ff4..bda764b83d 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -5784,6 +5784,158 @@ void Instruction::execute() { results_[0] = vecUMinP(sourceValues_); break; } + case Opcode::AArch64_UMOPA_MPPZZ_D: { // umopa zada.d, pn/m, pm/m, zn.h, + // zm.h + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 64; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const uint16_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const uint16_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLd x 4 sub matrix + // zm is a 4 x SVLd sub matrix + // Resulting SVLd x SVLd matrix has results widened to 64-bit + for (int row = 0; row < tileDim; row++) { + uint64_t outRow[32] = {0}; + const uint64_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + uint64_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << ((znIndex % 32) * 2); + const uint64_t shifted_active_zm = 1ull << ((zmIndex % 32) * 2); + if ((pn[znIndex / 32] & shifted_active_zn) && + (pm[zmIndex / 32] & shifted_active_zm)) + sum += (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; + } + case Opcode::AArch64_UMOPA_MPPZZ_S: { // umopa zada.s, pn/m, pm/m, zn.b, + // zm.b + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 32; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const uint8_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const uint8_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLs x 4 sub matrix + // zm is a 4 x SVLs sub matrix + // Resulting SVLs x SVLs matrix has results widened to 32-bit + for (int row = 0; row < tileDim; row++) { + uint32_t outRow[64] = {0}; + const uint32_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + uint32_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << (znIndex % 64); + const uint64_t shifted_active_zm = 1ull << (zmIndex % 64); + if ((pn[znIndex / 64] & shifted_active_zn) && + (pm[zmIndex / 64] & shifted_active_zm)) + sum += (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; + } + case Opcode::AArch64_UMOPS_MPPZZ_D: { // umops zada.d, pn/m, pm/m, zn.h, + // zm.h + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 64; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const uint16_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const uint16_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLd x 4 sub matrix + // zm is a 4 x SVLd sub matrix + // Resulting SVLd x SVLd matrix has results widened to 64-bit + for (int row = 0; row < tileDim; row++) { + uint64_t outRow[32] = {0}; + const uint64_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + uint64_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << ((znIndex % 32) * 2); + const uint64_t shifted_active_zm = 1ull << ((zmIndex % 32) * 2); + if ((pn[znIndex / 32] & shifted_active_zn) && + (pm[zmIndex / 32] & shifted_active_zm)) + sum -= (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; + } + case Opcode::AArch64_UMOPS_MPPZZ_S: { // umops zada.s, pn/m, pm/m, zn.b, + // zm.b + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 32; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const uint8_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const uint8_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLs x 4 sub matrix + // zm is a 4 x SVLs sub matrix + // Resulting SVLs x SVLs matrix has results widened to 32-bit + for (int row = 0; row < tileDim; row++) { + uint32_t outRow[64] = {0}; + const uint32_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + uint32_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << (znIndex % 64); + const uint64_t shifted_active_zm = 1ull << (zmIndex % 64); + if ((pn[znIndex / 64] & shifted_active_zn) && + (pm[zmIndex / 64] & shifted_active_zm)) + sum -= (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; + } case Opcode::AArch64_UMOVvi32_idx0: // umov wd, vn.s[0] case Opcode::AArch64_UMOVvi32: { // umov wd, vn.s[index] const uint32_t* vec = sourceValues_[0].getAsVector(); diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index 2abc0c944c..94fe221e48 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -709,6 +709,138 @@ TEST_P(InstSme, st1w) { } } +TEST_P(InstSme, umopa) { + // 32-bit + RUN_AARCH64(R"( + smstart + + dup z1.b, #8 + dup z2.b, #3 + ptrue p0.b + ptrue p1.b + + zero {za} + + umopa za0.s, p0/m, p1/m, z1.b, z2.b + + dup z3.b, #7 + dup z4.b, #4 + mov x0, #0 + mov x1, #2 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.b, xzr, x0 + + umopa za2.s, p0/m, p2/m, z3.b, z4.b + )"); + for (uint64_t i = 0; i < (SVL / 32); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, + fillNeon({96}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, uint32_t, + fillNeon({112}, (SVL / 16))); + } + + // 64-bit + RUN_AARCH64(R"( + smstart + + dup z1.h, #8 + dup z2.h, #3 + ptrue p0.h + ptrue p1.h + + zero {za} + + umopa za0.d, p0/m, p1/m, z1.h, z2.h + + dup z3.h, #7 + dup z4.h, #4 + mov x0, #0 + mov x1, #4 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.h, xzr, x0 + + umopa za2.d, p0/m, p2/m, z3.h, z4.h + )"); + for (uint64_t i = 0; i < (SVL / 64); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, + fillNeon({96}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD2, i, uint64_t, + fillNeon({112}, (SVL / 16))); + } +} + +TEST_P(InstSme, umops) { + // 32-bit + RUN_AARCH64(R"( + smstart + + dup z1.b, #8 + dup z2.b, #3 + dup z3.b, #2 + ptrue p0.b + ptrue p1.b + + zero {za} + + umopa za0.s, p0/m, p1/m, z1.b, z2.b + umops za0.s, p0/m, p1/m, z1.b, z3.b + + dup z3.b, #7 + dup z4.b, #4 + dup z5.b, #3 + mov x0, #0 + mov x1, #2 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.b, xzr, x0 + + umopa za2.s, p0/m, p2/m, z3.b, z4.b + umops za2.s, p0/m, p2/m, z3.b, z5.b + )"); + for (uint64_t i = 0; i < (SVL / 32); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, + fillNeon({32}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, uint32_t, + fillNeon({28}, (SVL / 16))); + } + + // 64-bit + RUN_AARCH64(R"( + smstart + + dup z1.h, #8 + dup z2.h, #3 + dup z3.h, #2 + ptrue p0.h + ptrue p1.h + + zero {za} + + umopa za0.d, p0/m, p1/m, z1.h, z2.h + umops za0.d, p0/m, p1/m, z1.h, z3.h + + dup z3.h, #7 + dup z4.h, #4 + dup z5.h, #3 + mov x0, #0 + mov x1, #4 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.h, xzr, x0 + + umopa za2.d, p0/m, p2/m, z3.h, z4.h + umops za2.d, p0/m, p2/m, z3.h, z5.h + )"); + for (uint64_t i = 0; i < (SVL / 64); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, + fillNeon({32}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD2, i, uint64_t, + fillNeon({28}, (SVL / 16))); + } +} + TEST_P(InstSme, zero) { RUN_AARCH64(R"( smstart From 63443156f914a5cc9d668dbbca42f5ddbb5a0064 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Wed, 14 Aug 2024 11:21:22 +0100 Subject: [PATCH 17/48] Fix jenkins build error. --- src/lib/arch/aarch64/Instruction.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/arch/aarch64/Instruction.cc b/src/lib/arch/aarch64/Instruction.cc index 6f3a259aed..b512b510d3 100644 --- a/src/lib/arch/aarch64/Instruction.cc +++ b/src/lib/arch/aarch64/Instruction.cc @@ -174,10 +174,10 @@ bool Instruction::checkStreamingGroup() { instructionGroup_ = smEnabled ? InstructionGroups::STREAMING_PREDICATE : InstructionGroups::PREDICATE; } else if (isInstruction(InsnType::isSVEData)) { - assert((instructionGroup_ >= InstructionGroups::SVE && - instructionGroup_ <= InstructionGroups::STORE_SVE) || - (instructionGroup_ >= InstructionGroups::STREAMING_SVE && - instructionGroup_ <= InstructionGroups::STORE_STREAMING_SVE) && + assert(((instructionGroup_ >= InstructionGroups::SVE) && + (instructionGroup_ <= InstructionGroups::STORE_SVE)) || + ((instructionGroup_ >= InstructionGroups::STREAMING_SVE) && + (instructionGroup_ <= InstructionGroups::STORE_STREAMING_SVE)) && "Invalid instruction group for SVE instruction."); // Get instruction group offset. instructionGroup_ -= (instructionGroup_ >= InstructionGroups::STREAMING_SVE) From 3724d507532eb4641383ed07d5d107939c08a4d9 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Wed, 14 Aug 2024 11:21:43 +0100 Subject: [PATCH 18/48] Added SME instructions SUMOPA and SUMOPS (S and D) support and regression tests. --- src/lib/arch/aarch64/Instruction_execute.cc | 152 ++++++++++++++++++++ test/regression/aarch64/instructions/sme.cc | 124 ++++++++++++++++ 2 files changed, 276 insertions(+) diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index bda764b83d..71e4b79a7c 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -5532,6 +5532,158 @@ void Instruction::execute() { [](uint8_t x, uint8_t y) -> uint8_t { return x - y; }); break; } + case Opcode::AArch64_SUMOPA_MPPZZ_D: { // sumopa zada.d, pn/m, pm/m, + // zn.h, zm.h + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 64; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const int16_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const uint16_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLd x 4 sub matrix + // zm is a 4 x SVLd sub matrix + // Resulting SVLd x SVLd matrix has results widened to 64-bit + for (int row = 0; row < tileDim; row++) { + int64_t outRow[32] = {0}; + const int64_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + int64_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << ((znIndex % 32) * 2); + const uint64_t shifted_active_zm = 1ull << ((zmIndex % 32) * 2); + if ((pn[znIndex / 32] & shifted_active_zn) && + (pm[zmIndex / 32] & shifted_active_zm)) + sum += (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; + } + case Opcode::AArch64_SUMOPA_MPPZZ_S: { // sumopa zada.s, pn/m, pm/m, + // zn.b, zm.b + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 32; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const int8_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const uint8_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLs x 4 sub matrix + // zm is a 4 x SVLs sub matrix + // Resulting SVLs x SVLs matrix has results widened to 32-bit + for (int row = 0; row < tileDim; row++) { + int32_t outRow[64] = {0}; + const int32_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + int32_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << (znIndex % 64); + const uint64_t shifted_active_zm = 1ull << (zmIndex % 64); + if ((pn[znIndex / 64] & shifted_active_zn) && + (pm[zmIndex / 64] & shifted_active_zm)) + sum += (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; + } + case Opcode::AArch64_SUMOPS_MPPZZ_D: { // sumops zada.d, pn/m, pm/m, + // zn.h, zm.h + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 64; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const int16_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const uint16_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLd x 4 sub matrix + // zm is a 4 x SVLd sub matrix + // Resulting SVLd x SVLd matrix has results widened to 64-bit + for (int row = 0; row < tileDim; row++) { + int64_t outRow[32] = {0}; + const int64_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + int64_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << ((znIndex % 32) * 2); + const uint64_t shifted_active_zm = 1ull << ((zmIndex % 32) * 2); + if ((pn[znIndex / 32] & shifted_active_zn) && + (pm[zmIndex / 32] & shifted_active_zm)) + sum -= (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; + } + case Opcode::AArch64_SUMOPS_MPPZZ_S: { // sumops zada.s, pn/m, pm/m, + // zn.b, zm.b + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 32; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const int8_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const uint8_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLs x 4 sub matrix + // zm is a 4 x SVLs sub matrix + // Resulting SVLs x SVLs matrix has results widened to 32-bit + for (int row = 0; row < tileDim; row++) { + int32_t outRow[64] = {0}; + const int32_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + int32_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << (znIndex % 64); + const uint64_t shifted_active_zm = 1ull << (zmIndex % 64); + if ((pn[znIndex / 64] & shifted_active_zn) && + (pm[zmIndex / 64] & shifted_active_zm)) + sum -= (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; + } case Opcode::AArch64_SVC: { // svc #imm exceptionEncountered_ = true; exception_ = InstructionException::SupervisorCall; diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index 94fe221e48..f8c995cf9c 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -709,6 +709,130 @@ TEST_P(InstSme, st1w) { } } +TEST_P(InstSme, sumopa) { + // 32-bit + RUN_AARCH64(R"( + smstart + + dup z1.b, #-8 + dup z2.b, #3 + ptrue p0.b + ptrue p1.b + + zero {za} + + sumopa za0.s, p0/m, p1/m, z1.b, z2.b + + dup z3.b, #-7 + dup z4.b, #4 + mov x0, #0 + mov x1, #2 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.b, xzr, x0 + + sumopa za2.s, p0/m, p2/m, z3.b, z4.b + )"); + for (uint64_t i = 0; i < (SVL / 32); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + fillNeon({-96}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + fillNeon({-112}, (SVL / 16))); + } + + // 64-bit + RUN_AARCH64(R"( + smstart + + dup z1.h, #-8 + dup z2.h, #3 + ptrue p0.h + ptrue p1.h + + zero {za} + + sumopa za0.d, p0/m, p1/m, z1.h, z2.h + + dup z3.h, #-7 + dup z4.h, #4 + mov x0, #0 + mov x1, #4 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.h, xzr, x0 + + sumopa za2.d, p0/m, p2/m, z3.h, z4.h + )"); + for (uint64_t i = 0; i < (SVL / 64); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + fillNeon({-96}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + fillNeon({-112}, (SVL / 16))); + } +} + +TEST_P(InstSme, sumops) { + // 32-bit + RUN_AARCH64(R"( + smstart + + dup z1.b, #-8 + dup z2.b, #3 + ptrue p0.b + ptrue p1.b + + zero {za} + + sumops za0.s, p0/m, p1/m, z1.b, z2.b + + dup z3.b, #-7 + dup z4.b, #4 + mov x0, #0 + mov x1, #2 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.b, xzr, x0 + + sumops za2.s, p0/m, p2/m, z3.b, z4.b + )"); + for (uint64_t i = 0; i < (SVL / 32); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + fillNeon({96}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + fillNeon({112}, (SVL / 16))); + } + + // 64-bit + RUN_AARCH64(R"( + smstart + + dup z1.h, #-8 + dup z2.h, #3 + ptrue p0.h + ptrue p1.h + + zero {za} + + sumops za0.d, p0/m, p1/m, z1.h, z2.h + + dup z3.h, #-7 + dup z4.h, #4 + mov x0, #0 + mov x1, #4 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.h, xzr, x0 + + sumops za2.d, p0/m, p2/m, z3.h, z4.h + )"); + for (uint64_t i = 0; i < (SVL / 64); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + fillNeon({96}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + fillNeon({112}, (SVL / 16))); + } +} + TEST_P(InstSme, umopa) { // 32-bit RUN_AARCH64(R"( From 3626b37123841ac3d56166e41bcee420f1d70082 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Wed, 14 Aug 2024 11:39:30 +0100 Subject: [PATCH 19/48] Updated SUMOPA and SUMOPS tests. --- test/regression/aarch64/instructions/sme.cc | 124 ++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index f8c995cf9c..5690c6eb7f 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -740,6 +740,37 @@ TEST_P(InstSme, sumopa) { fillNeon({-112}, (SVL / 16))); } + RUN_AARCH64(R"( + smstart + + # z1 is signed, z2 is unsigned so will become 255 + dup z1.b, #3 + dup z2.b, #-1 + ptrue p0.b + ptrue p1.b + + zero {za} + + sumopa za0.s, p0/m, p1/m, z1.b, z2.b + + # z3 is signed, z4 is unsigned so will become 254 + dup z3.b, #7 + dup z4.b, #-2 + mov x0, #0 + mov x1, #2 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.b, xzr, x0 + + sumopa za2.s, p0/m, p2/m, z3.b, z4.b + )"); + for (uint64_t i = 0; i < (SVL / 32); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + fillNeon({3060}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + fillNeon({7112}, (SVL / 16))); + } + // 64-bit RUN_AARCH64(R"( smstart @@ -769,6 +800,37 @@ TEST_P(InstSme, sumopa) { CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, fillNeon({-112}, (SVL / 16))); } + + RUN_AARCH64(R"( + smstart + + # z1 is signed, z2 is unsigned so will become 255 + dup z1.h, #3 + dup z2.h, #-1 + ptrue p0.h + ptrue p1.h + + zero {za} + + sumopa za0.d, p0/m, p1/m, z1.h, z2.h + + # z3 is signed, z4 is unsigned so will become 254 + dup z3.h, #7 + dup z4.h, #-2 + mov x0, #0 + mov x1, #4 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.h, xzr, x0 + + sumopa za2.d, p0/m, p2/m, z3.h, z4.h + )"); + for (uint64_t i = 0; i < (SVL / 64); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + fillNeon({786420}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + fillNeon({1834952}, (SVL / 16))); + } } TEST_P(InstSme, sumops) { @@ -802,6 +864,37 @@ TEST_P(InstSme, sumops) { fillNeon({112}, (SVL / 16))); } + RUN_AARCH64(R"( + smstart + + # z1 is signed, z2 is unsigned so will become 255 + dup z1.b, #3 + dup z2.b, #-1 + ptrue p0.b + ptrue p1.b + + zero {za} + + sumops za0.s, p0/m, p1/m, z1.b, z2.b + + # z3 is signed, z4 is unsigned so will become 254 + dup z3.b, #7 + dup z4.b, #-2 + mov x0, #0 + mov x1, #2 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.b, xzr, x0 + + sumops za2.s, p0/m, p2/m, z3.b, z4.b + )"); + for (uint64_t i = 0; i < (SVL / 32); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + fillNeon({-3060}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + fillNeon({-7112}, (SVL / 16))); + } + // 64-bit RUN_AARCH64(R"( smstart @@ -831,6 +924,37 @@ TEST_P(InstSme, sumops) { CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, fillNeon({112}, (SVL / 16))); } + + RUN_AARCH64(R"( + smstart + + # z1 is signed, z2 is unsigned so will become 255 + dup z1.h, #3 + dup z2.h, #-1 + ptrue p0.h + ptrue p1.h + + zero {za} + + sumops za0.d, p0/m, p1/m, z1.h, z2.h + + # z3 is signed, z4 is unsigned so will become 254 + dup z3.h, #7 + dup z4.h, #-2 + mov x0, #0 + mov x1, #4 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.h, xzr, x0 + + sumops za2.d, p0/m, p2/m, z3.h, z4.h + )"); + for (uint64_t i = 0; i < (SVL / 64); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + fillNeon({-786420}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + fillNeon({-1834952}, (SVL / 16))); + } } TEST_P(InstSme, umopa) { From 2227a55d77af9df12c3a71bb746ff7e8d39b8763 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Wed, 14 Aug 2024 12:03:45 +0100 Subject: [PATCH 20/48] Added SME instructions USMOPA and USMOPS (S and D) support and regression tests. --- src/lib/arch/aarch64/Instruction_execute.cc | 152 ++++++++++++ test/regression/aarch64/instructions/sme.cc | 252 +++++++++++++++++++- 2 files changed, 402 insertions(+), 2 deletions(-) diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 71e4b79a7c..2df20c3c25 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -6155,6 +6155,158 @@ void Instruction::execute() { sourceValues_, metadata_, false); break; } + case Opcode::AArch64_USMOPA_MPPZZ_D: { // usmopa zada.d, pn/m, pm/m, + // zn.h, zm.h + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 64; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const uint16_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const int16_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLd x 4 sub matrix + // zm is a 4 x SVLd sub matrix + // Resulting SVLd x SVLd matrix has results widened to 64-bit + for (int row = 0; row < tileDim; row++) { + int64_t outRow[32] = {0}; + const int64_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + int64_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << ((znIndex % 32) * 2); + const uint64_t shifted_active_zm = 1ull << ((zmIndex % 32) * 2); + if ((pn[znIndex / 32] & shifted_active_zn) && + (pm[zmIndex / 32] & shifted_active_zm)) + sum += (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; + } + case Opcode::AArch64_USMOPA_MPPZZ_S: { // usmopa zada.s, pn/m, pm/m, + // zn.b, zm.b + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 32; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const uint8_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const int8_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLs x 4 sub matrix + // zm is a 4 x SVLs sub matrix + // Resulting SVLs x SVLs matrix has results widened to 32-bit + for (int row = 0; row < tileDim; row++) { + int32_t outRow[64] = {0}; + const int32_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + int32_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << (znIndex % 64); + const uint64_t shifted_active_zm = 1ull << (zmIndex % 64); + if ((pn[znIndex / 64] & shifted_active_zn) && + (pm[zmIndex / 64] & shifted_active_zm)) + sum += (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; + } + case Opcode::AArch64_USMOPS_MPPZZ_D: { // usmops zada.d, pn/m, pm/m, + // zn.h, zm.h + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 64; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const uint16_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const int16_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLd x 4 sub matrix + // zm is a 4 x SVLd sub matrix + // Resulting SVLd x SVLd matrix has results widened to 64-bit + for (int row = 0; row < tileDim; row++) { + int64_t outRow[32] = {0}; + const int64_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + int64_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << ((znIndex % 32) * 2); + const uint64_t shifted_active_zm = 1ull << ((zmIndex % 32) * 2); + if ((pn[znIndex / 32] & shifted_active_zn) && + (pm[zmIndex / 32] & shifted_active_zm)) + sum -= (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; + } + case Opcode::AArch64_USMOPS_MPPZZ_S: { // usmops zada.s, pn/m, pm/m, + // zn.b, zm.b + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t tileDim = VL_bits / 32; + const uint64_t* pn = sourceValues_[tileDim].getAsVector(); + const uint64_t* pm = sourceValues_[tileDim + 1].getAsVector(); + const uint8_t* zn = sourceValues_[tileDim + 2].getAsVector(); + const int8_t* zm = sourceValues_[tileDim + 3].getAsVector(); + + // zn is a SVLs x 4 sub matrix + // zm is a 4 x SVLs sub matrix + // Resulting SVLs x SVLs matrix has results widened to 32-bit + for (int row = 0; row < tileDim; row++) { + int32_t outRow[64] = {0}; + const int32_t* zadaRow = sourceValues_[row].getAsVector(); + for (int col = 0; col < tileDim; col++) { + // Get corresponding output element + int32_t sum = zadaRow[col]; + for (int k = 0; k < 4; k++) { + const uint16_t znIndex = 4 * row + k; + const uint16_t zmIndex = 4 * col + k; + const uint64_t shifted_active_zn = 1ull << (znIndex % 64); + const uint64_t shifted_active_zm = 1ull << (zmIndex % 64); + if ((pn[znIndex / 64] & shifted_active_zn) && + (pm[zmIndex / 64] & shifted_active_zm)) + sum -= (static_cast(zn[znIndex]) * + static_cast(zm[zmIndex])); + } + outRow[col] = sum; + } + results_[row] = {outRow, 256}; + } + break; + } case Opcode::AArch64_UUNPKHI_ZZ_D: { // uunpkhi zd.d, zn.s results_[0] = sveUnpk_vecs(sourceValues_, VL_bits, true); diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index 5690c6eb7f..f0e6bb4144 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -804,7 +804,7 @@ TEST_P(InstSme, sumopa) { RUN_AARCH64(R"( smstart - # z1 is signed, z2 is unsigned so will become 255 + # z1 is signed, z2 is unsigned so will become 65535 dup z1.h, #3 dup z2.h, #-1 ptrue p0.h @@ -814,7 +814,7 @@ TEST_P(InstSme, sumopa) { sumopa za0.d, p0/m, p1/m, z1.h, z2.h - # z3 is signed, z4 is unsigned so will become 254 + # z3 is signed, z4 is unsigned so will become 65534 dup z3.h, #7 dup z4.h, #-2 mov x0, #0 @@ -1089,6 +1089,254 @@ TEST_P(InstSme, umops) { } } +TEST_P(InstSme, usmopa) { + // 32-bit + RUN_AARCH64(R"( + smstart + + dup z1.b, #8 + dup z2.b, #-3 + ptrue p0.b + ptrue p1.b + + zero {za} + + usmopa za0.s, p0/m, p1/m, z1.b, z2.b + + dup z3.b, #7 + dup z4.b, #-4 + mov x0, #0 + mov x1, #2 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.b, xzr, x0 + + usmopa za2.s, p0/m, p2/m, z3.b, z4.b + )"); + for (uint64_t i = 0; i < (SVL / 32); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + fillNeon({-96}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + fillNeon({-112}, (SVL / 16))); + } + + RUN_AARCH64(R"( + smstart + + # z1 is unsigned so will become 253, z2 is signed + dup z1.b, #-3 + dup z2.b, #2 + ptrue p0.b + ptrue p1.b + + zero {za} + + usmopa za0.s, p0/m, p1/m, z1.b, z2.b + + # z3 is unsigned so will become 254, z4 is unsigned + dup z3.b, #-2 + dup z4.b, #7 + mov x0, #0 + mov x1, #2 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.b, xzr, x0 + + usmopa za2.s, p0/m, p2/m, z3.b, z4.b + )"); + for (uint64_t i = 0; i < (SVL / 32); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + fillNeon({2024}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + fillNeon({7112}, (SVL / 16))); + } + + // 64-bit + RUN_AARCH64(R"( + smstart + + dup z1.h, #8 + dup z2.h, #-3 + ptrue p0.h + ptrue p1.h + + zero {za} + + usmopa za0.d, p0/m, p1/m, z1.h, z2.h + + dup z3.h, #7 + dup z4.h, #-4 + mov x0, #0 + mov x1, #4 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.h, xzr, x0 + + usmopa za2.d, p0/m, p2/m, z3.h, z4.h + )"); + for (uint64_t i = 0; i < (SVL / 64); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + fillNeon({-96}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + fillNeon({-112}, (SVL / 16))); + } + + RUN_AARCH64(R"( + smstart + + # z1 is unsigned so will become 65533, z2 is unsigned + dup z1.h, #-3 + dup z2.h, #2 + ptrue p0.h + ptrue p1.h + + zero {za} + + usmopa za0.d, p0/m, p1/m, z1.h, z2.h + + # z3 is unsigned so will become 65534, z4 is signed + dup z3.h, #-2 + dup z4.h, #7 + mov x0, #0 + mov x1, #4 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.h, xzr, x0 + + usmopa za2.d, p0/m, p2/m, z3.h, z4.h + )"); + for (uint64_t i = 0; i < (SVL / 64); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + fillNeon({524264}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + fillNeon({1834952}, (SVL / 16))); + } +} + +TEST_P(InstSme, usmops) { + // 32-bit + RUN_AARCH64(R"( + smstart + + dup z1.b, #8 + dup z2.b, #-3 + ptrue p0.b + ptrue p1.b + + zero {za} + + usmops za0.s, p0/m, p1/m, z1.b, z2.b + + dup z3.b, #7 + dup z4.b, #-4 + mov x0, #0 + mov x1, #2 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.b, xzr, x0 + + usmops za2.s, p0/m, p2/m, z3.b, z4.b + )"); + for (uint64_t i = 0; i < (SVL / 32); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + fillNeon({96}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + fillNeon({112}, (SVL / 16))); + } + + RUN_AARCH64(R"( + smstart + + # z1 is unsigned so will become 253, z2 is signed + dup z1.b, #-3 + dup z2.b, #2 + ptrue p0.b + ptrue p1.b + + zero {za} + + usmops za0.s, p0/m, p1/m, z1.b, z2.b + + # z3 is unsigned so will become 254, z4 is signed + dup z3.b, #-2 + dup z4.b, #7 + mov x0, #0 + mov x1, #2 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.b, xzr, x0 + + usmops za2.s, p0/m, p2/m, z3.b, z4.b + )"); + for (uint64_t i = 0; i < (SVL / 32); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + fillNeon({-2024}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + fillNeon({-7112}, (SVL / 16))); + } + + // 64-bit + RUN_AARCH64(R"( + smstart + + dup z1.h, #8 + dup z2.h, #-3 + ptrue p0.h + ptrue p1.h + + zero {za} + + usmops za0.d, p0/m, p1/m, z1.h, z2.h + + dup z3.h, #7 + dup z4.h, #-4 + mov x0, #0 + mov x1, #4 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.h, xzr, x0 + + usmops za2.d, p0/m, p2/m, z3.h, z4.h + )"); + for (uint64_t i = 0; i < (SVL / 64); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + fillNeon({96}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + fillNeon({112}, (SVL / 16))); + } + + RUN_AARCH64(R"( + smstart + + # z1 is unsigned so will become 65533, z2 is signed + dup z1.h, #-3 + dup z2.h, #2 + ptrue p0.h + ptrue p1.h + + zero {za} + + usmops za0.d, p0/m, p1/m, z1.h, z2.h + + # z3 is unsigned so will become 65534, z4 is signed + dup z3.h, #-2 + dup z4.h, #7 + mov x0, #0 + mov x1, #4 + addvl x0, x0, #1 + udiv x0, x0, x1 + whilelo p2.h, xzr, x0 + + usmops za2.d, p0/m, p2/m, z3.h, z4.h + )"); + for (uint64_t i = 0; i < (SVL / 64); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + fillNeon({-524264}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + fillNeon({-1834952}, (SVL / 16))); + } +} + TEST_P(InstSme, zero) { RUN_AARCH64(R"( smstart From 565cef403886b25c2b23f0933ef7572515e14af5 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Wed, 14 Aug 2024 12:08:38 +0100 Subject: [PATCH 21/48] Fix jenkins build error pt2. --- src/lib/arch/aarch64/Instruction.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/arch/aarch64/Instruction.cc b/src/lib/arch/aarch64/Instruction.cc index b512b510d3..967a72b7ba 100644 --- a/src/lib/arch/aarch64/Instruction.cc +++ b/src/lib/arch/aarch64/Instruction.cc @@ -174,11 +174,11 @@ bool Instruction::checkStreamingGroup() { instructionGroup_ = smEnabled ? InstructionGroups::STREAMING_PREDICATE : InstructionGroups::PREDICATE; } else if (isInstruction(InsnType::isSVEData)) { - assert(((instructionGroup_ >= InstructionGroups::SVE) && - (instructionGroup_ <= InstructionGroups::STORE_SVE)) || - ((instructionGroup_ >= InstructionGroups::STREAMING_SVE) && - (instructionGroup_ <= InstructionGroups::STORE_STREAMING_SVE)) && - "Invalid instruction group for SVE instruction."); + assert(((instructionGroup_ >= InstructionGroups::SVE && + instructionGroup_ <= InstructionGroups::STORE_SVE) || + (instructionGroup_ >= InstructionGroups::STREAMING_SVE && + instructionGroup_ <= InstructionGroups::STORE_STREAMING_SVE)) && + "Invalid instruction group for SVE instruction."); // Get instruction group offset. instructionGroup_ -= (instructionGroup_ >= InstructionGroups::STREAMING_SVE) ? InstructionGroups::STREAMING_SVE From dd7ffe137931e5955fe2e5499edd59f4d526b5f8 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Wed, 14 Aug 2024 15:51:27 +0100 Subject: [PATCH 22/48] Implemented SME STR instruction and regression test. --- src/lib/arch/aarch64/Instruction_address.cc | 10 ++++ src/lib/arch/aarch64/Instruction_execute.cc | 15 +++++ test/regression/aarch64/instructions/sme.cc | 66 +++++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/src/lib/arch/aarch64/Instruction_address.cc b/src/lib/arch/aarch64/Instruction_address.cc index 357077e7b3..8a73a3fe78 100644 --- a/src/lib/arch/aarch64/Instruction_address.cc +++ b/src/lib/arch/aarch64/Instruction_address.cc @@ -1545,6 +1545,16 @@ span Instruction::generateAddresses() { setMemoryAddresses({base + (offset * partition_num), partition_num}); break; } + case Opcode::AArch64_STR_ZA: { // str za[wv, #imm], [xn|sp{, #imm, mul + // vl}] + // SME + // ZA Row count === current VL in bytes + const uint16_t zaRowCount = VL_bits / 8; + const uint64_t xn = sourceValues_[zaRowCount + 1].get(); + const uint64_t imm = metadata_.operands[1].mem.disp; + setMemoryAddresses({{xn + (imm * zaRowCount), zaRowCount}}); + break; + } case Opcode::AArch64_STR_ZXI: { // str zt, [xn{, #imm, mul vl}] const uint16_t partition_num = VL_bits / 8; diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 2df20c3c25..95e88db235 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -5349,6 +5349,21 @@ void Instruction::execute() { memoryData_[0] = RegisterValue((char*)p, partition_num); break; } + case Opcode::AArch64_STR_ZA: { // str za[wv, #imm], [xn|sp{, #imm, mul + // vl}] + // SME, STORE + // If not in right context mode, raise exception + if (!ZAenabled) return ZAdisabled(); + + const uint16_t zaRowCount = VL_bits / 8; + const uint32_t wv = sourceValues_[zaRowCount].get(); + const uint32_t imm = metadata_.operands[0].sme_index.disp; + + const uint8_t* zaRow = + sourceValues_[(wv + imm) % zaRowCount].getAsVector(); + memoryData_[0] = RegisterValue((char*)zaRow, zaRowCount); + break; + } case Opcode::AArch64_STR_ZXI: { // str zt, [xn{, #imm, mul vl}] // STORE const uint16_t partition_num = VL_bits / 8; diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index f0e6bb4144..d77b7667b1 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -709,6 +709,72 @@ TEST_P(InstSme, st1w) { } } +TEST_P(InstSme, str) { + RUN_AARCH64(R"( + smstart + + zero {za} + + dup z0.b, #2 + dup z1.b, #5 + ptrue p0.b + ptrue p1.b + + # Fill first 32-bit ZA tile with 40 in every element + umopa za0.s, p0/m, p1/m, z0.b, z1.b + + dup z0.b, #1 + dup z1.b, #5 + + # Fill third 32-bit ZA tile with 20 in every element + umopa za2.s, p0/m, p1/m, z0.b, z1.b + + mov x2, #600 + mov w12, #0 + + # ZA sub tiles are interleaved, so 0th, 4th, 8th... rows will be for za0.s + # 2nd, 6th, 10th ... rows will be for za2.s + str za[w12, #0], [x2] + str za[w12, #1], [x2, #1, mul vl] + str za[w12, #2], [x2, #2, mul vl] + str za[w12, #3], [x2, #3, mul vl] + + # Store 8th row (3rd row of za0.s) + add w12, w12, #8 + mov x3, #0 + addvl x3, x3, #4 + add x2, x2, x3 + str za[w12, #0], [x2] + + # Store 10th row (3rd row of za2.s) + add w12, w12, #2 + mov x3, #0 + addvl x3, x3, #1 + add x2, x2, x3 + str za[w12, #0], [x2] + )"); + for (uint64_t i = 0; i < (SVL / 32); i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, + fillNeon({40}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS1, i, uint32_t, + fillNeon({0}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, uint32_t, + fillNeon({20}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS3, i, uint32_t, + fillNeon({0}, (SVL / 8))); + } + const uint64_t SVL_bytes = SVL / 8; + for (uint64_t i = 0; i < (SVL / 32); i++) { + const uint64_t off = i * sizeof(uint32_t); + EXPECT_EQ(getMemoryValue(600 + off), 40); + EXPECT_EQ(getMemoryValue(600 + SVL_bytes + off), 0); + EXPECT_EQ(getMemoryValue(600 + (2 * SVL_bytes) + off), 20); + EXPECT_EQ(getMemoryValue(600 + (3 * SVL_bytes) + off), 0); + EXPECT_EQ(getMemoryValue(600 + (4 * SVL_bytes) + off), 40); + EXPECT_EQ(getMemoryValue(600 + (5 * SVL_bytes) + off), 20); + } +} + TEST_P(InstSme, sumopa) { // 32-bit RUN_AARCH64(R"( From 40228df8f8acc9815115f39f1b2b75fe73599335 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Wed, 14 Aug 2024 17:07:13 +0100 Subject: [PATCH 23/48] Fixed execution logic for vertical ST1D and ST1W SME stores. --- src/lib/arch/aarch64/Instruction_execute.cc | 79 ++++++++++----------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 95e88db235..495df64490 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -4662,7 +4662,7 @@ void Instruction::execute() { case Opcode::AArch64_ST1_MXIPXX_H_D: { // st1d {zath.d[ws, #imm]}, pg, // [{, xm, lsl #3}] // SME, STORE - // Not in right context mode. Raise exception + // If not in right context mode, raise exception if (!ZAenabled) return ZAdisabled(); const uint16_t partition_num = VL_bits / 64; @@ -4676,7 +4676,25 @@ void Instruction::execute() { const uint64_t* tileSlice = sourceValues_[sliceNum].getAsVector(); memoryData_ = sve_merge_store_data(tileSlice, pg, VL_bits); + break; + } + case Opcode::AArch64_ST1_MXIPXX_H_S: { // st1w {zath.s[ws, #imm]}, pg, + // [{, xm, lsl #2}] + // SME, STORE + // If not in right context mode, raise exception + if (!ZAenabled) return ZAdisabled(); + const uint16_t partition_num = VL_bits / 32; + const uint32_t ws = sourceValues_[partition_num].get(); + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + + const uint32_t sliceNum = + (ws + metadata_.operands[0].sme_index.disp) % partition_num; + + const uint32_t* tileSlice = + sourceValues_[sliceNum].getAsVector(); + memoryData_ = sve_merge_store_data(tileSlice, pg, VL_bits); break; } case Opcode::AArch64_ST1_MXIPXX_V_D: { // st1d {zatv.d[ws, #imm]}, pg, @@ -4693,47 +4711,28 @@ void Instruction::execute() { const uint32_t sliceNum = (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; - std::array mdata; - uint16_t md_size = 0; + std::vector memData; uint16_t index = 0; for (uint16_t x = 0; x < partition_num; x++) { uint64_t shifted_active = 1ull << ((x % 8) * 8); if (pg[x / 8] & shifted_active) { - mdata[md_size] = sourceValues_[x].getAsVector()[sliceNum]; - md_size++; - } else if (md_size) { + memData.push_back( + sourceValues_[x].getAsVector()[sliceNum]); + } else if (memData.size() > 0) { memoryData_[index] = - RegisterValue((char*)mdata.data(), md_size * 8); - md_size = 0; + RegisterValue((char*)memData.data(), memData.size() * 8); + index++; + memData.clear(); } } - if (md_size) { - memoryData_[index] = RegisterValue((char*)mdata.data(), md_size * 8); + if (memData.size() > 0) { + memoryData_[index] = + RegisterValue((char*)memData.data(), memData.size() * 8); } break; } - case Opcode::AArch64_ST1_MXIPXX_H_S: { // st1w {zath.s[ws, #imm]}, pg, - // [{, xm, LSL #2}] - // SME, STORE - // Not in right context mode. Raise exception - if (!ZAenabled) return ZAdisabled(); - - const uint16_t partition_num = VL_bits / 32; - const uint32_t ws = sourceValues_[partition_num].get(); - const uint64_t* pg = - sourceValues_[partition_num + 1].getAsVector(); - - const uint32_t sliceNum = - (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; - - const uint32_t* tileSlice = - sourceValues_[sliceNum].getAsVector(); - memoryData_ = sve_merge_store_data(tileSlice, pg, VL_bits); - - break; - } case Opcode::AArch64_ST1_MXIPXX_V_S: { // st1w {zatv.s[ws, #imm]}, pg, // [{, xm, LSL #2}] // SME, STORE @@ -4748,26 +4747,26 @@ void Instruction::execute() { const uint32_t sliceNum = (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; - std::array mdata; - uint16_t md_size = 0; + std::vector memData; uint16_t index = 0; for (uint16_t x = 0; x < partition_num; x++) { uint64_t shifted_active = 1ull << ((x % 16) * 4); if (pg[x / 16] & shifted_active) { - mdata[md_size] = sourceValues_[x].getAsVector()[sliceNum]; - md_size++; - } else if (md_size) { + memData.push_back( + sourceValues_[x].getAsVector()[sliceNum]); + } else if (memData.size() > 0) { memoryData_[index] = - RegisterValue((char*)mdata.data(), md_size * 4); - md_size = 0; + RegisterValue((char*)memData.data(), memData.size() * 4); + index++; + memData.clear(); } } - if (md_size) { - memoryData_[index] = RegisterValue((char*)mdata.data(), md_size * 4); + if (memData.size() > 0) { + memoryData_[index] = + RegisterValue((char*)memData.data(), memData.size() * 4); } - break; } case Opcode::AArch64_SST1W_D_IMM: { // st1w {zt.d}, pg, [zn.d{, #imm}] From a55e45deb7fb8fc3f54fdca06b2e6193d064a9b3 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Wed, 14 Aug 2024 17:25:45 +0100 Subject: [PATCH 24/48] Implemented SME ST1B and ST1H (H and V) instruction logic. --- src/lib/arch/aarch64/Instruction_address.cc | 42 ++++++++ src/lib/arch/aarch64/Instruction_execute.cc | 110 ++++++++++++++++++++ 2 files changed, 152 insertions(+) diff --git a/src/lib/arch/aarch64/Instruction_address.cc b/src/lib/arch/aarch64/Instruction_address.cc index 8a73a3fe78..00190a65c2 100644 --- a/src/lib/arch/aarch64/Instruction_address.cc +++ b/src/lib/arch/aarch64/Instruction_address.cc @@ -958,6 +958,27 @@ span Instruction::generateAddresses() { setMemoryAddresses(std::move(addresses)); break; } + case Opcode::AArch64_ST1_MXIPXX_H_B: // st1b {zath.b[ws, #imm]}, pg, + // [{, xm}] + case Opcode::AArch64_ST1_MXIPXX_V_B: { // st1b {zatv.b[ws, #imm]}, pg, + // [{, xm}] + // SME + const uint16_t partition_num = VL_bits / 8; + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + const uint64_t n = sourceValues_[partition_num + 2].get(); + uint64_t m = 0; + if (metadata_.operands[2].mem.index) + m = sourceValues_[partition_num + 3].get(); + + std::vector addresses; + addresses.reserve(partition_num); + + generatePredicatedContiguousAddressBlocks((n + m), partition_num, 1, 1, + pg, addresses); + setMemoryAddresses(std::move(addresses)); + break; + } case Opcode::AArch64_ST1_MXIPXX_H_D: // st1d {zath.d[ws, #imm]}, pg, // [{, xm, lsl #3}] case Opcode::AArch64_ST1_MXIPXX_V_D: { // st1d {zatv.d[ws, #imm]}, pg, @@ -979,6 +1000,27 @@ span Instruction::generateAddresses() { setMemoryAddresses(std::move(addresses)); break; } + case Opcode::AArch64_ST1_MXIPXX_H_H: // st1h {zath.h[ws, #imm]}, pg, + // [{, xm, lsl #1}] + case Opcode::AArch64_ST1_MXIPXX_V_H: { // st1h {zatv.h[ws, #imm]}, pg, + // [{, xm, lsl #1}] + // SME + const uint16_t partition_num = VL_bits / 16; + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + const uint64_t n = sourceValues_[partition_num + 2].get(); + uint64_t m = 0; + if (metadata_.operands[2].mem.index) + m = sourceValues_[partition_num + 3].get() << 1; + + std::vector addresses; + addresses.reserve(partition_num); + + generatePredicatedContiguousAddressBlocks((n + m), partition_num, 2, 2, + pg, addresses); + setMemoryAddresses(std::move(addresses)); + break; + } case Opcode::AArch64_ST1_MXIPXX_H_S: // st1w {zath.s[ws, #imm]}, pg/z, // [{, xm, LSL #2}] case Opcode::AArch64_ST1_MXIPXX_V_S: { // st1w {zatv.s[ws, #imm]}, pg/z, diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 495df64490..86d7d9bb17 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -4659,6 +4659,25 @@ void Instruction::execute() { } break; } + case Opcode::AArch64_ST1_MXIPXX_H_B: { // st1b {zath.b[ws, #imm]}, pg, + // [{, xm}] + // SME, STORE + // If not in right context mode, raise exception + if (!ZAenabled) return ZAdisabled(); + + const uint16_t partition_num = VL_bits / 8; + const uint32_t ws = sourceValues_[partition_num].get(); + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + + const uint32_t sliceNum = + (ws + metadata_.operands[0].sme_index.disp) % partition_num; + + const uint8_t* tileSlice = + sourceValues_[sliceNum].getAsVector(); + memoryData_ = sve_merge_store_data(tileSlice, pg, VL_bits); + break; + } case Opcode::AArch64_ST1_MXIPXX_H_D: { // st1d {zath.d[ws, #imm]}, pg, // [{, xm, lsl #3}] // SME, STORE @@ -4678,6 +4697,25 @@ void Instruction::execute() { memoryData_ = sve_merge_store_data(tileSlice, pg, VL_bits); break; } + case Opcode::AArch64_ST1_MXIPXX_H_H: { // st1h {zath.h[ws, #imm]}, pg, + // [{, xm, lsl #1}] + // SME, STORE + // If not in right context mode, raise exception + if (!ZAenabled) return ZAdisabled(); + + const uint16_t partition_num = VL_bits / 16; + const uint32_t ws = sourceValues_[partition_num].get(); + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + + const uint32_t sliceNum = + (ws + metadata_.operands[0].sme_index.disp) % partition_num; + + const uint16_t* tileSlice = + sourceValues_[sliceNum].getAsVector(); + memoryData_ = sve_merge_store_data(tileSlice, pg, VL_bits); + break; + } case Opcode::AArch64_ST1_MXIPXX_H_S: { // st1w {zath.s[ws, #imm]}, pg, // [{, xm, lsl #2}] // SME, STORE @@ -4697,6 +4735,42 @@ void Instruction::execute() { memoryData_ = sve_merge_store_data(tileSlice, pg, VL_bits); break; } + case Opcode::AArch64_ST1_MXIPXX_V_B: { // st1b {zatv.b[ws, #imm]}, pg, + // [{, xm}] + // SME, STORE + // Not in right context mode. Raise exception + if (!ZAenabled) return ZAdisabled(); + + const uint16_t partition_num = VL_bits / 8; + const uint32_t ws = sourceValues_[partition_num].get(); + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + + const uint32_t sliceNum = + (ws + metadata_.operands[0].sme_index.disp) % partition_num; + + std::vector memData; + uint16_t index = 0; + + for (uint16_t x = 0; x < partition_num; x++) { + uint64_t shifted_active = 1ull << (x % 64); + if (pg[x / 64] & shifted_active) { + memData.push_back( + sourceValues_[x].getAsVector()[sliceNum]); + } else if (memData.size() > 0) { + memoryData_[index] = + RegisterValue((char*)memData.data(), memData.size()); + index++; + memData.clear(); + } + } + + if (memData.size() > 0) { + memoryData_[index] = + RegisterValue((char*)memData.data(), memData.size()); + } + break; + } case Opcode::AArch64_ST1_MXIPXX_V_D: { // st1d {zatv.d[ws, #imm]}, pg, // [{, xm, lsl #3}] // SME, STORE @@ -4733,6 +4807,42 @@ void Instruction::execute() { } break; } + case Opcode::AArch64_ST1_MXIPXX_V_H: { // st1h {zatv.h[ws, #imm]}, pg, + // [{, xm, LSL #1}] + // SME, STORE + // Not in right context mode. Raise exception + if (!ZAenabled) return ZAdisabled(); + + const uint16_t partition_num = VL_bits / 16; + const uint32_t ws = sourceValues_[partition_num].get(); + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + + const uint32_t sliceNum = + (ws + metadata_.operands[0].sme_index.disp) % partition_num; + + std::vector memData; + uint16_t index = 0; + + for (uint16_t x = 0; x < partition_num; x++) { + uint64_t shifted_active = 1ull << ((x % 32) * 2); + if (pg[x / 32] & shifted_active) { + memData.push_back( + sourceValues_[x].getAsVector()[sliceNum]); + } else if (memData.size() > 0) { + memoryData_[index] = + RegisterValue((char*)memData.data(), memData.size() * 2); + index++; + memData.clear(); + } + } + + if (memData.size() > 0) { + memoryData_[index] = + RegisterValue((char*)memData.data(), memData.size() * 2); + } + break; + } case Opcode::AArch64_ST1_MXIPXX_V_S: { // st1w {zatv.s[ws, #imm]}, pg, // [{, xm, LSL #2}] // SME, STORE From b73ca9ec055d378f9ed872baf74bc254270727e7 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Thu, 15 Aug 2024 11:46:04 +0100 Subject: [PATCH 25/48] Implemented SME LD1B and LD1H (H and V) instruction logic. --- src/lib/arch/aarch64/Instruction_address.cc | 26 +++ src/lib/arch/aarch64/Instruction_execute.cc | 168 +++++++++++++++++--- 2 files changed, 168 insertions(+), 26 deletions(-) diff --git a/src/lib/arch/aarch64/Instruction_address.cc b/src/lib/arch/aarch64/Instruction_address.cc index 00190a65c2..483b673465 100644 --- a/src/lib/arch/aarch64/Instruction_address.cc +++ b/src/lib/arch/aarch64/Instruction_address.cc @@ -91,6 +91,19 @@ span Instruction::generateAddresses() { setMemoryAddresses({{sourceValues_[2].get(), 8}}); break; } + case Opcode::AArch64_LD1_MXIPXX_V_B: // ld1b {zatv.b[ws, #imm]}, pg/z, + // [{, xm}] + case Opcode::AArch64_LD1_MXIPXX_H_B: { // ld1b {zath.b[ws, #imm]}, pg/z, + // [{, xm}] + // SME + const uint16_t partition_num = VL_bits / 8; + const uint64_t n = sourceValues_[partition_num + 2].get(); + uint64_t m = 0; + if (metadata_.operands[2].mem.index) + m = sourceValues_[partition_num + 3].get(); + setMemoryAddresses({(n + m), static_cast(VL_bits / 8)}); + break; + } case Opcode::AArch64_LD1_MXIPXX_V_D: // ld1d {zatv.d[ws, #imm]}, pg/z, // [{, xm, lsl #3}] case Opcode::AArch64_LD1_MXIPXX_H_D: { // ld1d {zath.d[ws, #imm]}, pg/z, @@ -104,6 +117,19 @@ span Instruction::generateAddresses() { setMemoryAddresses({(n + m), static_cast(VL_bits / 8)}); break; } + case Opcode::AArch64_LD1_MXIPXX_V_H: // ld1h {zatv.h[ws, #imm]}, pg/z, + // [{, xm, lsl #1}] + case Opcode::AArch64_LD1_MXIPXX_H_H: { // ld1h {zath.h[ws, #imm]}, pg/z, + // [{, xm, lsl #1}] + // SME + const uint16_t partition_num = VL_bits / 16; + const uint64_t n = sourceValues_[partition_num + 2].get(); + uint64_t m = 0; + if (metadata_.operands[2].mem.index) + m = sourceValues_[partition_num + 3].get() << 1; + setMemoryAddresses({(n + m), static_cast(VL_bits / 8)}); + break; + } case Opcode::AArch64_LD1_MXIPXX_V_S: // ld1w {zatv.s[ws, #imm]}, pg/z, // [{, xm, LSL #2}] case Opcode::AArch64_LD1_MXIPXX_H_S: { // ld1w {zath.s[ws, #imm]}, pg/z, diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 86d7d9bb17..d60048c59c 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -2621,10 +2621,43 @@ void Instruction::execute() { vecInsIndex_gpr(sourceValues_, metadata_); break; } + case Opcode::AArch64_LD1_MXIPXX_H_B: { // ld1b {zath.b[ws, #imm]}, pg/z, + // [{, xm}] + // SME, LOAD + // If not in right context mode, raise exception + if (!ZAenabled) return ZAdisabled(); + + const uint16_t partition_num = VL_bits / 8; + const uint32_t ws = sourceValues_[partition_num].get(); + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + + const uint16_t sliceNum = + (ws + metadata_.operands[0].sme_index.disp) % partition_num; + const uint8_t* data = memoryData_[0].getAsVector(); + + uint8_t out[256] = {0}; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << (i % 64); + if (pg[i / 64] & shifted_active) { + out[i] = data[i]; + } else { + out[i] = 0; + } + } + + // All Slice vectors are added to results[] so need to update the + // correct one + for (uint16_t i = 0; i < partition_num; i++) { + results_[i] = sourceValues_[i]; + } + results_[sliceNum] = {out, 256}; + break; + } case Opcode::AArch64_LD1_MXIPXX_H_D: { // ld1d {zath.d[ws, #imm]}, pg/z, // [{, xm, lsl #3}] // SME, LOAD - // Not in right context mode. Raise exception + // If not in right context mode, raise exception if (!ZAenabled) return ZAdisabled(); const uint16_t partition_num = VL_bits / 64; @@ -2649,46 +2682,48 @@ void Instruction::execute() { // All Slice vectors are added to results[] so need to update the // correct one for (uint16_t i = 0; i < partition_num; i++) { - if (i == sliceNum) - results_[i] = {out, 256}; - else - // Maintain un-updated rows. - results_[i] = sourceValues_[i]; + results_[i] = sourceValues_[i]; } + results_[sliceNum] = {out, 256}; break; } - case Opcode::AArch64_LD1_MXIPXX_V_D: { // ld1d {zatv.d[ws, #imm]}, pg/z, - // [{, xm, lsl #3}] + case Opcode::AArch64_LD1_MXIPXX_H_H: { // ld1h {zath.h[ws, #imm]}, pg/z, + // [{, xm, LSL #1}] // SME, LOAD - // Not in right context mode. Raise exception + // If not in right context mode, raise exception if (!ZAenabled) return ZAdisabled(); - const uint16_t partition_num = VL_bits / 64; + const uint16_t partition_num = VL_bits / 16; const uint32_t ws = sourceValues_[partition_num].get(); const uint64_t* pg = sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; - const uint64_t* data = memoryData_[0].getAsVector(); + const uint16_t* data = memoryData_[0].getAsVector(); + uint16_t out[128] = {0}; for (int i = 0; i < partition_num; i++) { - uint64_t* row = - const_cast(sourceValues_[i].getAsVector()); - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (pg[i / 8] & shifted_active) { - row[sliceNum] = data[i]; + uint64_t shifted_active = 1ull << ((i % 32) * 2); + if (pg[i / 32] & shifted_active) { + out[i] = data[i]; } else { - row[sliceNum] = 0; + out[i] = 0; } - results_[i] = RegisterValue(reinterpret_cast(row), 256); } + + // All Slice vectors are added to results[] so need to update the + // correct one + for (uint16_t i = 0; i < partition_num; i++) { + results_[i] = sourceValues_[i]; + } + results_[sliceNum] = {out, 256}; break; } case Opcode::AArch64_LD1_MXIPXX_H_S: { // ld1w {zath.s[ws, #imm]}, pg/z, // [{, xm, LSL #2}] // SME, LOAD - // Not in right context mode. Raise exception + // If not in right context mode, raise exception if (!ZAenabled) return ZAdisabled(); const uint16_t partition_num = VL_bits / 32; @@ -2712,19 +2747,100 @@ void Instruction::execute() { // All Slice vectors are added to results[] so need to update the // correct one - for (uint32_t i = 0; i < partition_num; i++) { - if (i == sliceNum) - results_[i] = {out, 256}; - else - // Maintain un-updated rows. - results_[i] = sourceValues_[i]; + for (uint16_t i = 0; i < partition_num; i++) { + results_[i] = sourceValues_[i]; + } + results_[sliceNum] = {out, 256}; + break; + } + case Opcode::AArch64_LD1_MXIPXX_V_B: { // ld1b {zatv.b[ws, #imm]}, pg/z, + // [{, xm}] + // SME, LOAD + // If not in right context mode, raise exception + if (!ZAenabled) return ZAdisabled(); + + const uint16_t partition_num = VL_bits / 8; + const uint32_t ws = sourceValues_[partition_num].get(); + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + + const uint32_t sliceNum = + (ws + metadata_.operands[0].sme_index.disp) % partition_num; + const uint8_t* data = memoryData_[0].getAsVector(); + + for (int i = 0; i < partition_num; i++) { + uint8_t* row = + const_cast(sourceValues_[i].getAsVector()); + uint64_t shifted_active = 1ull << (i % 64); + if (pg[i / 64] & shifted_active) { + row[sliceNum] = data[i]; + } else { + row[sliceNum] = 0; + } + results_[i] = RegisterValue(reinterpret_cast(row), 256); + } + break; + } + case Opcode::AArch64_LD1_MXIPXX_V_D: { // ld1d {zatv.d[ws, #imm]}, pg/z, + // [{, xm, lsl #3}] + // SME, LOAD + // If not in right context mode, raise exception + if (!ZAenabled) return ZAdisabled(); + + const uint16_t partition_num = VL_bits / 64; + const uint32_t ws = sourceValues_[partition_num].get(); + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + + const uint32_t sliceNum = + (ws + metadata_.operands[0].sme_index.disp) % partition_num; + const uint64_t* data = memoryData_[0].getAsVector(); + + for (int i = 0; i < partition_num; i++) { + uint64_t* row = + const_cast(sourceValues_[i].getAsVector()); + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (pg[i / 8] & shifted_active) { + row[sliceNum] = data[i]; + } else { + row[sliceNum] = 0; + } + results_[i] = RegisterValue(reinterpret_cast(row), 256); + } + break; + } + case Opcode::AArch64_LD1_MXIPXX_V_H: { // ld1h {zatv.h[ws, #imm]}, pg/z, + // [{, xm, lsl #1}] + // SME, LOAD + // If not in right context mode, raise exception + if (!ZAenabled) return ZAdisabled(); + + const uint16_t partition_num = VL_bits / 16; + const uint32_t ws = sourceValues_[partition_num].get(); + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + + const uint32_t sliceNum = + (ws + metadata_.operands[0].sme_index.disp) % partition_num; + const uint16_t* data = memoryData_[0].getAsVector(); + + for (int i = 0; i < partition_num; i++) { + uint16_t* row = + const_cast(sourceValues_[i].getAsVector()); + uint64_t shifted_active = 1ull << ((i % 32) * 2); + if (pg[i / 32] & shifted_active) { + row[sliceNum] = data[i]; + } else { + row[sliceNum] = 0; + } + results_[i] = RegisterValue(reinterpret_cast(row), 256); } break; } case Opcode::AArch64_LD1_MXIPXX_V_S: { // ld1w {zatv.s[ws, #imm]}, pg/z, // [{, xm, LSL #2}] // SME, LOAD - // Not in right context mode. Raise exception + // If not in right context mode, raise exception if (!ZAenabled) return ZAdisabled(); const uint16_t partition_num = VL_bits / 32; From 9461680d120cdf9ace6b66264108a13f5054b395 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Thu, 15 Aug 2024 14:04:06 +0100 Subject: [PATCH 26/48] Added SME LD1B and LD1H regression tests. --- test/regression/aarch64/instructions/sme.cc | 205 ++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index d77b7667b1..8f08523d63 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -172,6 +172,109 @@ TEST_P(InstSme, fmops) { } } +TEST_P(InstSme, ld1b) { + // Horizontal + initialHeapData_.resize(SVL / 4); + uint8_t* heap8 = reinterpret_cast(initialHeapData_.data()); + std::vector src = {0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, + 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}; + fillHeap(heap8, src, SVL / 4); + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + mov x1, #1 + ptrue p0.b + mov w12, #1 + # Load and broadcast values from heap + ld1b {za0h.b[w12, 0]}, p0/z, [x0, x1] + ld1b {za0h.b[w12, 2]}, p0/z, [x0] + + # Test for inactive lanes + mov x1, #0 + mov x3, #2 + # TODO change to addsvl when implemented + addvl x1, x1, #1 + udiv x1, x1, x3 + mov x2, #0 + whilelo p1.b, xzr, x1 + mov w12, #15 + ld1b {za0h.b[w12, 0]}, p1/z, [x0, x2] + )"); + CHECK_MAT_ROW( + ARM64_REG_ZAB0, 1, uint8_t, + fillNeon({0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, 0x76, + 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01, 0xDE}, + SVL / 8)); + CHECK_MAT_ROW( + ARM64_REG_ZAB0, 3, uint8_t, + fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, + 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, + SVL / 8)); + CHECK_MAT_ROW(ARM64_REG_ZAB0, 15, uint8_t, + fillNeonCombined( + {0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, 0x76, + 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, + {0}, SVL / 8)); + + // Vertical + initialHeapData_.resize(SVL / 4); + uint8_t* heap8_vert = reinterpret_cast(initialHeapData_.data()); + std::vector src_vert = {0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, + 0x56, 0x78, 0x98, 0x76, 0x54, 0x32, + 0xAB, 0xCD, 0xEF, 0x01}; + fillHeap(heap8_vert, src_vert, SVL / 4); + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + mov x1, #1 + ptrue p0.b + mov w12, #1 + # Load and broadcast values from heap + ld1b {za0v.b[w12, 0]}, p0/z, [x0, x1] + ld1b {za0v.b[w12, 2]}, p0/z, [x0] + + # Test for inactive lanes + mov x1, #0 + mov x3, #2 + # TODO change to addsvl when implemented + addvl x1, x1, #1 + udiv x1, x1, x3 + mov x2, #0 + whilelo p1.b, xzr, x1 + mov w12, #15 + ld1b {za0v.b[w12, 0]}, p1/z, [x0, x2] + )"); + CHECK_MAT_COL( + ARM64_REG_ZAB0, 1, uint8_t, + fillNeon({0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, 0x76, + 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01, 0xDE}, + SVL / 8)); + CHECK_MAT_COL( + ARM64_REG_ZAB0, 3, uint8_t, + fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, + 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, + SVL / 8)); + CHECK_MAT_COL(ARM64_REG_ZAB0, 15, uint8_t, + fillNeonCombined( + {0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, 0x76, + 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, + {0}, SVL / 8)); +} + TEST_P(InstSme, ld1d) { // Horizontal initialHeapData_.resize(SVL / 4); @@ -186,6 +289,8 @@ TEST_P(InstSme, ld1d) { smstart + zero {za} + mov x1, #1 ptrue p0.d mov w12, #0 @@ -226,6 +331,8 @@ TEST_P(InstSme, ld1d) { smstart + zero {za} + mov x1, #1 ptrue p0.d mov w12, #0 @@ -254,6 +361,100 @@ TEST_P(InstSme, ld1d) { {0xDEADBEEF12345678, 0x98765432ABCDEF01}, {0}, SVL / 8)); } +TEST_P(InstSme, ld1h) { + // Horizontal + initialHeapData_.resize(SVL / 4); + uint16_t* heap16 = reinterpret_cast(initialHeapData_.data()); + std::vector src = {0xDEAD, 0xBEEF, 0x1234, 0x5678, + 0x9876, 0x5432, 0xABCD, 0xEF01}; + fillHeap(heap16, src, SVL / 8); + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + mov x1, #1 + ptrue p0.h + mov w12, #1 + # Load and broadcast values from heap + ld1h {za0h.h[w12, 0]}, p0/z, [x0, x1, lsl #1] + ld1h {za0h.h[w12, 2]}, p0/z, [x0] + + # Test for inactive lanes + mov x1, #0 + mov x3, #4 + # TODO change to addsvl when implemented + addvl x1, x1, #1 + udiv x1, x1, x3 + mov x2, #0 + whilelo p1.h, xzr, x1 + ld1h {za1h.h[w12, 0]}, p1/z, [x0, x2, lsl #1] + )"); + CHECK_MAT_ROW(ARM64_REG_ZAH0, 1, uint16_t, + fillNeon({0xBEEF, 0x1234, 0x5678, 0x9876, 0x5432, + 0xABCD, 0xEF01, 0xDEAD}, + SVL / 8)); + CHECK_MAT_ROW(ARM64_REG_ZAH0, 3, uint16_t, + fillNeon({0xDEAD, 0xBEEF, 0x1234, 0x5678, 0x9876, + 0x5432, 0xABCD, 0xEF01}, + SVL / 8)); + CHECK_MAT_ROW(ARM64_REG_ZAH1, 1, uint16_t, + fillNeonCombined({0xDEAD, 0xBEEF, 0x1234, 0x5678, + 0x9876, 0x5432, 0xABCD, 0xEF01}, + {0}, SVL / 8)); + + // Vertical + initialHeapData_.resize(SVL / 4); + uint16_t* heap16_vert = reinterpret_cast(initialHeapData_.data()); + std::vector src_vert = {0xDEAD, 0xBEEF, 0x1234, 0x5678, + 0x9876, 0x5432, 0xABCD, 0xEF01}; + fillHeap(heap16_vert, src_vert, SVL / 8); + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + mov x1, #1 + ptrue p0.h + mov w12, #1 + # Load and broadcast values from heap + ld1h {za0v.h[w12, 0]}, p0/z, [x0, x1, lsl #1] + ld1h {za0v.h[w12, 2]}, p0/z, [x0] + + # Test for inactive lanes + mov x1, #0 + mov x3, #4 + # TODO change to addsvl when implemented + addvl x1, x1, #1 + udiv x1, x1, x3 + mov x2, #0 + whilelo p1.h, xzr, x1 + ld1h {za1v.h[w12, 0]}, p1/z, [x0, x2, lsl #1] + )"); + CHECK_MAT_COL(ARM64_REG_ZAH0, 1, uint16_t, + fillNeon({0xBEEF, 0x1234, 0x5678, 0x9876, 0x5432, + 0xABCD, 0xEF01, 0xDEAD}, + SVL / 8)); + CHECK_MAT_COL(ARM64_REG_ZAH0, 3, uint16_t, + fillNeon({0xDEAD, 0xBEEF, 0x1234, 0x5678, 0x9876, + 0x5432, 0xABCD, 0xEF01}, + SVL / 8)); + CHECK_MAT_COL(ARM64_REG_ZAH1, 1, uint16_t, + fillNeonCombined({0xDEAD, 0xBEEF, 0x1234, 0x5678, + 0x9876, 0x5432, 0xABCD, 0xEF01}, + {0}, SVL / 8)); +} + TEST_P(InstSme, ld1w) { // Horizontal initialHeapData_.resize(SVL / 4); @@ -268,6 +469,8 @@ TEST_P(InstSme, ld1w) { smstart + zero {za} + mov x1, #1 ptrue p0.s mov w12, #1 @@ -309,6 +512,8 @@ TEST_P(InstSme, ld1w) { smstart + zero {za} + mov x1, #1 ptrue p0.s mov w12, #1 From a3ba5071ceba5b3a96a1c6085312ff4edaaa5b3c Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Thu, 15 Aug 2024 15:17:37 +0100 Subject: [PATCH 27/48] Updated ST1D and ST1W SME regression tests. --- test/regression/aarch64/instructions/sme.cc | 138 +++++++++++++------- 1 file changed, 94 insertions(+), 44 deletions(-) diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index 8f08523d63..a50681c08c 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -709,24 +709,36 @@ TEST_P(InstSme, st1d) { smstart - mov x2, #0 - mov x4, #16 - addvl x2, x2, #1 - udiv x2, x2, x4 + zero {za} + mov x3, #2 - whilelo p1.d, xzr, x2 - mov x5, #800 + ptrue p0.d + pfalse p1.b + zip1 p1.d, p0.d, p1.d + mov x5, #400 + mov x6, #800 mov w12, #0 mov w13, #1 - ld1d {za3h.d[w12, 0]}, p1/z, [x0, x3, lsl #3] + # Load entire row + ld1d {za3h.d[w12, 0]}, p0/z, [x0, x3, lsl #3] + # Store all 0s to memory + st1d {za0h.d[w12, 0]}, p0, [x5] + # Store odd indexed elements to memory st1d {za3h.d[w12, 0]}, p1, [x5] - ld1d {za1h.d[w13, 1]}, p1/z, [x0, x3, lsl #3] - st1d {za1h.d[w13, 1]}, p1, [x5, x3, lsl #3] + + # Load entire row + ld1d {za1h.d[w13, 1]}, p0/z, [x0, x3, lsl #3] + # Store all 0s to memory + st1d {za0h.d[w12, 0]}, p0, [x6, x3, lsl #3] + # Store odd indexed elements to memory + st1d {za1h.d[w13, 1]}, p1, [x6, x3, lsl #3] )"); - for (uint64_t i = 0; i < (SVL / 128); i++) { - EXPECT_EQ(getMemoryValue(800 + (i * 8)), src[i % 2]); + for (uint64_t i = 0; i < (SVL / 64); i += 2) { + EXPECT_EQ(getMemoryValue(400 + (i * 8)), src[i % 2]); + EXPECT_EQ(getMemoryValue(400 + ((i + 1) * 8)), 0); EXPECT_EQ(getMemoryValue(800 + 16 + (i * 8)), src[i % 2]); + EXPECT_EQ(getMemoryValue(800 + 16 + ((i + 1) * 8)), 0); } // Vertical @@ -770,24 +782,36 @@ TEST_P(InstSme, st1d) { smstart - mov x2, #0 - mov x4, #16 - addvl x2, x2, #1 - udiv x2, x2, x4 + zero {za} + mov x3, #2 - whilelo p1.d, xzr, x2 - mov x5, #800 + ptrue p0.d + pfalse p1.b + zip1 p1.d, p0.d, p1.d + mov x5, #400 + mov x6, #800 mov w12, #0 mov w13, #1 - ld1d {za3v.d[w12, 0]}, p1/z, [x0, x3, lsl #3] + # Load entire row + ld1d {za3v.d[w12, 0]}, p0/z, [x0, x3, lsl #3] + # Store all 0s to memory + st1d {za0v.d[w12, 0]}, p0, [x5] + # Store odd indexed elements to memory st1d {za3v.d[w12, 0]}, p1, [x5] - ld1d {za1v.d[w13, 1]}, p1/z, [x0, x3, lsl #3] - st1d {za1v.d[w13, 1]}, p1, [x5, x3, lsl #3] + + # Load entire row + ld1d {za1v.d[w13, 1]}, p0/z, [x0, x3, lsl #3] + # Store all 0s to memory + st1d {za0v.d[w12, 0]}, p0, [x6, x3, lsl #3] + # Store odd indexed elements to memory + st1d {za1v.d[w13, 1]}, p1, [x6, x3, lsl #3] )"); - for (uint64_t i = 0; i < (SVL / 128); i++) { - EXPECT_EQ(getMemoryValue(800 + (i * 8)), src_vert[i % 2]); + for (uint64_t i = 0; i < (SVL / 64); i += 2) { + EXPECT_EQ(getMemoryValue(400 + (i * 8)), src_vert[i % 2]); + EXPECT_EQ(getMemoryValue(400 + ((i + 1) * 8)), 0); EXPECT_EQ(getMemoryValue(800 + 16 + (i * 8)), src_vert[i % 2]); + EXPECT_EQ(getMemoryValue(800 + 16 + ((i + 1) * 8)), 0); } } @@ -833,23 +857,36 @@ TEST_P(InstSme, st1w) { smstart - mov x2, #0 - mov x4, #8 - addvl x2, x2, #1 - udiv x2, x2, x4 + zero {za} + mov x3, #4 - whilelo p1.s, xzr, x2 - mov x5, #800 + ptrue p0.s + pfalse p1.b + zip1 p1.s, p0.s, p1.s + mov x5, #400 + mov x6, #800 mov w12, #0 - ld1w {za3h.s[w12, 0]}, p1/z, [x0, x3, lsl #2] + mov w13, #1 + # Load entire row + ld1w {za3h.s[w12, 0]}, p0/z, [x0, x3, lsl #2] + # Store all 0s to memory + st1w {za0h.s[w12, 0]}, p0, [x5] + # Store odd indexed elements to memory st1w {za3h.s[w12, 0]}, p1, [x5] - ld1w {za1h.s[w12, 2]}, p1/z, [x0, x3, lsl #2] - st1w {za1h.s[w12, 2]}, p1, [x5, x3, lsl #2] + + # Load entire row + ld1w {za1h.s[w13, 1]}, p0/z, [x0, x3, lsl #2] + # Store all 0s to memory + st1w {za0h.s[w12, 0]}, p0, [x6, x3, lsl #2] + # Store odd indexed elements to memory + st1w {za1h.s[w13, 1]}, p1, [x6, x3, lsl #2] )"); - for (uint64_t i = 0; i < (SVL / 64); i++) { - EXPECT_EQ(getMemoryValue(800 + (i * 4)), src[i % 4]); + for (uint64_t i = 0; i < (SVL / 32); i += 2) { + EXPECT_EQ(getMemoryValue(400 + (i * 4)), src[i % 4]); + EXPECT_EQ(getMemoryValue(400 + ((i + 1) * 4)), 0); EXPECT_EQ(getMemoryValue(800 + 16 + (i * 4)), src[i % 4]); + EXPECT_EQ(getMemoryValue(800 + 16 + ((i + 1) * 4)), 0); } // Vertical @@ -894,23 +931,36 @@ TEST_P(InstSme, st1w) { smstart - mov x2, #0 - mov x4, #8 - addvl x2, x2, #1 - udiv x2, x2, x4 + zero {za} + mov x3, #4 - whilelo p1.s, xzr, x2 - mov x5, #800 + ptrue p0.s + pfalse p1.b + zip1 p1.s, p0.s, p1.s + mov x5, #400 + mov x6, #800 mov w12, #0 - ld1w {za3v.s[w12, 0]}, p1/z, [x0, x3, lsl #2] + mov w13, #1 + # Load entire row + ld1w {za3v.s[w12, 0]}, p0/z, [x0, x3, lsl #2] + # Store all 0s to memory + st1w {za0v.s[w12, 0]}, p0, [x5] + # Store odd indexed elements to memory st1w {za3v.s[w12, 0]}, p1, [x5] - ld1w {za1v.s[w12, 2]}, p1/z, [x0, x3, lsl #2] - st1w {za1v.s[w12, 2]}, p1, [x5, x3, lsl #2] + + # Load entire row + ld1w {za1v.s[w13, 1]}, p0/z, [x0, x3, lsl #2] + # Store all 0s to memory + st1w {za0v.s[w12, 0]}, p0, [x6, x3, lsl #2] + # Store odd indexed elements to memory + st1w {za1v.s[w13, 1]}, p1, [x6, x3, lsl #2] )"); - for (uint64_t i = 0; i < (SVL / 64); i++) { - EXPECT_EQ(getMemoryValue(800 + (i * 4)), src_vert[i % 4]); + for (uint64_t i = 0; i < (SVL / 32); i += 2) { + EXPECT_EQ(getMemoryValue(400 + (i * 4)), src_vert[i % 4]); + EXPECT_EQ(getMemoryValue(400 + ((i + 1) * 4)), 0); EXPECT_EQ(getMemoryValue(800 + 16 + (i * 4)), src_vert[i % 4]); + EXPECT_EQ(getMemoryValue(800 + 16 + ((i + 1) * 4)), 0); } } From e9d4cf2e66db515a3c144291595fe1477af17050 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Thu, 15 Aug 2024 15:37:13 +0100 Subject: [PATCH 28/48] Added SME ST1B and ST1H regression tests. --- test/regression/aarch64/instructions/sme.cc | 317 ++++++++++++++++++++ 1 file changed, 317 insertions(+) diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index a50681c08c..970f8c5ddb 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -667,6 +667,161 @@ TEST_P(InstSme, smops) { } } +TEST_P(InstSme, st1b) { + // Horizontal + initialHeapData_.resize(SVL / 4); + uint8_t* heap8 = reinterpret_cast(initialHeapData_.data()); + std::vector src = {0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, + 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}; + fillHeap(heap8, src, SVL / 4); + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + sub sp, sp, #4095 + mov x1, #0 + mov x4, #0 + addvl x4, x4, #1 + ptrue p0.b + + mov w12, #0 + ld1b {za0h.b[w12, 0]}, p0/z, [x0, x1] + ld1b {za0h.b[w12, 3]}, p0/z, [x0, x1] + st1b {za0h.b[w12, 0]}, p0, [sp, x1] + st1b {za0h.b[w12, 3]}, p0, [x4] + )"); + for (uint64_t i = 0; i < (SVL / 8); i++) { + EXPECT_EQ( + getMemoryValue(process_->getInitialStackPointer() - 4095 + i), + src[i % 16]); + EXPECT_EQ(getMemoryValue((SVL / 8) + i), src[i % 16]); + } + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + mov x3, #16 + ptrue p0.b + pfalse p1.b + zip1 p1.b, p0.b, p1.b + mov x5, #400 + mov x6, #800 + + mov w12, #0 + mov w13, #1 + # Load entire row + ld1b {za0h.b[w12, 0]}, p0/z, [x0, x3] + # Store all 0s to memory + st1b {za0h.b[w12, 5]}, p0, [x5] + # Store odd indexed elements to memory + st1b {za0h.b[w12, 0]}, p1, [x5] + + # Load entire row + ld1b {za0h.b[w13, 1]}, p0/z, [x0, x3] + # Store all 0s to memory + st1b {za0h.b[w12, 5]}, p0, [x6, x3] + # Store odd indexed elements to memory + st1b {za0h.b[w13, 1]}, p1, [x6, x3] + )"); + for (uint64_t i = 0; i < (SVL / 8); i += 2) { + EXPECT_EQ(getMemoryValue(400 + i), src[i % 16]); + EXPECT_EQ(getMemoryValue(400 + (i + 1)), 0); + EXPECT_EQ(getMemoryValue(800 + 16 + i), src[i % 16]); + EXPECT_EQ(getMemoryValue(800 + 16 + (i + 1)), 0); + } + + // Vertical + initialHeapData_.resize(SVL / 4); + uint8_t* heap8_vert = reinterpret_cast(initialHeapData_.data()); + std::vector src_vert = {0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, + 0x56, 0x78, 0x98, 0x76, 0x54, 0x32, + 0xAB, 0xCD, 0xEF, 0x01}; + fillHeap(heap8_vert, src_vert, SVL / 4); + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + sub sp, sp, #4095 + mov x1, #0 + mov x4, #0 + addvl x4, x4, #1 + ptrue p0.b + + mov w12, #0 + ld1b {za0v.b[w12, 0]}, p0/z, [x0, x1] + ld1b {za0v.b[w12, 1]}, p0/z, [x0, x1] + st1b {za0v.b[w12, 0]}, p0, [sp, x1] + st1b {za0v.b[w12, 1]}, p0, [x4] + )"); + for (uint64_t i = 0; i < (SVL / 8); i++) { + EXPECT_EQ( + getMemoryValue(process_->getInitialStackPointer() - 4095 + i), + src_vert[i % 16]); + EXPECT_EQ(getMemoryValue((SVL / 8) + i), src_vert[i % 16]); + } + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + mov x3, #16 + ptrue p0.b + pfalse p1.b + zip1 p1.b, p0.b, p1.b + mov x5, #400 + mov x6, #800 + + mov w12, #0 + mov w13, #1 + # Load entire row + ld1b {za0v.b[w12, 0]}, p0/z, [x0, x3] + # Store all 0s to memory + st1b {za0v.b[w12, 5]}, p0, [x5] + # Store odd indexed elements to memory + st1b {za0v.b[w12, 0]}, p1, [x5] + + # Load entire row + ld1b {za0v.b[w13, 1]}, p0/z, [x0, x3] + # Store all 0s to memory + st1b {za0v.b[w12, 5]}, p0, [x6, x3] + # Store odd indexed elements to memory + st1b {za0v.b[w13, 1]}, p1, [x6, x3] + )"); + for (uint64_t i = 0; i < (SVL / 8); i += 2) { + EXPECT_EQ(getMemoryValue(400 + i), src[i % 16]); + EXPECT_EQ(getMemoryValue(400 + (i + 1)), 0); + EXPECT_EQ(getMemoryValue(800 + 16 + i), src[i % 16]); + EXPECT_EQ(getMemoryValue(800 + 16 + (i + 1)), 0); + } +} + TEST_P(InstSme, st1d) { // Horizontal initialHeapData_.resize(SVL / 4); @@ -682,6 +837,8 @@ TEST_P(InstSme, st1d) { smstart + zero {za} + sub sp, sp, #4095 mov x1, #0 mov x4, #0 @@ -755,6 +912,8 @@ TEST_P(InstSme, st1d) { smstart + zero {za} + sub sp, sp, #4095 mov x1, #0 mov x4, #0 @@ -815,6 +974,160 @@ TEST_P(InstSme, st1d) { } } +TEST_P(InstSme, st1h) { + // Horizontal + initialHeapData_.resize(SVL / 4); + uint16_t* heap16 = reinterpret_cast(initialHeapData_.data()); + std::vector src = {0xDEAD, 0xBEEF, 0x1234, 0x5678, + 0x9876, 0x5432, 0xABCD, 0xEF01}; + fillHeap(heap16, src, SVL / 8); + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + sub sp, sp, #4095 + mov x1, #0 + mov x4, #0 + addvl x4, x4, #1 + ptrue p0.h + + mov w12, #0 + ld1h {za0h.h[w12, 0]}, p0/z, [x0, x1, lsl #1] + ld1h {za1h.h[w12, 1]}, p0/z, [x0, x1, lsl #1] + st1h {za0h.h[w12, 0]}, p0, [sp, x1, lsl #1] + st1h {za1h.h[w12, 1]}, p0, [x4] + )"); + for (uint64_t i = 0; i < (SVL / 16); i++) { + EXPECT_EQ(getMemoryValue(process_->getInitialStackPointer() - + 4095 + (i * 2)), + src[i % 8]); + EXPECT_EQ(getMemoryValue((SVL / 8) + (i * 2)), src[i % 8]); + } + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + mov x3, #8 + ptrue p0.h + pfalse p1.b + zip1 p1.h, p0.h, p1.h + mov x5, #400 + mov x6, #800 + + mov w12, #0 + mov w13, #1 + # Load entire row + ld1h {za0h.h[w12, 0]}, p0/z, [x0, x3, lsl #1] + # Store all 0s to memory + st1h {za1h.h[w12, 0]}, p0, [x5] + # Store odd indexed elements to memory + st1h {za0h.h[w12, 0]}, p1, [x5] + + # Load entire row + ld1h {za0h.h[w13, 1]}, p0/z, [x0, x3, lsl #1] + # Store all 0s to memory + st1h {za1h.h[w12, 0]}, p0, [x6, x3, lsl #1] + # Store odd indexed elements to memory + st1h {za0h.h[w13, 1]}, p1, [x6, x3, lsl #1] + )"); + for (uint64_t i = 0; i < (SVL / 16); i += 2) { + EXPECT_EQ(getMemoryValue(400 + (i * 2)), src[i % 8]); + EXPECT_EQ(getMemoryValue(400 + ((i + 1) * 2)), 0); + EXPECT_EQ(getMemoryValue(800 + 16 + (i * 2)), src[i % 8]); + EXPECT_EQ(getMemoryValue(800 + 16 + ((i + 1) * 2)), 0); + } + + // Vertical + initialHeapData_.resize(SVL / 4); + uint16_t* heap16_vert = reinterpret_cast(initialHeapData_.data()); + std::vector src_vert = {0xDEAD, 0xBEEF, 0x1234, 0x5678, + 0x9876, 0x5432, 0xABCD, 0xEF01}; + fillHeap(heap16_vert, src_vert, SVL / 8); + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + sub sp, sp, #4095 + mov x1, #0 + mov x4, #0 + addvl x4, x4, #1 + ptrue p0.h + + mov w12, #0 + ld1h {za0v.h[w12, 0]}, p0/z, [x0, x1, lsl #1] + ld1h {za1v.h[w12, 1]}, p0/z, [x0, x1, lsl #1] + st1h {za0v.h[w12, 0]}, p0, [sp, x1, lsl #1] + st1h {za1v.h[w12, 1]}, p0, [x4] + )"); + for (uint64_t i = 0; i < (SVL / 16); i++) { + EXPECT_EQ(getMemoryValue(process_->getInitialStackPointer() - + 4095 + (i * 2)), + src_vert[i % 8]); + EXPECT_EQ(getMemoryValue((SVL / 8) + (i * 2)), src_vert[i % 8]); + } + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + mov x3, #8 + ptrue p0.h + pfalse p1.b + zip1 p1.h, p0.h, p1.h + mov x5, #400 + mov x6, #800 + + mov w12, #0 + mov w13, #1 + # Load entire row + ld1h {za0v.h[w12, 0]}, p0/z, [x0, x3, lsl #1] + # Store all 0s to memory + st1h {za1v.h[w12, 0]}, p0, [x5] + # Store odd indexed elements to memory + st1h {za0v.h[w12, 0]}, p1, [x5] + + # Load entire row + ld1h {za0v.h[w13, 1]}, p0/z, [x0, x3, lsl #1] + # Store all 0s to memory + st1h {za1v.h[w12, 0]}, p0, [x6, x3, lsl #1] + # Store odd indexed elements to memory + st1h {za0v.h[w13, 1]}, p1, [x6, x3, lsl #1] + )"); + for (uint64_t i = 0; i < (SVL / 16); i += 2) { + EXPECT_EQ(getMemoryValue(400 + (i * 2)), src[i % 8]); + EXPECT_EQ(getMemoryValue(400 + ((i + 1) * 2)), 0); + EXPECT_EQ(getMemoryValue(800 + 16 + (i * 2)), src[i % 8]); + EXPECT_EQ(getMemoryValue(800 + 16 + ((i + 1) * 2)), 0); + } +} + TEST_P(InstSme, st1w) { // Horizontal initialHeapData_.resize(SVL / 4); @@ -830,6 +1143,8 @@ TEST_P(InstSme, st1w) { smstart + zero {za} + sub sp, sp, #4095 mov x1, #0 mov x4, #0 @@ -904,6 +1219,8 @@ TEST_P(InstSme, st1w) { smstart + zero {za} + sub sp, sp, #4095 mov x1, #0 mov x4, #0 From faf54a7e8f4e9a9d385cd2c3df65fca6acd7216c Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Thu, 15 Aug 2024 16:27:43 +0100 Subject: [PATCH 29/48] Implemented SME MOVA (Tile to Vec, horizontal) instructions and regression test (B, H, S, D) --- src/lib/arch/aarch64/Instruction_execute.cc | 93 ++++++++- test/regression/aarch64/instructions/sme.cc | 218 +++++++++++++++++--- 2 files changed, 279 insertions(+), 32 deletions(-) diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index d60048c59c..3c86157bba 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -1237,23 +1237,106 @@ void Instruction::execute() { const uint16_t rowCount = VL_bits / 8; const uint8_t* zd = sourceValues_[0].getAsVector(); const uint64_t* pg = sourceValues_[1].getAsVector(); - const uint64_t sliceNum = + const uint32_t sliceNum = (sourceValues_[2 + rowCount].get() + static_cast( metadata_.operands[2].sme.slice_offset.imm)) % rowCount; - const uint8_t* zanRow = + const uint8_t* zaRow = sourceValues_[2 + sliceNum].getAsVector(); - uint8_t out[256] = {0}; + uint8_t out[256] = {0}; for (int elem = 0; elem < rowCount; elem++) { - uint64_t shifted_active = 1ull << ((elem % 64)); + uint64_t shifted_active = 1ull << (elem % 64); if (pg[elem / 64] & shifted_active) - out[elem] = zanRow[elem]; + out[elem] = zaRow[elem]; + else + out[elem] = zd[elem]; + } + results_[0] = {out, 256}; + break; + } + case Opcode::AArch64_EXTRACT_ZPMXI_H_D: { // MOVA zd.d, pg/m, zanh.d[ws, + // #imm] + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 64; + const uint64_t* zd = sourceValues_[0].getAsVector(); + const uint64_t* pg = sourceValues_[1].getAsVector(); + const uint32_t sliceNum = + (sourceValues_[2 + rowCount].get() + + static_cast(metadata_.operands[2].sme_index.disp)) % + rowCount; + const uint64_t* zaRow = + sourceValues_[2 + sliceNum].getAsVector(); + + uint64_t out[32] = {0}; + for (int elem = 0; elem < rowCount; elem++) { + uint64_t shifted_active = 1ull << ((elem % 8) * 8); + if (pg[elem / 8] & shifted_active) + out[elem] = zaRow[elem]; + else + out[elem] = zd[elem]; + } + results_[0] = {out, 256}; + break; + } + case Opcode::AArch64_EXTRACT_ZPMXI_H_H: { // MOVA zd.h, pg/m, zanh.h[ws, + // #imm] + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 16; + const uint16_t* zd = sourceValues_[0].getAsVector(); + const uint64_t* pg = sourceValues_[1].getAsVector(); + const uint32_t sliceNum = + (sourceValues_[2 + rowCount].get() + + static_cast(metadata_.operands[2].sme_index.disp)) % + rowCount; + const uint16_t* zaRow = + sourceValues_[2 + sliceNum].getAsVector(); + + uint16_t out[128] = {0}; + for (int elem = 0; elem < rowCount; elem++) { + uint64_t shifted_active = 1ull << ((elem % 32) * 2); + if (pg[elem / 32] & shifted_active) + out[elem] = zaRow[elem]; else out[elem] = zd[elem]; } + results_[0] = {out, 256}; + break; + } + case Opcode::AArch64_EXTRACT_ZPMXI_H_S: { // MOVA zd.s, pg/m, zanh.s[ws, + // #imm] + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + const uint16_t rowCount = VL_bits / 32; + const uint32_t* zd = sourceValues_[0].getAsVector(); + const uint64_t* pg = sourceValues_[1].getAsVector(); + const uint32_t sliceNum = + (sourceValues_[2 + rowCount].get() + + static_cast(metadata_.operands[2].sme_index.disp)) % + rowCount; + const uint32_t* zaRow = + sourceValues_[2 + sliceNum].getAsVector(); + + uint32_t out[64] = {0}; + for (int elem = 0; elem < rowCount; elem++) { + uint64_t shifted_active = 1ull << ((elem % 16) * 4); + if (pg[elem / 16] & shifted_active) + out[elem] = zaRow[elem]; + else + out[elem] = zd[elem]; + } results_[0] = {out, 256}; break; } diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index 970f8c5ddb..5d931a23b7 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -8,44 +8,208 @@ namespace { using InstSme = AArch64RegressionTest; #if SIMENG_LLVM_VERSION >= 14 -TEST_P(InstSme, mova) { +TEST_P(InstSme, mova_tileToVec) { // 8-bit + initialHeapData_.resize(SVL / 4); + uint8_t* heap8 = reinterpret_cast(initialHeapData_.data()); + std::vector src8 = {0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, + 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}; + fillHeap(heap8, src8, SVL / 4); RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + smstart - ptrue p0.s - ptrue p1.s + zero {za} - fdup z1.s, #1.0 - mov w0, #1 - index z2.s, #1, w0 - scvtf z2.s, p0/m, z2.s + ptrue p0.b + pfalse p1.b + zip1 p1.b, p0.b, p1.b + + mov w12, #0 + dup z0.b, #1 + dup z1.b, #2 + dup z2.b, #3 + dup z3.b, #4 - fdup z4.s, #5.0 - fdup z5.s, #10.0 - fdup z6.s, #5.0 - fdup z7.s, #10.0 - fmopa za0.s, p0/m, p1/m, z2.s, z1.s + # Horizontal + ld1b {za0h.b[w12, #0]}, p0/z, [x0] + mova z0.b, p0/m, za0h.b[w12, #0] + mova z1.b, p1/m, za0h.b[w12, #0] - ptrue p2.b - mov x2, #0 - mov x3, #2 - addvl x2, x2, #1 - sdiv x2, x2, x3 - whilelo p3.b, xzr, x2 + # Vertical + ld1b {za0v.b[w12, #3]}, p0/z, [x0] + # mova z2.b, p0/m, za0v.b[w12, #3] + # mova z3.b, p1/m, za0v.b[w12, #3] + )"); + CHECK_NEON(0, uint8_t, + fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, + 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, + SVL / 8)); + CHECK_NEON(1, uint8_t, + fillNeon({0xDE, 2, 0xBE, 2, 0x12, 2, 0x56, 2, 0x98, 2, + 0x54, 2, 0xAB, 2, 0xEF, 2}, + SVL / 8)); + // CHECK_NEON(2, uint8_t, + // fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, + // 0x78, + // 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, + // 0x01}, + // SVL / 8)); + // CHECK_NEON(3, uint8_t, + // fillNeon({0xDE, 4, 0xBE, 4, 0x12, 4, 0x56, 4, 0x98, 4, + // 0x54, 4, 0xAB, 4, 0xEF, 4}, + // SVL / 8)); + + // 16-bit + initialHeapData_.resize(SVL / 4); + uint16_t* heap16 = reinterpret_cast(initialHeapData_.data()); + std::vector src16 = {0xDEAD, 0xBEEF, 0x1234, 0x5678, + 0x9876, 0x5432, 0xABCD, 0xEF01}; + fillHeap(heap16, src16, SVL / 8); + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + ptrue p0.h + pfalse p1.b + zip1 p1.h, p0.h, p1.h + + mov w12, #0 + dup z0.h, #1 + dup z1.h, #2 + dup z2.h, #3 + dup z3.h, #4 + + # Horizontal + ld1h {za0h.h[w12, #0]}, p0/z, [x0] + mova z0.h, p0/m, za0h.h[w12, #0] + mova z1.h, p1/m, za0h.h[w12, #0] + + # Vertical + ld1h {za0v.h[w12, #3]}, p0/z, [x0] + # mova z2.h, p0/m, za0v.h[w12, #3] + # mova z3.h, p1/m, za0v.h[w12, #3] + )"); + CHECK_NEON(0, uint16_t, + fillNeon({0xDEAD, 0xBEEF, 0x1234, 0x5678, 0x9876, 0x5432, + 0xABCD, 0xEF01}, + SVL / 8)); + CHECK_NEON(1, uint16_t, + fillNeon({0xDEAD, 2, 0x1234, 2, 0x9876, 2, 0xABCD, 2}, + SVL / 8)); + // CHECK_NEON(2, uint16_t, + // fillNeon({0xDEAD, 0xBEEF, 0x1234, 0x5678, 0x9876, + // 0x5432, + // 0xABCD, 0xEF01}, + // SVL / 8)); + // CHECK_NEON(3, uint16_t, + // fillNeon({0xDEAD, 4, 0x1234, 4, 0x9876, 4, 0xABCD, 4}, + // SVL / 8)); + + // 32-bit + initialHeapData_.resize(SVL / 4); + uint32_t* heap32 = reinterpret_cast(initialHeapData_.data()); + std::vector src32 = {0xDEADBEEF, 0x12345678, 0x98765432, + 0xABCDEF01}; + fillHeap(heap32, src32, SVL / 16); + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + ptrue p0.s + pfalse p1.b + zip1 p1.s, p0.s, p1.s mov w12, #0 - mov w15, #2 + dup z0.s, #1 + dup z1.s, #2 + dup z2.s, #3 + dup z3.s, #4 + + # Horizontal + ld1w {za0h.s[w12, #0]}, p0/z, [x0] + mova z0.s, p0/m, za0h.s[w12, #0] + mova z1.s, p1/m, za0h.s[w12, #0] + + # Vertical + ld1w {za0v.s[w12, #3]}, p0/z, [x0] + # mova z2.s, p0/m, za0v.s[w12, #3] + # mova z3.s, p1/m, za0v.s[w12, #3] + )"); + CHECK_NEON(0, uint32_t, + fillNeon( + {0xDEADBEEF, 0x12345678, 0x98765432, 0xABCDEF01}, SVL / 8)); + CHECK_NEON(1, uint32_t, + fillNeon({0xDEADBEEF, 2, 0x98765432, 2}, SVL / 8)); + // CHECK_NEON( + // 2, uint32_t, + // fillNeon( + // {0xDEADBEEF, 0x12345678, 0x98765432, 0xABCDEF01}, SVL / + // 8)); + // CHECK_NEON(3, uint32_t, + // fillNeon({0xDEADBEEF, 4, 0x98765432, 4}, SVL / + // 8)); - mova z4.b, p2/m, za0h.b[w12, #0] - mova z5.b, p2/m, za0h.b[w12, #4] - mova z6.b, p3/m, za0h.b[w15, #6] - mova z7.b, p3/m, za0h.b[w15, #10] + // 64-bit + initialHeapData_.resize(SVL / 4); + uint64_t* heap64 = reinterpret_cast(initialHeapData_.data()); + std::vector src64 = {0xDEADBEEF12345678, 0x98765432ABCDEF01}; + fillHeap(heap64, src64, SVL / 32); + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + ptrue p0.d + pfalse p1.b + zip1 p1.d, p0.d, p1.d + + mov w12, #0 + dup z0.d, #1 + dup z1.d, #2 + dup z2.d, #3 + dup z3.d, #4 + + # Horizontal + ld1d {za0h.d[w12, #0]}, p0/z, [x0] + mova z0.d, p0/m, za0h.d[w12, #0] + mova z1.d, p1/m, za0h.d[w12, #0] + + # Vertical + ld1d {za0v.d[w12, #1]}, p0/z, [x0] + # mova z2.d, p0/m, za0v.d[w12, #1] + # mova z3.d, p1/m, za0v.d[w12, #1] )"); - CHECK_NEON(4, float, fillNeon({1}, SVL / 8)); - CHECK_NEON(5, float, fillNeon({2}, SVL / 8)); - CHECK_NEON(6, float, fillNeonCombined({3}, {5}, SVL / 8)); - CHECK_NEON(7, float, fillNeonCombined({4}, {10}, SVL / 8)); + CHECK_NEON( + 0, uint64_t, + fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); + CHECK_NEON(1, uint64_t, fillNeon({0xDEADBEEF12345678, 2}, SVL / 8)); + // CHECK_NEON( + // 2, uint64_t, + // fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); + // CHECK_NEON(3, uint64_t, fillNeon({0xDEADBEEF12345678, 4}, SVL / + // 8)); } TEST_P(InstSme, fmopa) { From 594a5b86bec7dff5dfebb080c0a23e6d95aff2bd Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Thu, 15 Aug 2024 17:16:21 +0100 Subject: [PATCH 30/48] Implemented SME MOVA (Tile to Vec, vertical) instructions and regression test (B, H, S, D) --- src/lib/arch/aarch64/Instruction_execute.cc | 108 ++++++++++++++++++++ test/regression/aarch64/instructions/sme.cc | 71 ++++++------- 2 files changed, 140 insertions(+), 39 deletions(-) diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 3c86157bba..767bd15929 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -1340,6 +1340,114 @@ void Instruction::execute() { results_[0] = {out, 256}; break; } + case Opcode::AArch64_EXTRACT_ZPMXI_V_B: { // MOVA zd.b, pg/m, zanv.b[ws, + // #imm] + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 8; + const uint8_t* zd = sourceValues_[0].getAsVector(); + const uint64_t* pg = sourceValues_[1].getAsVector(); + const uint32_t sliceNum = + (sourceValues_[2 + rowCount].get() + + static_cast(metadata_.operands[2].sme_index.disp)) % + rowCount; + + uint8_t out[256] = {0}; + for (uint16_t elem = 0; elem < rowCount; elem++) { + uint64_t shifted_active = 1ull << (elem % 64); + if (pg[elem / 64] & shifted_active) + out[elem] = + sourceValues_[2 + elem].getAsVector()[sliceNum]; + else + out[elem] = zd[elem]; + } + results_[0] = {out, 256}; + break; + } + case Opcode::AArch64_EXTRACT_ZPMXI_V_D: { // MOVA zd.d, pg/m, zanv.d[ws, + // #imm] + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 64; + const uint64_t* zd = sourceValues_[0].getAsVector(); + const uint64_t* pg = sourceValues_[1].getAsVector(); + const uint32_t sliceNum = + (sourceValues_[2 + rowCount].get() + + static_cast(metadata_.operands[2].sme_index.disp)) % + rowCount; + + uint64_t out[32] = {0}; + for (uint16_t elem = 0; elem < rowCount; elem++) { + uint64_t shifted_active = 1ull << ((elem % 8) * 8); + if (pg[elem / 8] & shifted_active) + out[elem] = + sourceValues_[2 + elem].getAsVector()[sliceNum]; + else + out[elem] = zd[elem]; + } + results_[0] = {out, 256}; + break; + } + case Opcode::AArch64_EXTRACT_ZPMXI_V_H: { // MOVA zd.h, pg/m, zanv.h[ws, + // #imm] + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 16; + const uint16_t* zd = sourceValues_[0].getAsVector(); + const uint64_t* pg = sourceValues_[1].getAsVector(); + const uint32_t sliceNum = + (sourceValues_[2 + rowCount].get() + + static_cast(metadata_.operands[2].sme_index.disp)) % + rowCount; + + uint16_t out[128] = {0}; + for (uint16_t elem = 0; elem < rowCount; elem++) { + uint64_t shifted_active = 1ull << ((elem % 32) * 2); + if (pg[elem / 32] & shifted_active) + out[elem] = + sourceValues_[2 + elem].getAsVector()[sliceNum]; + else + out[elem] = zd[elem]; + } + results_[0] = {out, 256}; + break; + } + case Opcode::AArch64_EXTRACT_ZPMXI_V_S: { // MOVA zd.s, pg/m, zanv.s[ws, + // #imm] + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 32; + const uint32_t* zd = sourceValues_[0].getAsVector(); + const uint64_t* pg = sourceValues_[1].getAsVector(); + const uint32_t sliceNum = + (sourceValues_[2 + rowCount].get() + + static_cast(metadata_.operands[2].sme_index.disp)) % + rowCount; + + uint32_t out[64] = {0}; + for (uint16_t elem = 0; elem < rowCount; elem++) { + uint64_t shifted_active = 1ull << ((elem % 16) * 4); + if (pg[elem / 16] & shifted_active) + out[elem] = + sourceValues_[2 + elem].getAsVector()[sliceNum]; + else + out[elem] = zd[elem]; + } + results_[0] = {out, 256}; + break; + } case Opcode::AArch64_EXTRWrri: { // extr wd, wn, wm, #lsb results_[0] = {extrLSB_registers(sourceValues_, metadata_), 8}; diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index 5d931a23b7..bf465555ba 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -42,8 +42,8 @@ TEST_P(InstSme, mova_tileToVec) { # Vertical ld1b {za0v.b[w12, #3]}, p0/z, [x0] - # mova z2.b, p0/m, za0v.b[w12, #3] - # mova z3.b, p1/m, za0v.b[w12, #3] + mova z2.b, p0/m, za0v.b[w12, #3] + mova z3.b, p1/m, za0v.b[w12, #3] )"); CHECK_NEON(0, uint8_t, fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, @@ -53,16 +53,14 @@ TEST_P(InstSme, mova_tileToVec) { fillNeon({0xDE, 2, 0xBE, 2, 0x12, 2, 0x56, 2, 0x98, 2, 0x54, 2, 0xAB, 2, 0xEF, 2}, SVL / 8)); - // CHECK_NEON(2, uint8_t, - // fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, - // 0x78, - // 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, - // 0x01}, - // SVL / 8)); - // CHECK_NEON(3, uint8_t, - // fillNeon({0xDE, 4, 0xBE, 4, 0x12, 4, 0x56, 4, 0x98, 4, - // 0x54, 4, 0xAB, 4, 0xEF, 4}, - // SVL / 8)); + CHECK_NEON(2, uint8_t, + fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, + 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, + SVL / 8)); + CHECK_NEON(3, uint8_t, + fillNeon({0xDE, 4, 0xBE, 4, 0x12, 4, 0x56, 4, 0x98, 4, + 0x54, 4, 0xAB, 4, 0xEF, 4}, + SVL / 8)); // 16-bit initialHeapData_.resize(SVL / 4); @@ -97,8 +95,8 @@ TEST_P(InstSme, mova_tileToVec) { # Vertical ld1h {za0v.h[w12, #3]}, p0/z, [x0] - # mova z2.h, p0/m, za0v.h[w12, #3] - # mova z3.h, p1/m, za0v.h[w12, #3] + mova z2.h, p0/m, za0v.h[w12, #3] + mova z3.h, p1/m, za0v.h[w12, #3] )"); CHECK_NEON(0, uint16_t, fillNeon({0xDEAD, 0xBEEF, 0x1234, 0x5678, 0x9876, 0x5432, @@ -107,14 +105,13 @@ TEST_P(InstSme, mova_tileToVec) { CHECK_NEON(1, uint16_t, fillNeon({0xDEAD, 2, 0x1234, 2, 0x9876, 2, 0xABCD, 2}, SVL / 8)); - // CHECK_NEON(2, uint16_t, - // fillNeon({0xDEAD, 0xBEEF, 0x1234, 0x5678, 0x9876, - // 0x5432, - // 0xABCD, 0xEF01}, - // SVL / 8)); - // CHECK_NEON(3, uint16_t, - // fillNeon({0xDEAD, 4, 0x1234, 4, 0x9876, 4, 0xABCD, 4}, - // SVL / 8)); + CHECK_NEON(2, uint16_t, + fillNeon({0xDEAD, 0xBEEF, 0x1234, 0x5678, 0x9876, 0x5432, + 0xABCD, 0xEF01}, + SVL / 8)); + CHECK_NEON(3, uint16_t, + fillNeon({0xDEAD, 4, 0x1234, 4, 0x9876, 4, 0xABCD, 4}, + SVL / 8)); // 32-bit initialHeapData_.resize(SVL / 4); @@ -149,22 +146,19 @@ TEST_P(InstSme, mova_tileToVec) { # Vertical ld1w {za0v.s[w12, #3]}, p0/z, [x0] - # mova z2.s, p0/m, za0v.s[w12, #3] - # mova z3.s, p1/m, za0v.s[w12, #3] + mova z2.s, p0/m, za0v.s[w12, #3] + mova z3.s, p1/m, za0v.s[w12, #3] )"); CHECK_NEON(0, uint32_t, fillNeon( {0xDEADBEEF, 0x12345678, 0x98765432, 0xABCDEF01}, SVL / 8)); CHECK_NEON(1, uint32_t, fillNeon({0xDEADBEEF, 2, 0x98765432, 2}, SVL / 8)); - // CHECK_NEON( - // 2, uint32_t, - // fillNeon( - // {0xDEADBEEF, 0x12345678, 0x98765432, 0xABCDEF01}, SVL / - // 8)); - // CHECK_NEON(3, uint32_t, - // fillNeon({0xDEADBEEF, 4, 0x98765432, 4}, SVL / - // 8)); + CHECK_NEON(2, uint32_t, + fillNeon( + {0xDEADBEEF, 0x12345678, 0x98765432, 0xABCDEF01}, SVL / 8)); + CHECK_NEON(3, uint32_t, + fillNeon({0xDEADBEEF, 4, 0x98765432, 4}, SVL / 8)); // 64-bit initialHeapData_.resize(SVL / 4); @@ -198,18 +192,17 @@ TEST_P(InstSme, mova_tileToVec) { # Vertical ld1d {za0v.d[w12, #1]}, p0/z, [x0] - # mova z2.d, p0/m, za0v.d[w12, #1] - # mova z3.d, p1/m, za0v.d[w12, #1] + mova z2.d, p0/m, za0v.d[w12, #1] + mova z3.d, p1/m, za0v.d[w12, #1] )"); CHECK_NEON( 0, uint64_t, fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); CHECK_NEON(1, uint64_t, fillNeon({0xDEADBEEF12345678, 2}, SVL / 8)); - // CHECK_NEON( - // 2, uint64_t, - // fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); - // CHECK_NEON(3, uint64_t, fillNeon({0xDEADBEEF12345678, 4}, SVL / - // 8)); + CHECK_NEON( + 2, uint64_t, + fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); + CHECK_NEON(3, uint64_t, fillNeon({0xDEADBEEF12345678, 4}, SVL / 8)); } TEST_P(InstSme, fmopa) { From c3aed6dfa15bf6dab536264aa81157af0ca83d29 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Thu, 15 Aug 2024 17:28:40 +0100 Subject: [PATCH 31/48] Implemented SME MOV (Tile to Vec, vertical and horizontal) instruction alias and regression tests (B, H, S, D) --- test/regression/aarch64/instructions/sme.cc | 88 +++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index bf465555ba..4da776889b 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -34,16 +34,26 @@ TEST_P(InstSme, mova_tileToVec) { dup z1.b, #2 dup z2.b, #3 dup z3.b, #4 + dup z4.b, #5 + dup z5.b, #6 + dup z6.b, #7 + dup z7.b, #8 # Horizontal ld1b {za0h.b[w12, #0]}, p0/z, [x0] mova z0.b, p0/m, za0h.b[w12, #0] mova z1.b, p1/m, za0h.b[w12, #0] + #Alias + mov z4.b, p0/m, za0h.b[w12, #0] + mov z5.b, p1/m, za0h.b[w12, #0] # Vertical ld1b {za0v.b[w12, #3]}, p0/z, [x0] mova z2.b, p0/m, za0v.b[w12, #3] mova z3.b, p1/m, za0v.b[w12, #3] + #Alias + mov z6.b, p0/m, za0v.b[w12, #3] + mov z7.b, p1/m, za0v.b[w12, #3] )"); CHECK_NEON(0, uint8_t, fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, @@ -61,6 +71,22 @@ TEST_P(InstSme, mova_tileToVec) { fillNeon({0xDE, 4, 0xBE, 4, 0x12, 4, 0x56, 4, 0x98, 4, 0x54, 4, 0xAB, 4, 0xEF, 4}, SVL / 8)); + CHECK_NEON(4, uint8_t, + fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, + 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, + SVL / 8)); + CHECK_NEON(5, uint8_t, + fillNeon({0xDE, 6, 0xBE, 6, 0x12, 6, 0x56, 6, 0x98, 6, + 0x54, 6, 0xAB, 6, 0xEF, 6}, + SVL / 8)); + CHECK_NEON(6, uint8_t, + fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, + 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, + SVL / 8)); + CHECK_NEON(7, uint8_t, + fillNeon({0xDE, 8, 0xBE, 8, 0x12, 8, 0x56, 8, 0x98, 8, + 0x54, 8, 0xAB, 8, 0xEF, 8}, + SVL / 8)); // 16-bit initialHeapData_.resize(SVL / 4); @@ -87,16 +113,26 @@ TEST_P(InstSme, mova_tileToVec) { dup z1.h, #2 dup z2.h, #3 dup z3.h, #4 + dup z4.h, #5 + dup z5.h, #6 + dup z6.h, #7 + dup z7.h, #8 # Horizontal ld1h {za0h.h[w12, #0]}, p0/z, [x0] mova z0.h, p0/m, za0h.h[w12, #0] mova z1.h, p1/m, za0h.h[w12, #0] + #Alias + mov z4.h, p0/m, za0h.h[w12, #0] + mov z5.h, p1/m, za0h.h[w12, #0] # Vertical ld1h {za0v.h[w12, #3]}, p0/z, [x0] mova z2.h, p0/m, za0v.h[w12, #3] mova z3.h, p1/m, za0v.h[w12, #3] + #Alias + mov z6.h, p0/m, za0v.h[w12, #3] + mov z7.h, p1/m, za0v.h[w12, #3] )"); CHECK_NEON(0, uint16_t, fillNeon({0xDEAD, 0xBEEF, 0x1234, 0x5678, 0x9876, 0x5432, @@ -112,6 +148,20 @@ TEST_P(InstSme, mova_tileToVec) { CHECK_NEON(3, uint16_t, fillNeon({0xDEAD, 4, 0x1234, 4, 0x9876, 4, 0xABCD, 4}, SVL / 8)); + CHECK_NEON(4, uint16_t, + fillNeon({0xDEAD, 0xBEEF, 0x1234, 0x5678, 0x9876, 0x5432, + 0xABCD, 0xEF01}, + SVL / 8)); + CHECK_NEON(5, uint16_t, + fillNeon({0xDEAD, 6, 0x1234, 6, 0x9876, 6, 0xABCD, 6}, + SVL / 8)); + CHECK_NEON(6, uint16_t, + fillNeon({0xDEAD, 0xBEEF, 0x1234, 0x5678, 0x9876, 0x5432, + 0xABCD, 0xEF01}, + SVL / 8)); + CHECK_NEON(7, uint16_t, + fillNeon({0xDEAD, 8, 0x1234, 8, 0x9876, 8, 0xABCD, 8}, + SVL / 8)); // 32-bit initialHeapData_.resize(SVL / 4); @@ -138,16 +188,26 @@ TEST_P(InstSme, mova_tileToVec) { dup z1.s, #2 dup z2.s, #3 dup z3.s, #4 + dup z4.s, #5 + dup z5.s, #6 + dup z6.s, #7 + dup z7.s, #8 # Horizontal ld1w {za0h.s[w12, #0]}, p0/z, [x0] mova z0.s, p0/m, za0h.s[w12, #0] mova z1.s, p1/m, za0h.s[w12, #0] + #Alias + mov z4.s, p0/m, za0h.s[w12, #0] + mov z5.s, p1/m, za0h.s[w12, #0] # Vertical ld1w {za0v.s[w12, #3]}, p0/z, [x0] mova z2.s, p0/m, za0v.s[w12, #3] mova z3.s, p1/m, za0v.s[w12, #3] + #Alias + mov z6.s, p0/m, za0v.s[w12, #3] + mov z7.s, p1/m, za0v.s[w12, #3] )"); CHECK_NEON(0, uint32_t, fillNeon( @@ -159,6 +219,16 @@ TEST_P(InstSme, mova_tileToVec) { {0xDEADBEEF, 0x12345678, 0x98765432, 0xABCDEF01}, SVL / 8)); CHECK_NEON(3, uint32_t, fillNeon({0xDEADBEEF, 4, 0x98765432, 4}, SVL / 8)); + CHECK_NEON(4, uint32_t, + fillNeon( + {0xDEADBEEF, 0x12345678, 0x98765432, 0xABCDEF01}, SVL / 8)); + CHECK_NEON(5, uint32_t, + fillNeon({0xDEADBEEF, 6, 0x98765432, 6}, SVL / 8)); + CHECK_NEON(6, uint32_t, + fillNeon( + {0xDEADBEEF, 0x12345678, 0x98765432, 0xABCDEF01}, SVL / 8)); + CHECK_NEON(7, uint32_t, + fillNeon({0xDEADBEEF, 8, 0x98765432, 8}, SVL / 8)); // 64-bit initialHeapData_.resize(SVL / 4); @@ -184,16 +254,26 @@ TEST_P(InstSme, mova_tileToVec) { dup z1.d, #2 dup z2.d, #3 dup z3.d, #4 + dup z4.d, #5 + dup z5.d, #6 + dup z6.d, #7 + dup z7.d, #8 # Horizontal ld1d {za0h.d[w12, #0]}, p0/z, [x0] mova z0.d, p0/m, za0h.d[w12, #0] mova z1.d, p1/m, za0h.d[w12, #0] + #Alias + mov z4.d, p0/m, za0h.d[w12, #0] + mov z5.d, p1/m, za0h.d[w12, #0] # Vertical ld1d {za0v.d[w12, #1]}, p0/z, [x0] mova z2.d, p0/m, za0v.d[w12, #1] mova z3.d, p1/m, za0v.d[w12, #1] + #Alias + mov z6.d, p0/m, za0v.d[w12, #1] + mov z7.d, p1/m, za0v.d[w12, #1] )"); CHECK_NEON( 0, uint64_t, @@ -203,6 +283,14 @@ TEST_P(InstSme, mova_tileToVec) { 2, uint64_t, fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); CHECK_NEON(3, uint64_t, fillNeon({0xDEADBEEF12345678, 4}, SVL / 8)); + CHECK_NEON( + 4, uint64_t, + fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); + CHECK_NEON(5, uint64_t, fillNeon({0xDEADBEEF12345678, 6}, SVL / 8)); + CHECK_NEON( + 6, uint64_t, + fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); + CHECK_NEON(7, uint64_t, fillNeon({0xDEADBEEF12345678, 8}, SVL / 8)); } TEST_P(InstSme, fmopa) { From a927b37b40174a88aa6e97614c592ee8bd4984ab Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Fri, 16 Aug 2024 14:43:32 +0100 Subject: [PATCH 32/48] Implemented SME MOVA/MOV (Vec to Tile, vertical and horizontal) instructions and aliases and regression tests (B, H, S, D) --- src/lib/arch/aarch64/InstructionMetadata.cc | 25 ++ src/lib/arch/aarch64/Instruction_execute.cc | 235 +++++++++++ test/regression/aarch64/instructions/sme.cc | 424 ++++++++++++++++++++ 3 files changed, 684 insertions(+) diff --git a/src/lib/arch/aarch64/InstructionMetadata.cc b/src/lib/arch/aarch64/InstructionMetadata.cc index 34ddca07d7..429e8809f7 100644 --- a/src/lib/arch/aarch64/InstructionMetadata.cc +++ b/src/lib/arch/aarch64/InstructionMetadata.cc @@ -232,6 +232,31 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) operands[2].access = CS_AC_READ; operands[3].access = CS_AC_READ; break; + + case Opcode::AArch64_INSERT_MXIPZ_H_B: + [[fallthrough]]; + case Opcode::AArch64_INSERT_MXIPZ_H_D: + [[fallthrough]]; + case Opcode::AArch64_INSERT_MXIPZ_H_H: + [[fallthrough]]; + case Opcode::AArch64_INSERT_MXIPZ_H_S: + [[fallthrough]]; + case Opcode::AArch64_INSERT_MXIPZ_V_B: + [[fallthrough]]; + case Opcode::AArch64_INSERT_MXIPZ_V_D: + [[fallthrough]]; + case Opcode::AArch64_INSERT_MXIPZ_V_H: + [[fallthrough]]; + case Opcode::AArch64_INSERT_MXIPZ_V_S: + // Need to add access specifiers + // although operands[0] should be READ | WRITE, due to the implemented + // decode logic for SME tile destinations, the register will be added as + // both source and destination with just WRITE access. + operands[0].access = CS_AC_WRITE; + operands[1].access = CS_AC_READ; + operands[2].access = CS_AC_READ; + break; + case Opcode::AArch64_ZERO_M: { // Incorrect access type: All are READ but should all be WRITE for (int i = 0; i < operandCount; i++) { diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 767bd15929..6e0436aecb 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -2784,6 +2784,241 @@ void Instruction::execute() { VL_bits, false, false); break; } + + case Opcode::AArch64_INSERT_MXIPZ_H_B: { // mova za0h.b[ws, #imm], pg/m, + // zn.b + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 8; + const uint32_t sliceNum = + (sourceValues_[rowCount].get() + + static_cast(metadata_.operands[0].sme_index.disp)) % + rowCount; + const uint8_t* zaRow = sourceValues_[sliceNum].getAsVector(); + const uint64_t* pg = + sourceValues_[rowCount + 1].getAsVector(); + const uint8_t* zn = sourceValues_[rowCount + 2].getAsVector(); + + uint8_t out[256] = {0}; + for (uint16_t elem = 0; elem < rowCount; elem++) { + uint64_t shifted_active = 1ull << (elem % 64); + if (pg[elem / 64] & shifted_active) + out[elem] = zn[elem]; + else + out[elem] = zaRow[elem]; + } + // Need to update whole za tile + for (uint16_t row = 0; row < rowCount; row++) { + results_[row] = + (row == sliceNum) ? RegisterValue(out, 256) : sourceValues_[row]; + } + break; + } + case Opcode::AArch64_INSERT_MXIPZ_H_D: { // mova za0h.d[ws, #imm], pg/m, + // zn.d + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 64; + const uint32_t sliceNum = + (sourceValues_[rowCount].get() + + static_cast(metadata_.operands[0].sme_index.disp)) % + rowCount; + const uint64_t* zaRow = sourceValues_[sliceNum].getAsVector(); + const uint64_t* pg = + sourceValues_[rowCount + 1].getAsVector(); + const uint64_t* zn = + sourceValues_[rowCount + 2].getAsVector(); + + uint64_t out[32] = {0}; + for (uint16_t elem = 0; elem < rowCount; elem++) { + uint64_t shifted_active = 1ull << ((elem % 8) * 8); + if (pg[elem / 8] & shifted_active) + out[elem] = zn[elem]; + else + out[elem] = zaRow[elem]; + } + // Need to update whole za tile + for (uint16_t row = 0; row < rowCount; row++) { + results_[row] = + (row == sliceNum) ? RegisterValue(out, 256) : sourceValues_[row]; + } + break; + } + case Opcode::AArch64_INSERT_MXIPZ_H_H: { // mova za0h.h[ws, #imm], pg/m, + // zn.h + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 16; + const uint32_t sliceNum = + (sourceValues_[rowCount].get() + + static_cast(metadata_.operands[0].sme_index.disp)) % + rowCount; + const uint16_t* zaRow = sourceValues_[sliceNum].getAsVector(); + const uint64_t* pg = + sourceValues_[rowCount + 1].getAsVector(); + const uint16_t* zn = + sourceValues_[rowCount + 2].getAsVector(); + + uint16_t out[128] = {0}; + for (uint16_t elem = 0; elem < rowCount; elem++) { + uint64_t shifted_active = 1ull << ((elem % 32) * 2); + if (pg[elem / 32] & shifted_active) + out[elem] = zn[elem]; + else + out[elem] = zaRow[elem]; + } + // Need to update whole za tile + for (uint16_t row = 0; row < rowCount; row++) { + results_[row] = + (row == sliceNum) ? RegisterValue(out, 256) : sourceValues_[row]; + } + break; + } + case Opcode::AArch64_INSERT_MXIPZ_H_S: { // mova za0h.s[ws, #imm], pg/m, + // zn.s + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 32; + const uint32_t sliceNum = + (sourceValues_[rowCount].get() + + static_cast(metadata_.operands[0].sme_index.disp)) % + rowCount; + const uint32_t* zaRow = sourceValues_[sliceNum].getAsVector(); + const uint64_t* pg = + sourceValues_[rowCount + 1].getAsVector(); + const uint32_t* zn = + sourceValues_[rowCount + 2].getAsVector(); + + uint32_t out[64] = {0}; + for (uint16_t elem = 0; elem < rowCount; elem++) { + uint64_t shifted_active = 1ull << ((elem % 16) * 4); + if (pg[elem / 16] & shifted_active) + out[elem] = zn[elem]; + else + out[elem] = zaRow[elem]; + } + // Need to update whole za tile + for (uint16_t row = 0; row < rowCount; row++) { + results_[row] = + (row == sliceNum) ? RegisterValue(out, 256) : sourceValues_[row]; + } + break; + } + case Opcode::AArch64_INSERT_MXIPZ_V_B: { // mova za0v.b[ws, #imm], pg/m, + // zn.b + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 8; + const uint32_t sliceNum = + (sourceValues_[rowCount].get() + + static_cast(metadata_.operands[0].sme_index.disp)) % + rowCount; + const uint64_t* pg = + sourceValues_[rowCount + 1].getAsVector(); + const uint8_t* zn = sourceValues_[rowCount + 2].getAsVector(); + + for (uint16_t i = 0; i < rowCount; i++) { + uint8_t* row = + const_cast(sourceValues_[i].getAsVector()); + uint64_t shifted_active = 1ull << (i % 64); + if (pg[i / 64] & shifted_active) row[sliceNum] = zn[i]; + results_[i] = {(char*)row, 256}; + } + break; + } + case Opcode::AArch64_INSERT_MXIPZ_V_D: { // mova za0v.d[ws, #imm], pg/m, + // zn.d + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 64; + const uint32_t sliceNum = + (sourceValues_[rowCount].get() + + static_cast(metadata_.operands[0].sme_index.disp)) % + rowCount; + const uint64_t* pg = + sourceValues_[rowCount + 1].getAsVector(); + const uint64_t* zn = + sourceValues_[rowCount + 2].getAsVector(); + + for (uint16_t i = 0; i < rowCount; i++) { + uint64_t* row = + const_cast(sourceValues_[i].getAsVector()); + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (pg[i / 8] & shifted_active) row[sliceNum] = zn[i]; + results_[i] = {(char*)row, 256}; + } + break; + } + case Opcode::AArch64_INSERT_MXIPZ_V_H: { // mova za0v.h[ws, #imm], pg/m, + // zn.h + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 16; + const uint32_t sliceNum = + (sourceValues_[rowCount].get() + + static_cast(metadata_.operands[0].sme_index.disp)) % + rowCount; + const uint64_t* pg = + sourceValues_[rowCount + 1].getAsVector(); + const uint16_t* zn = + sourceValues_[rowCount + 2].getAsVector(); + + for (uint16_t i = 0; i < rowCount; i++) { + uint16_t* row = + const_cast(sourceValues_[i].getAsVector()); + uint64_t shifted_active = 1ull << ((i % 32) * 2); + if (pg[i / 32] & shifted_active) row[sliceNum] = zn[i]; + results_[i] = {(char*)row, 256}; + } + break; + } + case Opcode::AArch64_INSERT_MXIPZ_V_S: { // mova za0v.s[ws, #imm], pg/m, + // zn.s + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 32; + const uint32_t sliceNum = + (sourceValues_[rowCount].get() + + static_cast(metadata_.operands[0].sme_index.disp)) % + rowCount; + const uint64_t* pg = + sourceValues_[rowCount + 1].getAsVector(); + const uint32_t* zn = + sourceValues_[rowCount + 2].getAsVector(); + + for (uint16_t i = 0; i < rowCount; i++) { + uint32_t* row = + const_cast(sourceValues_[i].getAsVector()); + uint64_t shifted_active = 1ull << ((i % 16) * 4); + if (pg[i / 16] & shifted_active) row[sliceNum] = zn[i]; + results_[i] = {(char*)row, 256}; + } + break; + } case Opcode::AArch64_INSvi16gpr: { // ins vd.h[index], wn results_[0] = vecInsIndex_gpr(sourceValues_, metadata_); diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index 4da776889b..c0d4f72624 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -293,6 +293,430 @@ TEST_P(InstSme, mova_tileToVec) { CHECK_NEON(7, uint64_t, fillNeon({0xDEADBEEF12345678, 8}, SVL / 8)); } +TEST_P(InstSme, mova_b_vecToTile) { + // 8-bit + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.b + pfalse p1.b + zip1 p1.b, p0.b, p1.b + + mov w12, #0 + dup z0.b, #1 + dup z1.b, #2 + + # Horizontal + mova za0h.b[w12, #0], p0/m, z0.b + mova za0h.b[w12, #1], p1/m, z1.b + )"); + CHECK_MAT_ROW(ARM64_REG_ZAB0, 0, uint8_t, fillNeon({1}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAB0, 1, uint8_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 8; i++) { + CHECK_MAT_ROW(ARM64_REG_ZAB0, i, uint8_t, + fillNeon({0}, (SVL / 8))); + } + + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.b + pfalse p1.b + zip1 p1.b, p0.b, p1.b + + mov w12, #0 + dup z0.b, #1 + dup z1.b, #2 + + # Horizontal Alias + mov za0h.b[w12, #0], p0/m, z0.b + mov za0h.b[w12, #1], p1/m, z1.b + )"); + CHECK_MAT_ROW(ARM64_REG_ZAB0, 0, uint8_t, fillNeon({1}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAB0, 1, uint8_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 8; i++) { + CHECK_MAT_ROW(ARM64_REG_ZAB0, i, uint8_t, + fillNeon({0}, (SVL / 8))); + } + + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.b + pfalse p1.b + zip1 p1.b, p0.b, p1.b + + mov w12, #0 + dup z0.b, #1 + dup z1.b, #2 + + # Vertical + mova za0v.b[w12, #0], p0/m, z0.b + mova za0v.b[w12, #1], p1/m, z1.b + )"); + CHECK_MAT_COL(ARM64_REG_ZAB0, 0, uint8_t, fillNeon({1}, (SVL / 8))); + CHECK_MAT_COL(ARM64_REG_ZAB0, 1, uint8_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 8; i++) { + CHECK_MAT_COL(ARM64_REG_ZAB0, i, uint8_t, + fillNeon({0}, (SVL / 8))); + } + + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.b + pfalse p1.b + zip1 p1.b, p0.b, p1.b + + mov w12, #0 + dup z0.b, #1 + dup z1.b, #2 + + # Vertical Alias + mov za0v.b[w12, #0], p0/m, z0.b + mov za0v.b[w12, #1], p1/m, z1.b + )"); + CHECK_MAT_COL(ARM64_REG_ZAB0, 0, uint8_t, fillNeon({1}, (SVL / 8))); + CHECK_MAT_COL(ARM64_REG_ZAB0, 1, uint8_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 8; i++) { + CHECK_MAT_COL(ARM64_REG_ZAB0, i, uint8_t, + fillNeon({0}, (SVL / 8))); + } +} + +TEST_P(InstSme, mova_h_vecToTile) { + // 16-bit + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.h + pfalse p1.b + zip1 p1.h, p0.h, p1.h + + mov w12, #0 + dup z0.h, #1 + dup z1.h, #2 + + # Horizontal + mova za0h.h[w12, #0], p0/m, z0.h + mova za0h.h[w12, #1], p1/m, z1.h + )"); + CHECK_MAT_ROW(ARM64_REG_ZAH0, 0, uint16_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAH0, 1, uint16_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 16; i++) { + CHECK_MAT_ROW(ARM64_REG_ZAH0, i, uint16_t, + fillNeon({0}, (SVL / 8))); + } + + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.h + pfalse p1.b + zip1 p1.h, p0.h, p1.h + + mov w12, #0 + dup z0.h, #1 + dup z1.h, #2 + + # Horizontal Alias + mov za0h.h[w12, #0], p0/m, z0.h + mov za0h.h[w12, #1], p1/m, z1.h + )"); + CHECK_MAT_ROW(ARM64_REG_ZAH0, 0, uint16_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAH0, 1, uint16_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 16; i++) { + CHECK_MAT_ROW(ARM64_REG_ZAH0, i, uint16_t, + fillNeon({0}, (SVL / 8))); + } + + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.h + pfalse p1.b + zip1 p1.h, p0.h, p1.h + + mov w12, #0 + dup z0.h, #1 + dup z1.h, #2 + + # Vertical + mova za0v.h[w12, #0], p0/m, z0.h + mova za0v.h[w12, #1], p1/m, z1.h + )"); + CHECK_MAT_COL(ARM64_REG_ZAH0, 0, uint16_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_COL(ARM64_REG_ZAH0, 1, uint16_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 16; i++) { + CHECK_MAT_COL(ARM64_REG_ZAH0, i, uint16_t, + fillNeon({0}, (SVL / 8))); + } + + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.h + pfalse p1.b + zip1 p1.h, p0.h, p1.h + + mov w12, #0 + dup z0.h, #1 + dup z1.h, #2 + + # Vertical Alias + mov za0v.h[w12, #0], p0/m, z0.h + mov za0v.h[w12, #1], p1/m, z1.h + )"); + CHECK_MAT_COL(ARM64_REG_ZAH0, 0, uint16_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_COL(ARM64_REG_ZAH0, 1, uint16_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 16; i++) { + CHECK_MAT_COL(ARM64_REG_ZAH0, i, uint16_t, + fillNeon({0}, (SVL / 8))); + } +} + +TEST_P(InstSme, mova_s_vecToTile) { + // 32-bit + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.s + pfalse p1.b + zip1 p1.s, p0.s, p1.s + + mov w12, #0 + dup z0.s, #1 + dup z1.s, #2 + + # Horizontal + mova za0h.s[w12, #0], p0/m, z0.s + mova za0h.s[w12, #1], p1/m, z1.s + )"); + CHECK_MAT_ROW(ARM64_REG_ZAS0, 0, uint32_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS0, 1, uint32_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 32; i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, + fillNeon({0}, (SVL / 8))); + } + + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.s + pfalse p1.b + zip1 p1.s, p0.s, p1.s + + mov w12, #0 + dup z0.s, #1 + dup z1.s, #2 + + # Horizontal Alias + mov za0h.s[w12, #0], p0/m, z0.s + mov za0h.s[w12, #1], p1/m, z1.s + )"); + CHECK_MAT_ROW(ARM64_REG_ZAS0, 0, uint32_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS0, 1, uint32_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 32; i++) { + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, + fillNeon({0}, (SVL / 8))); + } + + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.s + pfalse p1.b + zip1 p1.s, p0.s, p1.s + + mov w12, #0 + dup z0.s, #1 + dup z1.s, #2 + + # Vertical + mova za0v.s[w12, #0], p0/m, z0.s + mova za0v.s[w12, #1], p1/m, z1.s + )"); + CHECK_MAT_COL(ARM64_REG_ZAS0, 0, uint32_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_COL(ARM64_REG_ZAS0, 1, uint32_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 32; i++) { + CHECK_MAT_COL(ARM64_REG_ZAS0, i, uint32_t, + fillNeon({0}, (SVL / 8))); + } + + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.s + pfalse p1.b + zip1 p1.s, p0.s, p1.s + + mov w12, #0 + dup z0.s, #1 + dup z1.s, #2 + + # Vertical Alias + mov za0v.s[w12, #0], p0/m, z0.s + mov za0v.s[w12, #1], p1/m, z1.s + )"); + CHECK_MAT_COL(ARM64_REG_ZAS0, 0, uint32_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_COL(ARM64_REG_ZAS0, 1, uint32_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 32; i++) { + CHECK_MAT_COL(ARM64_REG_ZAS0, i, uint32_t, + fillNeon({0}, (SVL / 8))); + } +} + +TEST_P(InstSme, mova_d_vecToTile) { + // 64-bit + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.d + pfalse p1.b + zip1 p1.d, p0.d, p1.d + + mov w12, #0 + dup z0.d, #1 + dup z1.d, #2 + + # Horizontal + mova za0h.d[w12, #0], p0/m, z0.d + mova za0h.d[w12, #1], p1/m, z1.d + )"); + CHECK_MAT_ROW(ARM64_REG_ZAD0, 0, uint64_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD0, 1, uint64_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 64; i++) { + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, + fillNeon({0}, (SVL / 8))); + } + + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.d + pfalse p1.b + zip1 p1.d, p0.d, p1.d + + mov w12, #0 + dup z0.d, #1 + dup z1.d, #2 + + # Horizontal Alias + mov za0h.d[w12, #0], p0/m, z0.d + mov za0h.d[w12, #1], p1/m, z1.d + )"); + CHECK_MAT_ROW(ARM64_REG_ZAD0, 0, uint64_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD0, 1, uint64_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 64; i++) { + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, + fillNeon({0}, (SVL / 8))); + } + + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.d + pfalse p1.b + zip1 p1.d, p0.d, p1.d + + mov w12, #0 + dup z0.d, #1 + dup z1.d, #2 + + # Vertical + mova za0v.d[w12, #0], p0/m, z0.d + mova za0v.d[w12, #1], p1/m, z1.d + )"); + CHECK_MAT_COL(ARM64_REG_ZAD0, 0, uint64_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_COL(ARM64_REG_ZAD0, 1, uint64_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 64; i++) { + CHECK_MAT_COL(ARM64_REG_ZAD0, i, uint64_t, + fillNeon({0}, (SVL / 8))); + } + + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.d + pfalse p1.b + zip1 p1.d, p0.d, p1.d + + mov w12, #0 + dup z0.d, #1 + dup z1.d, #2 + + # Vertical Alias + mov za0v.d[w12, #0], p0/m, z0.d + mov za0v.d[w12, #1], p1/m, z1.d + )"); + CHECK_MAT_COL(ARM64_REG_ZAD0, 0, uint64_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_COL(ARM64_REG_ZAD0, 1, uint64_t, + fillNeon({2, 0}, (SVL / 8))); + for (int i = 2; i < SVL / 64; i++) { + CHECK_MAT_COL(ARM64_REG_ZAD0, i, uint64_t, + fillNeon({0}, (SVL / 8))); + } +} + TEST_P(InstSme, fmopa) { // 32-bit RUN_AARCH64(R"( From 0869be6c279e3c959827863017d2370b93b828c6 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Fri, 16 Aug 2024 16:51:56 +0100 Subject: [PATCH 33/48] Implemented SME LDR instruction and regression tests. --- src/lib/arch/aarch64/InstructionMetadata.cc | 8 ++++- src/lib/arch/aarch64/Instruction_address.cc | 11 ++++++ src/lib/arch/aarch64/Instruction_execute.cc | 24 +++++++++++++ test/regression/aarch64/instructions/sme.cc | 40 +++++++++++++++++++++ 4 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/lib/arch/aarch64/InstructionMetadata.cc b/src/lib/arch/aarch64/InstructionMetadata.cc index 429e8809f7..7e556c4e59 100644 --- a/src/lib/arch/aarch64/InstructionMetadata.cc +++ b/src/lib/arch/aarch64/InstructionMetadata.cc @@ -256,7 +256,13 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) operands[1].access = CS_AC_READ; operands[2].access = CS_AC_READ; break; - + case Opcode::AArch64_LDR_ZA: + // Need to add access specifier + // although operands[0] should be READ | WRITE, due to the implemented + // decode logic for SME tile destinations, the register will be added as + // both source and destination with just WRITE access. + operands[0].access = CS_AC_WRITE; + break; case Opcode::AArch64_ZERO_M: { // Incorrect access type: All are READ but should all be WRITE for (int i = 0; i < operandCount; i++) { diff --git a/src/lib/arch/aarch64/Instruction_address.cc b/src/lib/arch/aarch64/Instruction_address.cc index 483b673465..8eaae50a9c 100644 --- a/src/lib/arch/aarch64/Instruction_address.cc +++ b/src/lib/arch/aarch64/Instruction_address.cc @@ -485,6 +485,17 @@ span Instruction::generateAddresses() { setMemoryAddresses({{sourceValues_[0].get(), 8}}); break; } + case Opcode::AArch64_LDR_ZA: { // ldr za[wv, #imm], [{, #imm, mul + // vl}] + // SME + // ZA Row count === current VL in bytes + const uint16_t zaRowCount = VL_bits / 8; + const uint64_t xn = sourceValues_[zaRowCount + 1].get(); + const uint64_t imm = + static_cast(metadata_.operands[1].mem.disp); + setMemoryAddresses({xn + (imm * zaRowCount), zaRowCount}); + break; + } case Opcode::AArch64_LDRBBpost: { // ldrb wt, [xn], #imm setMemoryAddresses({{sourceValues_[0].get(), 1}}); break; diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 6e0436aecb..c4cda5a41d 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -4277,6 +4277,30 @@ void Instruction::execute() { results_[0] = {out, 256}; break; } + case Opcode::AArch64_LDR_ZA: { // ldr za[wv, #imm], [{, #imm, mul + // vl}] + // SME, LOAD + // If not in right context mode, raise exception + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 8; + const uint32_t wn = sourceValues_[rowCount].get(); + const uint32_t sliceNum = + wn + static_cast(metadata_.operands[0].sme_index.disp); + + const uint8_t* data = memoryData_[0].getAsVector(); + uint8_t out[256] = {0}; + for (uint16_t i = 0; i < rowCount; i++) { + out[i] = data[i]; + } + + for (uint16_t row = 0; row < rowCount; row++) { + results_[row] = (row == sliceNum) + ? RegisterValue(out, 256) + : results_[row] = sourceValues_[row]; + } + break; + } case Opcode::AArch64_LDTRSBXi: { // ldtrsb xt, [xn, #imm] // LOAD // TODO: implement diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index c0d4f72624..a4b783bb3c 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -1212,6 +1212,46 @@ TEST_P(InstSme, ld1w) { {0xDEADBEEF, 0x12345678, 0x98765432, 0xABCDEF01}, {0}, SVL / 8)); } +TEST_P(InstSme, ldr) { + // Horizontal + initialHeapData_.resize(SVL); + uint8_t* heap8 = reinterpret_cast(initialHeapData_.data()); + std::vector src = {0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, + 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}; + fillHeap(heap8, src, SVL); + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + ptrue p0.b + mov w12, #0 + # Load and broadcast values from heap + ldr za[w12, 0], [x0] + ldr za[w12, 2], [x0, #2, mul vl] + )"); + CHECK_MAT_ROW( + ARM64_REG_ZAB0, 0, uint8_t, + fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, + 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, + SVL / 8)); + CHECK_MAT_ROW(ARM64_REG_ZAB0, 1, uint8_t, fillNeon({0}, SVL / 8)); + CHECK_MAT_ROW( + ARM64_REG_ZAB0, 2, uint8_t, + fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, + 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, + SVL / 8)); + + for (int i = 3; i < SVL / 8; i++) { + CHECK_MAT_ROW(ARM64_REG_ZAB0, i, uint8_t, fillNeon({0}, SVL / 8)); + } +} + TEST_P(InstSme, smopa) { // 32-bit RUN_AARCH64(R"( From dca22ead36ae9fb3aff54a72acaadd040e1a171f Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Mon, 19 Aug 2024 16:46:20 +0100 Subject: [PATCH 34/48] Implemented SME ADDHA and ADDVA (S and D) instructions and regression tests. --- src/lib/arch/aarch64/Instruction_execute.cc | 138 +++++++++++++ test/regression/aarch64/instructions/sme.cc | 212 ++++++++++++++++++++ 2 files changed, 350 insertions(+) diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index c4cda5a41d..81468a00ff 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -108,6 +108,144 @@ void Instruction::execute() { } } else { switch (metadata_.opcode) { + case Opcode::AArch64_ADDHA_MPPZ_D: { // addha zada.d, pn/m, pm/m, zn.d + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 64; + const uint64_t* pn = sourceValues_[rowCount].getAsVector(); + const uint64_t* pm = + sourceValues_[rowCount + 1].getAsVector(); + const uint64_t* zn = + sourceValues_[rowCount + 2].getAsVector(); + + for (uint16_t row = 0; row < rowCount; row++) { + const uint64_t* zaRow = sourceValues_[row].getAsVector(); + uint64_t out[32] = {0}; + std::memcpy(out, zaRow, rowCount * sizeof(uint64_t)); + // Slice element is active IFF: + // - Element in 1st source pred corresponding to horiz. slice is TRUE + // - Corresponding element in 2nd source pred is TRUE + const uint64_t shifted_active_pn = 1ull << ((row % 8) * 8); + if (pn[row / 8] & shifted_active_pn) { + for (uint16_t elem = 0; elem < rowCount; elem++) { + const uint64_t shifted_active_pm = 1ull << ((elem % 8) * 8); + if (pm[elem / 8] & shifted_active_pm) { + out[elem] = zn[elem]; + } + } + } + results_[row] = {out, 256}; + } + break; + } + case Opcode::AArch64_ADDHA_MPPZ_S: { // addha zada.s, pn/m, pm/m, zn.s + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 32; + const uint64_t* pn = sourceValues_[rowCount].getAsVector(); + const uint64_t* pm = + sourceValues_[rowCount + 1].getAsVector(); + const uint32_t* zn = + sourceValues_[rowCount + 2].getAsVector(); + + for (uint16_t row = 0; row < rowCount; row++) { + const uint32_t* zaRow = sourceValues_[row].getAsVector(); + uint32_t out[64] = {0}; + std::memcpy(out, zaRow, rowCount * sizeof(uint32_t)); + // Slice element is active IFF: + // - Element in 1st source pred corresponding to horiz. slice is TRUE + // - Corresponding element in 2nd source pred is TRUE + const uint64_t shifted_active_pn = 1ull << ((row % 16) * 4); + if (pn[row / 16] & shifted_active_pn) { + for (uint16_t elem = 0; elem < rowCount; elem++) { + const uint64_t shifted_active_pm = 1ull << ((elem % 16) * 4); + if (pm[elem / 16] & shifted_active_pm) { + out[elem] = zn[elem]; + } + } + } + results_[row] = {out, 256}; + } + break; + } + case Opcode::AArch64_ADDVA_MPPZ_D: { // addva zada.d, pn/m, pm/m, zn.d + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 64; + const uint64_t* pn = sourceValues_[rowCount].getAsVector(); + const uint64_t* pm = + sourceValues_[rowCount + 1].getAsVector(); + const uint64_t* zn = + sourceValues_[rowCount + 2].getAsVector(); + + for (uint16_t row = 0; row < rowCount; row++) { + const uint64_t* zaRow = sourceValues_[row].getAsVector(); + uint64_t out[32] = {0}; + std::memcpy(out, zaRow, rowCount * sizeof(uint64_t)); + // Slice element is active IFF: + // - Corresponding element in 1st source pred is TRUE + // - Element in 2nd source pred corresponding to vert. slice is TRUE + const uint64_t shifted_active_pn = 1ull << ((row % 8) * 8); + if (pn[row / 8] & shifted_active_pn) { + // Corresponding slice element is active (i.e. all elements in row). + // Now check if each vertical slice (i.e. each row element) is + // active + for (uint16_t elem = 0; elem < rowCount; elem++) { + const uint64_t shifted_active_pm = 1ull << ((elem % 8) * 8); + if (pm[elem / 8] & shifted_active_pm) { + out[elem] = zn[elem]; + } + } + } + results_[row] = {out, 256}; + } + break; + } + case Opcode::AArch64_ADDVA_MPPZ_S: { // addva zada.s, pn/m, pm/m, zn.s + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 32; + const uint64_t* pn = sourceValues_[rowCount].getAsVector(); + const uint64_t* pm = + sourceValues_[rowCount + 1].getAsVector(); + const uint32_t* zn = + sourceValues_[rowCount + 2].getAsVector(); + + for (uint16_t row = 0; row < rowCount; row++) { + const uint32_t* zaRow = sourceValues_[row].getAsVector(); + uint32_t out[64] = {0}; + std::memcpy(out, zaRow, rowCount * sizeof(uint32_t)); + // Slice element is active IFF: + // - Corresponding element in 1st source pred is TRUE + // - Element in 2nd source pred corresponding to vert. slice is TRUE + const uint64_t shifted_active_pn = 1ull << ((row % 16) * 4); + if (pn[row / 16] & shifted_active_pn) { + // Corresponding slice element is active (i.e. all elements in row). + // Now check if each vertical slice (i.e. each row element) is + // active in 2nd pred + for (uint16_t elem = 0; elem < rowCount; elem++) { + const uint64_t shifted_active_pm = 1ull << ((elem % 16) * 4); + if (pm[elem / 16] & shifted_active_pm) { + out[elem] = zn[elem]; + } + } + } + results_[row] = {out, 256}; + } + break; + } case Opcode::AArch64_ADCXr: { // adc xd, xn, xm auto [result, nzcv] = addCarry_3ops(sourceValues_); (void)nzcv; // Prevent unused variable warnings in GCC7 diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index a4b783bb3c..6a7328cf01 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -8,6 +8,218 @@ namespace { using InstSme = AArch64RegressionTest; #if SIMENG_LLVM_VERSION >= 14 +TEST_P(InstSme, addha) { + // 32-bit + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.s + pfalse p1.b + zip1 p1.s, p0.s, p1.s + + dup z0.s, #3 + dup z1.s, #7 + + # Add to all rows and elems + addha za0.s, p0/m, p0/m, z0.s + + # Add to all rows, even numbered elements + addha za1.s, p0/m, p0/m, z0.s + addha za1.s, p0/m, p1/m, z1.s + + # Add to even rows, all elements + addha za2.s, p0/m, p0/m, z0.s + addha za2.s, p1/m, p0/m, z1.s + + # Checker-board add + addha za3.s, p0/m, p0/m, z0.s + addha za3.s, p1/m, p1/m, z1.s + )"); + for (int i = 0; i < (SVL / 32); i++) { + // All rows, all elems + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, + fillNeon({3}, (SVL / 8))); + // All rows, even elements + CHECK_MAT_ROW(ARM64_REG_ZAS1, i, uint32_t, + fillNeon({7, 3}, (SVL / 8))); + if (i % 2 == 0) { + // Even rows, all elements + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, uint32_t, + fillNeon({7}, (SVL / 8))); + // Checker-board + CHECK_MAT_ROW(ARM64_REG_ZAS3, i, uint32_t, + fillNeon({7, 3}, (SVL / 8))); + } else { + // Even rows, all elements + CHECK_MAT_ROW(ARM64_REG_ZAS2, i, uint32_t, + fillNeon({3}, (SVL / 8))); + // Checker-board + CHECK_MAT_ROW(ARM64_REG_ZAS3, i, uint32_t, + fillNeon({3}, (SVL / 8))); + } + } + + // 64-bit + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.d + pfalse p1.b + zip1 p1.d, p0.d, p1.d + + dup z0.d, #3 + dup z1.d, #7 + + # Add to all rows and elems + addha za0.d, p0/m, p0/m, z0.d + + # Add to all rows, even numbered elements + addha za1.d, p0/m, p0/m, z0.d + addha za1.d, p0/m, p1/m, z1.d + + # Add to even rows, all elements + addha za2.d, p0/m, p0/m, z0.d + addha za2.d, p1/m, p0/m, z1.d + + # Checker-board add + addha za3.d, p0/m, p0/m, z0.d + addha za3.d, p1/m, p1/m, z1.d + )"); + for (int i = 0; i < (SVL / 64); i++) { + // All rows, all elems + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, + fillNeon({3}, (SVL / 8))); + // All rows, even elements + CHECK_MAT_ROW(ARM64_REG_ZAD1, i, uint64_t, + fillNeon({7, 3}, (SVL / 8))); + if (i % 2 == 0) { + // Even rows, all elements + CHECK_MAT_ROW(ARM64_REG_ZAD2, i, uint64_t, + fillNeon({7}, (SVL / 8))); + // Checker-board + CHECK_MAT_ROW(ARM64_REG_ZAD3, i, uint64_t, + fillNeon({7, 3}, (SVL / 8))); + } else { + // Even rows, all elements + CHECK_MAT_ROW(ARM64_REG_ZAD2, i, uint64_t, + fillNeon({3}, (SVL / 8))); + // Checker-board + CHECK_MAT_ROW(ARM64_REG_ZAD3, i, uint64_t, + fillNeon({3}, (SVL / 8))); + } + } +} + +TEST_P(InstSme, addva) { + // 32-bit + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.s + pfalse p1.b + zip1 p1.s, p0.s, p1.s + + dup z0.s, #3 + dup z1.s, #7 + + # Add to all cols and elems + addva za0.s, p0/m, p0/m, z0.s + + # All cols, even elements + addva za1.s, p0/m, p0/m, z0.s + addva za1.s, p1/m, p0/m, z1.s + + # Add to even numbered cols, all elements + addva za2.s, p0/m, p0/m, z0.s + addva za2.s, p0/m, p1/m, z1.s + + # Checker-board add + addva za3.s, p0/m, p0/m, z0.s + addva za3.s, p1/m, p1/m, z1.s + )"); + for (int i = 0; i < (SVL / 32); i++) { + // All cols, all elems + CHECK_MAT_COL(ARM64_REG_ZAS0, i, uint32_t, + fillNeon({3}, (SVL / 8))); + // All cols, even elements + CHECK_MAT_COL(ARM64_REG_ZAS1, i, uint32_t, + fillNeon({7, 3}, (SVL / 8))); + if (i % 2 == 0) { + // Even cols, all elements + CHECK_MAT_COL(ARM64_REG_ZAS2, i, uint32_t, + fillNeon({7}, (SVL / 8))); + // Checker-board + CHECK_MAT_COL(ARM64_REG_ZAS3, i, uint32_t, + fillNeon({7, 3}, (SVL / 8))); + } else { + // Even cols, all elements + CHECK_MAT_COL(ARM64_REG_ZAS2, i, uint32_t, + fillNeon({3}, (SVL / 8))); + // Checker-board + CHECK_MAT_COL(ARM64_REG_ZAS3, i, uint32_t, + fillNeon({3}, (SVL / 8))); + } + } + + // 64-bit + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.d + pfalse p1.b + zip1 p1.d, p0.d, p1.d + + dup z0.d, #3 + dup z1.d, #7 + + # Add to all cols and elems + addva za0.d, p0/m, p0/m, z0.d + + # All cols, even elements + addva za1.d, p0/m, p0/m, z0.d + addva za1.d, p1/m, p0/m, z1.d + + # Add to even numbered cols, all elements + addva za2.d, p0/m, p0/m, z0.d + addva za2.d, p0/m, p1/m, z1.d + + # Checker-board add + addva za3.d, p0/m, p0/m, z0.d + addva za3.d, p1/m, p1/m, z1.d + )"); + for (int i = 0; i < (SVL / 64); i++) { + // All rows, all elems + CHECK_MAT_COL(ARM64_REG_ZAD0, i, uint64_t, + fillNeon({3}, (SVL / 8))); + // All cols, even elements + CHECK_MAT_COL(ARM64_REG_ZAD1, i, uint64_t, + fillNeon({7, 3}, (SVL / 8))); + if (i % 2 == 0) { + // Even cols, all elements + CHECK_MAT_COL(ARM64_REG_ZAD2, i, uint64_t, + fillNeon({7}, (SVL / 8))); + // Checker-board + CHECK_MAT_COL(ARM64_REG_ZAD3, i, uint64_t, + fillNeon({7, 3}, (SVL / 8))); + } else { + // Even cols, all elements + CHECK_MAT_COL(ARM64_REG_ZAD2, i, uint64_t, + fillNeon({3}, (SVL / 8))); + // Checker-board + CHECK_MAT_COL(ARM64_REG_ZAD3, i, uint64_t, + fillNeon({3}, (SVL / 8))); + } + } +} + TEST_P(InstSme, mova_tileToVec) { // 8-bit initialHeapData_.resize(SVL / 4); From b5857012f093d86001242b7b135e5f1ff6354ece Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Tue, 20 Aug 2024 10:38:48 +0100 Subject: [PATCH 35/48] Updated ADDHA test to make more specific. --- test/regression/aarch64/instructions/sme.cc | 54 ++++++++++++++------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index 6a7328cf01..5000f21ced 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -19,11 +19,11 @@ TEST_P(InstSme, addha) { pfalse p1.b zip1 p1.s, p0.s, p1.s - dup z0.s, #3 - dup z1.s, #7 + dup z0.s, #65 + index z1.s, #0, #1 # Add to all rows and elems - addha za0.s, p0/m, p0/m, z0.s + addha za0.s, p0/m, p0/m, z1.s # Add to all rows, even numbered elements addha za1.s, p0/m, p0/m, z0.s @@ -37,27 +37,36 @@ TEST_P(InstSme, addha) { addha za3.s, p0/m, p0/m, z0.s addha za3.s, p1/m, p1/m, z1.s )"); + std::vector full32(64, 0); + std::vector inter32(64, 0); + std::vector index32(64, 0); + for (int i = 0; i < 64; i++) { + full32[i] = 65; + index32[i] = i; + inter32[i] = (i % 2 == 0) ? i : 65; + } + for (int i = 0; i < (SVL / 32); i++) { // All rows, all elems CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, - fillNeon({3}, (SVL / 8))); + fillNeon(index32, (SVL / 8))); // All rows, even elements CHECK_MAT_ROW(ARM64_REG_ZAS1, i, uint32_t, - fillNeon({7, 3}, (SVL / 8))); + fillNeon(inter32, (SVL / 8))); if (i % 2 == 0) { // Even rows, all elements CHECK_MAT_ROW(ARM64_REG_ZAS2, i, uint32_t, - fillNeon({7}, (SVL / 8))); + fillNeon(index32, (SVL / 8))); // Checker-board CHECK_MAT_ROW(ARM64_REG_ZAS3, i, uint32_t, - fillNeon({7, 3}, (SVL / 8))); + fillNeon(inter32, (SVL / 8))); } else { // Even rows, all elements CHECK_MAT_ROW(ARM64_REG_ZAS2, i, uint32_t, - fillNeon({3}, (SVL / 8))); + fillNeon(full32, (SVL / 8))); // Checker-board CHECK_MAT_ROW(ARM64_REG_ZAS3, i, uint32_t, - fillNeon({3}, (SVL / 8))); + fillNeon(full32, (SVL / 8))); } } @@ -71,11 +80,11 @@ TEST_P(InstSme, addha) { pfalse p1.b zip1 p1.d, p0.d, p1.d - dup z0.d, #3 - dup z1.d, #7 + dup z0.d, #65 + index z1.d, #0, #1 # Add to all rows and elems - addha za0.d, p0/m, p0/m, z0.d + addha za0.d, p0/m, p0/m, z1.d # Add to all rows, even numbered elements addha za1.d, p0/m, p0/m, z0.d @@ -89,27 +98,36 @@ TEST_P(InstSme, addha) { addha za3.d, p0/m, p0/m, z0.d addha za3.d, p1/m, p1/m, z1.d )"); + std::vector full64(32, 0); + std::vector inter64(32, 0); + std::vector index64(32, 0); + for (int i = 0; i < 32; i++) { + full64[i] = 65; + index64[i] = i; + inter64[i] = (i % 2 == 0) ? i : 65; + } + for (int i = 0; i < (SVL / 64); i++) { // All rows, all elems CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, - fillNeon({3}, (SVL / 8))); + fillNeon(index64, (SVL / 8))); // All rows, even elements CHECK_MAT_ROW(ARM64_REG_ZAD1, i, uint64_t, - fillNeon({7, 3}, (SVL / 8))); + fillNeon(inter64, (SVL / 8))); if (i % 2 == 0) { // Even rows, all elements CHECK_MAT_ROW(ARM64_REG_ZAD2, i, uint64_t, - fillNeon({7}, (SVL / 8))); + fillNeon(index64, (SVL / 8))); // Checker-board CHECK_MAT_ROW(ARM64_REG_ZAD3, i, uint64_t, - fillNeon({7, 3}, (SVL / 8))); + fillNeon(inter64, (SVL / 8))); } else { // Even rows, all elements CHECK_MAT_ROW(ARM64_REG_ZAD2, i, uint64_t, - fillNeon({3}, (SVL / 8))); + fillNeon(full64, (SVL / 8))); // Checker-board CHECK_MAT_ROW(ARM64_REG_ZAD3, i, uint64_t, - fillNeon({3}, (SVL / 8))); + fillNeon(full64, (SVL / 8))); } } } From 53959cfc773f38c1c3255e57496e19c846a4c1ba Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Tue, 20 Aug 2024 10:52:56 +0100 Subject: [PATCH 36/48] Corrected ADDVA execution logic. --- src/lib/arch/aarch64/Instruction_execute.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 81468a00ff..10b35b03f0 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -202,7 +202,7 @@ void Instruction::execute() { for (uint16_t elem = 0; elem < rowCount; elem++) { const uint64_t shifted_active_pm = 1ull << ((elem % 8) * 8); if (pm[elem / 8] & shifted_active_pm) { - out[elem] = zn[elem]; + out[elem] = zn[row]; } } } @@ -238,7 +238,7 @@ void Instruction::execute() { for (uint16_t elem = 0; elem < rowCount; elem++) { const uint64_t shifted_active_pm = 1ull << ((elem % 16) * 4); if (pm[elem / 16] & shifted_active_pm) { - out[elem] = zn[elem]; + out[elem] = zn[row]; } } } From a6b61e7f563994519b7de3e56e106ed9a01df858 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Tue, 20 Aug 2024 10:53:07 +0100 Subject: [PATCH 37/48] Updated ADDVA test to make more specific. --- test/regression/aarch64/instructions/sme.cc | 100 ++++++++++++-------- 1 file changed, 63 insertions(+), 37 deletions(-) diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index 5000f21ced..a7af8d0f9e 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -33,23 +33,25 @@ TEST_P(InstSme, addha) { addha za2.s, p0/m, p0/m, z0.s addha za2.s, p1/m, p0/m, z1.s - # Checker-board add + # Even numbered rows, even numbered elements addha za3.s, p0/m, p0/m, z0.s addha za3.s, p1/m, p1/m, z1.s )"); std::vector full32(64, 0); - std::vector inter32(64, 0); std::vector index32(64, 0); + std::vector inter32(64, 0); for (int i = 0; i < 64; i++) { full32[i] = 65; index32[i] = i; inter32[i] = (i % 2 == 0) ? i : 65; } - for (int i = 0; i < (SVL / 32); i++) { + for (uint32_t i = 0; i < (SVL / 32); i++) { // All rows, all elems CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, fillNeon(index32, (SVL / 8))); + CHECK_MAT_COL(ARM64_REG_ZAS0, i, uint32_t, + fillNeon({i}, (SVL / 8))); // All rows, even elements CHECK_MAT_ROW(ARM64_REG_ZAS1, i, uint32_t, fillNeon(inter32, (SVL / 8))); @@ -57,14 +59,14 @@ TEST_P(InstSme, addha) { // Even rows, all elements CHECK_MAT_ROW(ARM64_REG_ZAS2, i, uint32_t, fillNeon(index32, (SVL / 8))); - // Checker-board + // Even rows, even elements CHECK_MAT_ROW(ARM64_REG_ZAS3, i, uint32_t, fillNeon(inter32, (SVL / 8))); } else { // Even rows, all elements CHECK_MAT_ROW(ARM64_REG_ZAS2, i, uint32_t, fillNeon(full32, (SVL / 8))); - // Checker-board + // Even rows, even elements CHECK_MAT_ROW(ARM64_REG_ZAS3, i, uint32_t, fillNeon(full32, (SVL / 8))); } @@ -94,23 +96,25 @@ TEST_P(InstSme, addha) { addha za2.d, p0/m, p0/m, z0.d addha za2.d, p1/m, p0/m, z1.d - # Checker-board add + # Even numbered rows, even numbered elements addha za3.d, p0/m, p0/m, z0.d addha za3.d, p1/m, p1/m, z1.d )"); std::vector full64(32, 0); - std::vector inter64(32, 0); std::vector index64(32, 0); + std::vector inter64(32, 0); for (int i = 0; i < 32; i++) { full64[i] = 65; index64[i] = i; inter64[i] = (i % 2 == 0) ? i : 65; } - for (int i = 0; i < (SVL / 64); i++) { + for (uint64_t i = 0; i < (SVL / 64); i++) { // All rows, all elems CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, fillNeon(index64, (SVL / 8))); + CHECK_MAT_COL(ARM64_REG_ZAD0, i, uint64_t, + fillNeon({i}, (SVL / 8))); // All rows, even elements CHECK_MAT_ROW(ARM64_REG_ZAD1, i, uint64_t, fillNeon(inter64, (SVL / 8))); @@ -118,14 +122,14 @@ TEST_P(InstSme, addha) { // Even rows, all elements CHECK_MAT_ROW(ARM64_REG_ZAD2, i, uint64_t, fillNeon(index64, (SVL / 8))); - // Checker-board + // Even rows, even elements CHECK_MAT_ROW(ARM64_REG_ZAD3, i, uint64_t, fillNeon(inter64, (SVL / 8))); } else { // Even rows, all elements CHECK_MAT_ROW(ARM64_REG_ZAD2, i, uint64_t, fillNeon(full64, (SVL / 8))); - // Checker-board + // Even rows, even elements CHECK_MAT_ROW(ARM64_REG_ZAD3, i, uint64_t, fillNeon(full64, (SVL / 8))); } @@ -143,11 +147,11 @@ TEST_P(InstSme, addva) { pfalse p1.b zip1 p1.s, p0.s, p1.s - dup z0.s, #3 - dup z1.s, #7 + dup z0.s, #65 + index z1.s, #0, #1 # Add to all cols and elems - addva za0.s, p0/m, p0/m, z0.s + addva za0.s, p0/m, p0/m, z1.s # All cols, even elements addva za1.s, p0/m, p0/m, z0.s @@ -157,31 +161,42 @@ TEST_P(InstSme, addva) { addva za2.s, p0/m, p0/m, z0.s addva za2.s, p0/m, p1/m, z1.s - # Checker-board add + # Even numbered cols, even numbered elements addva za3.s, p0/m, p0/m, z0.s addva za3.s, p1/m, p1/m, z1.s )"); - for (int i = 0; i < (SVL / 32); i++) { + std::vector full32(64, 0); + std::vector index32(64, 0); + std::vector inter32(64, 0); + for (int i = 0; i < 64; i++) { + full32[i] = 65; + index32[i] = i; + inter32[i] = (i % 2 == 0) ? i : 65; + } + + for (uint32_t i = 0; i < (SVL / 32); i++) { // All cols, all elems CHECK_MAT_COL(ARM64_REG_ZAS0, i, uint32_t, - fillNeon({3}, (SVL / 8))); + fillNeon(index32, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, + fillNeon({i}, (SVL / 8))); // All cols, even elements CHECK_MAT_COL(ARM64_REG_ZAS1, i, uint32_t, - fillNeon({7, 3}, (SVL / 8))); + fillNeon(inter32, (SVL / 8))); if (i % 2 == 0) { // Even cols, all elements CHECK_MAT_COL(ARM64_REG_ZAS2, i, uint32_t, - fillNeon({7}, (SVL / 8))); - // Checker-board + fillNeon(index32, (SVL / 8))); + // Even cols, even elements CHECK_MAT_COL(ARM64_REG_ZAS3, i, uint32_t, - fillNeon({7, 3}, (SVL / 8))); + fillNeon(inter32, (SVL / 8))); } else { // Even cols, all elements CHECK_MAT_COL(ARM64_REG_ZAS2, i, uint32_t, - fillNeon({3}, (SVL / 8))); - // Checker-board + fillNeon(full32, (SVL / 8))); + // Even cols, even elements CHECK_MAT_COL(ARM64_REG_ZAS3, i, uint32_t, - fillNeon({3}, (SVL / 8))); + fillNeon(full32, (SVL / 8))); } } @@ -195,11 +210,11 @@ TEST_P(InstSme, addva) { pfalse p1.b zip1 p1.d, p0.d, p1.d - dup z0.d, #3 - dup z1.d, #7 + dup z0.d, #65 + index z1.d, #0, #1 # Add to all cols and elems - addva za0.d, p0/m, p0/m, z0.d + addva za0.d, p0/m, p0/m, z1.d # All cols, even elements addva za1.d, p0/m, p0/m, z0.d @@ -209,31 +224,42 @@ TEST_P(InstSme, addva) { addva za2.d, p0/m, p0/m, z0.d addva za2.d, p0/m, p1/m, z1.d - # Checker-board add + # Even numbered cols, even numbered elements addva za3.d, p0/m, p0/m, z0.d addva za3.d, p1/m, p1/m, z1.d )"); - for (int i = 0; i < (SVL / 64); i++) { - // All rows, all elems + std::vector full64(32, 0); + std::vector index64(32, 0); + std::vector inter64(32, 0); + for (int i = 0; i < 32; i++) { + full64[i] = 65; + index64[i] = i; + inter64[i] = (i % 2 == 0) ? i : 65; + } + + for (uint64_t i = 0; i < (SVL / 64); i++) { + // All cols, all elems CHECK_MAT_COL(ARM64_REG_ZAD0, i, uint64_t, - fillNeon({3}, (SVL / 8))); + fillNeon(index64, (SVL / 8))); + CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, + fillNeon({i}, (SVL / 8))); // All cols, even elements CHECK_MAT_COL(ARM64_REG_ZAD1, i, uint64_t, - fillNeon({7, 3}, (SVL / 8))); + fillNeon(inter64, (SVL / 8))); if (i % 2 == 0) { // Even cols, all elements CHECK_MAT_COL(ARM64_REG_ZAD2, i, uint64_t, - fillNeon({7}, (SVL / 8))); - // Checker-board + fillNeon(index64, (SVL / 8))); + // Even cols, even elements CHECK_MAT_COL(ARM64_REG_ZAD3, i, uint64_t, - fillNeon({7, 3}, (SVL / 8))); + fillNeon(inter64, (SVL / 8))); } else { // Even cols, all elements CHECK_MAT_COL(ARM64_REG_ZAD2, i, uint64_t, - fillNeon({3}, (SVL / 8))); - // Checker-board + fillNeon(full64, (SVL / 8))); + // Even cols, even elements CHECK_MAT_COL(ARM64_REG_ZAD3, i, uint64_t, - fillNeon({3}, (SVL / 8))); + fillNeon(full64, (SVL / 8))); } } } From 857cd9b3a4a3741f519e4182c9c9c64b46696d7e Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Tue, 20 Aug 2024 13:30:25 +0100 Subject: [PATCH 38/48] Added SME MOVA (tile to vec, vec to tile) Quad-word instructions and regression tests. --- src/lib/arch/aarch64/InstructionMetadata.cc | 4 + src/lib/arch/aarch64/Instruction_execute.cc | 169 ++++++++++++-- test/regression/aarch64/instructions/sme.cc | 235 ++++++++++++++++++-- 3 files changed, 371 insertions(+), 37 deletions(-) diff --git a/src/lib/arch/aarch64/InstructionMetadata.cc b/src/lib/arch/aarch64/InstructionMetadata.cc index 7e556c4e59..56e438a3d8 100644 --- a/src/lib/arch/aarch64/InstructionMetadata.cc +++ b/src/lib/arch/aarch64/InstructionMetadata.cc @@ -239,6 +239,8 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) [[fallthrough]]; case Opcode::AArch64_INSERT_MXIPZ_H_H: [[fallthrough]]; + case Opcode::AArch64_INSERT_MXIPZ_H_Q: + [[fallthrough]]; case Opcode::AArch64_INSERT_MXIPZ_H_S: [[fallthrough]]; case Opcode::AArch64_INSERT_MXIPZ_V_B: @@ -247,6 +249,8 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) [[fallthrough]]; case Opcode::AArch64_INSERT_MXIPZ_V_H: [[fallthrough]]; + case Opcode::AArch64_INSERT_MXIPZ_V_Q: + [[fallthrough]]; case Opcode::AArch64_INSERT_MXIPZ_V_S: // Need to add access specifiers // although operands[0] should be READ | WRITE, due to the implemented diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 10b35b03f0..b70f744639 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -1365,7 +1365,7 @@ void Instruction::execute() { [](uint8_t x, uint8_t y) -> uint8_t { return x ^ y; }); break; } - case Opcode::AArch64_EXTRACT_ZPMXI_H_B: { // MOVA zd.b, pg/m, zanh.b[ws, + case Opcode::AArch64_EXTRACT_ZPMXI_H_B: { // mova zd.b, pg/m, zanh.b[ws, // #imm] // SME // Check core is in correct context mode (check SM first) @@ -1394,7 +1394,7 @@ void Instruction::execute() { results_[0] = {out, 256}; break; } - case Opcode::AArch64_EXTRACT_ZPMXI_H_D: { // MOVA zd.d, pg/m, zanh.d[ws, + case Opcode::AArch64_EXTRACT_ZPMXI_H_D: { // mova zd.d, pg/m, zanh.d[ws, // #imm] // SME // Check core is in correct context mode (check SM first) @@ -1422,7 +1422,7 @@ void Instruction::execute() { results_[0] = {out, 256}; break; } - case Opcode::AArch64_EXTRACT_ZPMXI_H_H: { // MOVA zd.h, pg/m, zanh.h[ws, + case Opcode::AArch64_EXTRACT_ZPMXI_H_H: { // mova zd.h, pg/m, zanh.h[ws, // #imm] // SME // Check core is in correct context mode (check SM first) @@ -1450,7 +1450,41 @@ void Instruction::execute() { results_[0] = {out, 256}; break; } - case Opcode::AArch64_EXTRACT_ZPMXI_H_S: { // MOVA zd.s, pg/m, zanh.s[ws, + case Opcode::AArch64_EXTRACT_ZPMXI_H_Q: { // mova zd.q, pg/m, zanh.q[ws] + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 128; + // Use uint64_t as no 128-bit + const uint64_t* zd = sourceValues_[0].getAsVector(); + const uint64_t* pg = sourceValues_[1].getAsVector(); + const uint32_t sliceNum = + sourceValues_[2 + rowCount].get() % rowCount; + // Use uint64_t as no 128-bit + const uint64_t* zaRow = + sourceValues_[2 + sliceNum].getAsVector(); + + // Use uint64_t as no 128-bit + uint64_t out[32] = {0}; + for (int elem = 0; elem < rowCount; elem++) { + // For 128-bit there are 16-bit for each active element + uint64_t shifted_active = 1ull << ((elem % 4) * 16); + if (pg[elem / 4] & shifted_active) { + // Need to move two consecutive 64-bit elements + out[2 * elem] = zaRow[2 * elem]; + out[2 * elem + 1] = zaRow[2 * elem + 1]; + } else { + // Need to move two consecutive 64-bit elements + out[2 * elem] = zd[2 * elem]; + out[2 * elem + 1] = zd[2 * elem + 1]; + } + } + results_[0] = {out, 256}; + break; + } + case Opcode::AArch64_EXTRACT_ZPMXI_H_S: { // mova zd.s, pg/m, zanh.s[ws, // #imm] // SME // Check core is in correct context mode (check SM first) @@ -1478,7 +1512,7 @@ void Instruction::execute() { results_[0] = {out, 256}; break; } - case Opcode::AArch64_EXTRACT_ZPMXI_V_B: { // MOVA zd.b, pg/m, zanv.b[ws, + case Opcode::AArch64_EXTRACT_ZPMXI_V_B: { // mova zd.b, pg/m, zanv.b[ws, // #imm] // SME // Check core is in correct context mode (check SM first) @@ -1505,7 +1539,7 @@ void Instruction::execute() { results_[0] = {out, 256}; break; } - case Opcode::AArch64_EXTRACT_ZPMXI_V_D: { // MOVA zd.d, pg/m, zanv.d[ws, + case Opcode::AArch64_EXTRACT_ZPMXI_V_D: { // mova zd.d, pg/m, zanv.d[ws, // #imm] // SME // Check core is in correct context mode (check SM first) @@ -1532,7 +1566,7 @@ void Instruction::execute() { results_[0] = {out, 256}; break; } - case Opcode::AArch64_EXTRACT_ZPMXI_V_H: { // MOVA zd.h, pg/m, zanv.h[ws, + case Opcode::AArch64_EXTRACT_ZPMXI_V_H: { // mova zd.h, pg/m, zanv.h[ws, // #imm] // SME // Check core is in correct context mode (check SM first) @@ -1559,7 +1593,40 @@ void Instruction::execute() { results_[0] = {out, 256}; break; } - case Opcode::AArch64_EXTRACT_ZPMXI_V_S: { // MOVA zd.s, pg/m, zanv.s[ws, + case Opcode::AArch64_EXTRACT_ZPMXI_V_Q: { // mova zd.q, pg/m, zanv.q[ws] + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 128; + // Use uint64_t as no 128-bit + const uint64_t* zd = sourceValues_[0].getAsVector(); + const uint64_t* pg = sourceValues_[1].getAsVector(); + const uint32_t sliceNum = + sourceValues_[2 + rowCount].get() % rowCount; + + // Use uint64_t as no 128-bit + uint64_t out[32] = {0}; + for (uint16_t elem = 0; elem < rowCount; elem++) { + // For 128-bit there are 16-bit for each active element + uint64_t shifted_active = 1ull << ((elem % 4) * 16); + if (pg[elem / 4] & shifted_active) { + // Need to move two consecutive 64-bit elements + const uint64_t* zaRow = + sourceValues_[2 + elem].getAsVector(); + out[2 * elem] = zaRow[2 * sliceNum]; + out[2 * elem + 1] = zaRow[2 * sliceNum + 1]; + } else { + // Need to move two consecutive 64-bit elements + out[2 * elem] = zd[2 * elem]; + out[2 * elem + 1] = zd[2 * elem + 1]; + } + } + results_[0] = {out, 256}; + break; + } + case Opcode::AArch64_EXTRACT_ZPMXI_V_S: { // mova zd.s, pg/m, zanv.s[ws, // #imm] // SME // Check core is in correct context mode (check SM first) @@ -2923,7 +2990,7 @@ void Instruction::execute() { break; } - case Opcode::AArch64_INSERT_MXIPZ_H_B: { // mova za0h.b[ws, #imm], pg/m, + case Opcode::AArch64_INSERT_MXIPZ_H_B: { // mova zadh.b[ws, #imm], pg/m, // zn.b // SME // Check core is in correct context mode (check SM first) @@ -2955,7 +3022,7 @@ void Instruction::execute() { } break; } - case Opcode::AArch64_INSERT_MXIPZ_H_D: { // mova za0h.d[ws, #imm], pg/m, + case Opcode::AArch64_INSERT_MXIPZ_H_D: { // mova zadh.d[ws, #imm], pg/m, // zn.d // SME // Check core is in correct context mode (check SM first) @@ -2988,7 +3055,7 @@ void Instruction::execute() { } break; } - case Opcode::AArch64_INSERT_MXIPZ_H_H: { // mova za0h.h[ws, #imm], pg/m, + case Opcode::AArch64_INSERT_MXIPZ_H_H: { // mova zadh.h[ws, #imm], pg/m, // zn.h // SME // Check core is in correct context mode (check SM first) @@ -3021,7 +3088,47 @@ void Instruction::execute() { } break; } - case Opcode::AArch64_INSERT_MXIPZ_H_S: { // mova za0h.s[ws, #imm], pg/m, + case Opcode::AArch64_INSERT_MXIPZ_H_Q: { // mova zadh.q[ws], pg/m, zn.q + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 128; + const uint32_t sliceNum = + sourceValues_[rowCount].get() % rowCount; + // Use uint64_t in place of 128-bit + const uint64_t* zaRow = sourceValues_[sliceNum].getAsVector(); + + const uint64_t* pg = + sourceValues_[rowCount + 1].getAsVector(); + // Use uint64_t in place of 128-bit + const uint64_t* zn = + sourceValues_[rowCount + 2].getAsVector(); + + // Use uint64_t in place of 128-bit + uint64_t out[32] = {0}; + for (uint16_t elem = 0; elem < rowCount; elem++) { + // For 128-bit there are 16-bit for each active element + uint64_t shifted_active = 1ull << ((elem % 4) * 16); + if (pg[elem / 4] & shifted_active) { + // Need to move two consecutive 64-bit elements + out[(2 * elem)] = zn[(2 * elem)]; + out[(2 * elem + 1)] = zn[(2 * elem + 1)]; + } else { + // Need to move two consecutive 64-bit elements + out[(2 * elem)] = zaRow[(2 * elem)]; + out[(2 * elem + 1)] = zaRow[(2 * elem + 1)]; + } + } + // Need to update whole za tile + for (uint16_t row = 0; row < rowCount; row++) { + results_[row] = + (row == sliceNum) ? RegisterValue(out, 256) : sourceValues_[row]; + } + break; + } + case Opcode::AArch64_INSERT_MXIPZ_H_S: { // mova zadh.s[ws, #imm], pg/m, // zn.s // SME // Check core is in correct context mode (check SM first) @@ -3054,7 +3161,7 @@ void Instruction::execute() { } break; } - case Opcode::AArch64_INSERT_MXIPZ_V_B: { // mova za0v.b[ws, #imm], pg/m, + case Opcode::AArch64_INSERT_MXIPZ_V_B: { // mova zadv.b[ws, #imm], pg/m, // zn.b // SME // Check core is in correct context mode (check SM first) @@ -3079,7 +3186,7 @@ void Instruction::execute() { } break; } - case Opcode::AArch64_INSERT_MXIPZ_V_D: { // mova za0v.d[ws, #imm], pg/m, + case Opcode::AArch64_INSERT_MXIPZ_V_D: { // mova zadv.d[ws, #imm], pg/m, // zn.d // SME // Check core is in correct context mode (check SM first) @@ -3105,7 +3212,7 @@ void Instruction::execute() { } break; } - case Opcode::AArch64_INSERT_MXIPZ_V_H: { // mova za0v.h[ws, #imm], pg/m, + case Opcode::AArch64_INSERT_MXIPZ_V_H: { // mova zadv.h[ws, #imm], pg/m, // zn.h // SME // Check core is in correct context mode (check SM first) @@ -3131,7 +3238,37 @@ void Instruction::execute() { } break; } - case Opcode::AArch64_INSERT_MXIPZ_V_S: { // mova za0v.s[ws, #imm], pg/m, + case Opcode::AArch64_INSERT_MXIPZ_V_Q: { // mova zadv.q[ws], pg/m, zn.q + // SME + // Check core is in correct context mode (check SM first) + if (!SMenabled) return SMdisabled(); + if (!ZAenabled) return ZAdisabled(); + + const uint16_t rowCount = VL_bits / 128; + const uint32_t sliceNum = + sourceValues_[rowCount].get() % rowCount; + const uint64_t* pg = + sourceValues_[rowCount + 1].getAsVector(); + // Use uint64_t in place of 128-bit + const uint64_t* zn = + sourceValues_[rowCount + 2].getAsVector(); + + for (uint16_t i = 0; i < rowCount; i++) { + // Use uint64_t in place of 128-bit + uint64_t* row = + const_cast(sourceValues_[i].getAsVector()); + // For 128-bit there are 16-bit for each active element + uint64_t shifted_active = 1ull << ((i % 4) * 16); + if (pg[i / 4] & shifted_active) { + // Need to move two consecutive 64-bit elements + row[2 * sliceNum] = zn[2 * i]; + row[2 * sliceNum + 1] = zn[2 * i + 1]; + } + results_[i] = {(char*)row, 256}; + } + break; + } + case Opcode::AArch64_INSERT_MXIPZ_V_S: { // mova zadv.s[ws, #imm], pg/m, // zn.s // SME // Check core is in correct context mode (check SM first) diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index a7af8d0f9e..23a54a9080 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -40,7 +40,7 @@ TEST_P(InstSme, addha) { std::vector full32(64, 0); std::vector index32(64, 0); std::vector inter32(64, 0); - for (int i = 0; i < 64; i++) { + for (uint16_t i = 0; i < 64; i++) { full32[i] = 65; index32[i] = i; inter32[i] = (i % 2 == 0) ? i : 65; @@ -103,7 +103,7 @@ TEST_P(InstSme, addha) { std::vector full64(32, 0); std::vector index64(32, 0); std::vector inter64(32, 0); - for (int i = 0; i < 32; i++) { + for (uint16_t i = 0; i < 32; i++) { full64[i] = 65; index64[i] = i; inter64[i] = (i % 2 == 0) ? i : 65; @@ -168,7 +168,7 @@ TEST_P(InstSme, addva) { std::vector full32(64, 0); std::vector index32(64, 0); std::vector inter32(64, 0); - for (int i = 0; i < 64; i++) { + for (uint16_t i = 0; i < 64; i++) { full32[i] = 65; index32[i] = i; inter32[i] = (i % 2 == 0) ? i : 65; @@ -231,7 +231,7 @@ TEST_P(InstSme, addva) { std::vector full64(32, 0); std::vector index64(32, 0); std::vector inter64(32, 0); - for (int i = 0; i < 32; i++) { + for (uint16_t i = 0; i < 32; i++) { full64[i] = 65; index64[i] = i; inter64[i] = (i % 2 == 0) ? i : 65; @@ -547,6 +547,84 @@ TEST_P(InstSme, mova_tileToVec) { 6, uint64_t, fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); CHECK_NEON(7, uint64_t, fillNeon({0xDEADBEEF12345678, 8}, SVL / 8)); + + // 128-bit + // Re-use 64-bit heap + initialHeapData_.resize(SVL / 4); + heap64 = reinterpret_cast(initialHeapData_.data()); + fillHeap(heap64, src64, SVL / 32); + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + ptrue p0.d + pfalse p1.b + # Zip1 twice to get on-off-on-off pattern with quadwords + zip1 p1.d, p0.d, p1.d + zip1 p1.d, p1.d, p1.d + + mov w12, #0 + dup z0.d, #1 + dup z1.d, #2 + dup z2.d, #3 + dup z3.d, #4 + dup z4.d, #5 + dup z5.d, #6 + dup z6.d, #7 + dup z7.d, #8 + + # Horizontal + ld1d {za0h.d[w12, #0]}, p0/z, [x0] + mova z0.q, p0/m, za0h.q[w12, #0] + mova z1.q, p1/m, za0h.q[w12, #0] + #Alias + mov z4.q, p0/m, za0h.q[w12, #0] + mov z5.q, p1/m, za0h.q[w12, #0] + + # Vertical + mov w12, #1 + ld1d {z8.d}, p0/z, [x0] + mova za0v.q[w12, #0], p0/m, z8.q + mova z2.q, p0/m, za0v.q[w12, #0] + mova z3.q, p1/m, za0v.q[w12, #0] + #Alias + mov z6.q, p0/m, za0v.q[w12, #0] + mov z7.q, p1/m, za0v.q[w12, #0] + )"); + // Horizontal + CHECK_NEON( + 0, uint64_t, + fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); + CHECK_NEON(1, uint64_t, + fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01, 2, 2}, + SVL / 8)); + // Vertical + CHECK_NEON( + 2, uint64_t, + fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); + CHECK_NEON(3, uint64_t, + fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01, 4, 4}, + SVL / 8)); + // Horizontal + CHECK_NEON( + 4, uint64_t, + fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); + CHECK_NEON(5, uint64_t, + fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01, 6, 6}, + SVL / 8)); + // Vertical + CHECK_NEON( + 6, uint64_t, + fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); + CHECK_NEON(7, uint64_t, + fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01, 8, 8}, + SVL / 8)); } TEST_P(InstSme, mova_b_vecToTile) { @@ -571,7 +649,7 @@ TEST_P(InstSme, mova_b_vecToTile) { CHECK_MAT_ROW(ARM64_REG_ZAB0, 0, uint8_t, fillNeon({1}, (SVL / 8))); CHECK_MAT_ROW(ARM64_REG_ZAB0, 1, uint8_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 8; i++) { + for (uint16_t i = 2; i < SVL / 8; i++) { CHECK_MAT_ROW(ARM64_REG_ZAB0, i, uint8_t, fillNeon({0}, (SVL / 8))); } @@ -596,7 +674,7 @@ TEST_P(InstSme, mova_b_vecToTile) { CHECK_MAT_ROW(ARM64_REG_ZAB0, 0, uint8_t, fillNeon({1}, (SVL / 8))); CHECK_MAT_ROW(ARM64_REG_ZAB0, 1, uint8_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 8; i++) { + for (uint16_t i = 2; i < SVL / 8; i++) { CHECK_MAT_ROW(ARM64_REG_ZAB0, i, uint8_t, fillNeon({0}, (SVL / 8))); } @@ -621,7 +699,7 @@ TEST_P(InstSme, mova_b_vecToTile) { CHECK_MAT_COL(ARM64_REG_ZAB0, 0, uint8_t, fillNeon({1}, (SVL / 8))); CHECK_MAT_COL(ARM64_REG_ZAB0, 1, uint8_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 8; i++) { + for (uint16_t i = 2; i < SVL / 8; i++) { CHECK_MAT_COL(ARM64_REG_ZAB0, i, uint8_t, fillNeon({0}, (SVL / 8))); } @@ -646,7 +724,7 @@ TEST_P(InstSme, mova_b_vecToTile) { CHECK_MAT_COL(ARM64_REG_ZAB0, 0, uint8_t, fillNeon({1}, (SVL / 8))); CHECK_MAT_COL(ARM64_REG_ZAB0, 1, uint8_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 8; i++) { + for (uint16_t i = 2; i < SVL / 8; i++) { CHECK_MAT_COL(ARM64_REG_ZAB0, i, uint8_t, fillNeon({0}, (SVL / 8))); } @@ -675,7 +753,7 @@ TEST_P(InstSme, mova_h_vecToTile) { fillNeon({1}, (SVL / 8))); CHECK_MAT_ROW(ARM64_REG_ZAH0, 1, uint16_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 16; i++) { + for (uint16_t i = 2; i < SVL / 16; i++) { CHECK_MAT_ROW(ARM64_REG_ZAH0, i, uint16_t, fillNeon({0}, (SVL / 8))); } @@ -701,7 +779,7 @@ TEST_P(InstSme, mova_h_vecToTile) { fillNeon({1}, (SVL / 8))); CHECK_MAT_ROW(ARM64_REG_ZAH0, 1, uint16_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 16; i++) { + for (uint16_t i = 2; i < SVL / 16; i++) { CHECK_MAT_ROW(ARM64_REG_ZAH0, i, uint16_t, fillNeon({0}, (SVL / 8))); } @@ -727,7 +805,7 @@ TEST_P(InstSme, mova_h_vecToTile) { fillNeon({1}, (SVL / 8))); CHECK_MAT_COL(ARM64_REG_ZAH0, 1, uint16_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 16; i++) { + for (uint16_t i = 2; i < SVL / 16; i++) { CHECK_MAT_COL(ARM64_REG_ZAH0, i, uint16_t, fillNeon({0}, (SVL / 8))); } @@ -753,7 +831,7 @@ TEST_P(InstSme, mova_h_vecToTile) { fillNeon({1}, (SVL / 8))); CHECK_MAT_COL(ARM64_REG_ZAH0, 1, uint16_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 16; i++) { + for (uint16_t i = 2; i < SVL / 16; i++) { CHECK_MAT_COL(ARM64_REG_ZAH0, i, uint16_t, fillNeon({0}, (SVL / 8))); } @@ -782,7 +860,7 @@ TEST_P(InstSme, mova_s_vecToTile) { fillNeon({1}, (SVL / 8))); CHECK_MAT_ROW(ARM64_REG_ZAS0, 1, uint32_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 32; i++) { + for (uint16_t i = 2; i < SVL / 32; i++) { CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, fillNeon({0}, (SVL / 8))); } @@ -808,7 +886,7 @@ TEST_P(InstSme, mova_s_vecToTile) { fillNeon({1}, (SVL / 8))); CHECK_MAT_ROW(ARM64_REG_ZAS0, 1, uint32_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 32; i++) { + for (uint16_t i = 2; i < SVL / 32; i++) { CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, fillNeon({0}, (SVL / 8))); } @@ -834,7 +912,7 @@ TEST_P(InstSme, mova_s_vecToTile) { fillNeon({1}, (SVL / 8))); CHECK_MAT_COL(ARM64_REG_ZAS0, 1, uint32_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 32; i++) { + for (uint16_t i = 2; i < SVL / 32; i++) { CHECK_MAT_COL(ARM64_REG_ZAS0, i, uint32_t, fillNeon({0}, (SVL / 8))); } @@ -860,7 +938,7 @@ TEST_P(InstSme, mova_s_vecToTile) { fillNeon({1}, (SVL / 8))); CHECK_MAT_COL(ARM64_REG_ZAS0, 1, uint32_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 32; i++) { + for (uint16_t i = 2; i < SVL / 32; i++) { CHECK_MAT_COL(ARM64_REG_ZAS0, i, uint32_t, fillNeon({0}, (SVL / 8))); } @@ -889,7 +967,7 @@ TEST_P(InstSme, mova_d_vecToTile) { fillNeon({1}, (SVL / 8))); CHECK_MAT_ROW(ARM64_REG_ZAD0, 1, uint64_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 64; i++) { + for (uint16_t i = 2; i < SVL / 64; i++) { CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, fillNeon({0}, (SVL / 8))); } @@ -915,7 +993,7 @@ TEST_P(InstSme, mova_d_vecToTile) { fillNeon({1}, (SVL / 8))); CHECK_MAT_ROW(ARM64_REG_ZAD0, 1, uint64_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 64; i++) { + for (uint16_t i = 2; i < SVL / 64; i++) { CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, fillNeon({0}, (SVL / 8))); } @@ -941,7 +1019,7 @@ TEST_P(InstSme, mova_d_vecToTile) { fillNeon({1}, (SVL / 8))); CHECK_MAT_COL(ARM64_REG_ZAD0, 1, uint64_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 64; i++) { + for (uint16_t i = 2; i < SVL / 64; i++) { CHECK_MAT_COL(ARM64_REG_ZAD0, i, uint64_t, fillNeon({0}, (SVL / 8))); } @@ -967,12 +1045,127 @@ TEST_P(InstSme, mova_d_vecToTile) { fillNeon({1}, (SVL / 8))); CHECK_MAT_COL(ARM64_REG_ZAD0, 1, uint64_t, fillNeon({2, 0}, (SVL / 8))); - for (int i = 2; i < SVL / 64; i++) { + for (uint16_t i = 2; i < SVL / 64; i++) { CHECK_MAT_COL(ARM64_REG_ZAD0, i, uint64_t, fillNeon({0}, (SVL / 8))); } } +TEST_P(InstSme, mova_q_vecToTile) { + // 128-bit + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.d + pfalse p1.b + # Zip1 twice to get on-off-on-off pattern with quadwords + zip1 p1.d, p0.d, p1.d + zip1 p1.d, p1.d, p1.d + + mov w12, #0 + dup z0.d, #1 + dup z1.d, #2 + + # Horizontal + mova za0h.q[w12, #0], p0/m, z0.q + mova za0h.q[w12, #0], p1/m, z1.q + )"); + CHECK_MAT_ROW(ARM64_REG_ZAQ0, 0, uint64_t, + fillNeon({2, 2, 1, 1}, (SVL / 8))); + for (uint16_t i = 1; i < SVL / 128; i++) { + CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, + fillNeon({0}, (SVL / 8))); + } + + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.d + pfalse p1.b + # Zip1 twice to get on-off-on-off pattern with quadwords + zip1 p1.d, p0.d, p1.d + zip1 p1.d, p1.d, p1.d + + mov w12, #0 + dup z0.d, #1 + dup z1.d, #2 + + # Horizontal Alias + mov za0h.q[w12, #0], p0/m, z0.q + mov za0h.q[w12, #0], p1/m, z1.q + )"); + CHECK_MAT_ROW(ARM64_REG_ZAQ0, 0, uint64_t, + fillNeon({2, 2, 1, 1}, (SVL / 8))); + for (uint16_t i = 1; i < SVL / 128; i++) { + CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, + fillNeon({0}, (SVL / 8))); + } + + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.d + pfalse p1.b + # Zip1 twice to get on-off-on-off pattern with quadwords + zip1 p1.d, p0.d, p1.d + zip1 p1.d, p1.d, p1.d + + mov w12, #0 + dup z0.d, #1 + dup z1.d, #2 + + # Vertical + mova za0v.q[w12, #0], p0/m, z0.q + mova za0v.q[w12, #0], p1/m, z1.q + )"); + auto onRow = fillNeon({0}, (SVL / 8)); + auto offRow = fillNeon({0}, (SVL / 8)); + onRow[0] = 2; + onRow[1] = 2; + offRow[0] = 1; + offRow[1] = 1; + for (uint16_t i = 0; i < SVL / 128; i++) { + if (i % 2 == 0) { + CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, onRow); + } else { + CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, offRow); + } + } + + RUN_AARCH64(R"( + smstart + + zero {za} + + ptrue p0.d + pfalse p1.b + # Zip1 twice to get on-off-on-off pattern with quadwords + zip1 p1.d, p0.d, p1.d + zip1 p1.d, p1.d, p1.d + + mov w12, #0 + dup z0.d, #1 + dup z1.d, #2 + + # Vertical Alias + mov za0v.q[w12, #0], p0/m, z0.q + mov za0v.q[w12, #0], p1/m, z1.q + )"); + for (uint16_t i = 0; i < SVL / 128; i++) { + if (i % 2 == 0) { + CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, onRow); + } else { + CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, offRow); + } + } +} + TEST_P(InstSme, fmopa) { // 32-bit RUN_AARCH64(R"( @@ -1503,7 +1696,7 @@ TEST_P(InstSme, ldr) { 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, SVL / 8)); - for (int i = 3; i < SVL / 8; i++) { + for (uint16_t i = 3; i < SVL / 8; i++) { CHECK_MAT_ROW(ARM64_REG_ZAB0, i, uint8_t, fillNeon({0}, SVL / 8)); } } From 882ce0a446f206712a331c490daf5919abb83555 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Wed, 28 Aug 2024 12:51:12 +0100 Subject: [PATCH 39/48] Implemented SME ST1Q and LD1Q (V and H) instructions and regression tests. --- src/lib/arch/aarch64/Instruction_address.cc | 34 +++ src/lib/arch/aarch64/Instruction_execute.cc | 157 +++++++++++ test/regression/aarch64/instructions/sme.cc | 272 ++++++++++++++++++++ 3 files changed, 463 insertions(+) diff --git a/src/lib/arch/aarch64/Instruction_address.cc b/src/lib/arch/aarch64/Instruction_address.cc index 8eaae50a9c..956939859f 100644 --- a/src/lib/arch/aarch64/Instruction_address.cc +++ b/src/lib/arch/aarch64/Instruction_address.cc @@ -130,6 +130,19 @@ span Instruction::generateAddresses() { setMemoryAddresses({(n + m), static_cast(VL_bits / 8)}); break; } + case Opcode::AArch64_LD1_MXIPXX_V_Q: // ld1q {zatv.q[ws]}, pg/z, + // [{, xm, lsl #4}] + case Opcode::AArch64_LD1_MXIPXX_H_Q: { // ld1q {zath.q[ws]}, pg/z, + // [{, xm, lsl #4}] + // SME + const uint16_t partition_num = VL_bits / 128; + const uint64_t n = sourceValues_[partition_num + 2].get(); + uint64_t m = 0; + if (metadata_.operands[2].mem.index) + m = sourceValues_[partition_num + 3].get() << 4; + setMemoryAddresses({(n + m), static_cast(VL_bits / 8)}); + break; + } case Opcode::AArch64_LD1_MXIPXX_V_S: // ld1w {zatv.s[ws, #imm]}, pg/z, // [{, xm, LSL #2}] case Opcode::AArch64_LD1_MXIPXX_H_S: { // ld1w {zath.s[ws, #imm]}, pg/z, @@ -1058,6 +1071,27 @@ span Instruction::generateAddresses() { setMemoryAddresses(std::move(addresses)); break; } + case Opcode::AArch64_ST1_MXIPXX_H_Q: // st1q {zath.q[ws]}, pg, [{, + // xm, lsl #4}] + case Opcode::AArch64_ST1_MXIPXX_V_Q: { // st1q {zatv.q[ws]}, pg, + // [{, xm, lsl #4}] + // SME + const uint16_t partition_num = VL_bits / 128; + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + const uint64_t n = sourceValues_[partition_num + 2].get(); + uint64_t m = 0; + if (metadata_.operands[2].mem.index) + m = sourceValues_[partition_num + 3].get() << 4; + + std::vector addresses; + addresses.reserve(partition_num); + + generatePredicatedContiguousAddressBlocks((n + m), partition_num, 16, + 16, pg, addresses); + setMemoryAddresses(std::move(addresses)); + break; + } case Opcode::AArch64_ST1_MXIPXX_H_S: // st1w {zath.s[ws, #imm]}, pg/z, // [{, xm, LSL #2}] case Opcode::AArch64_ST1_MXIPXX_V_S: { // st1w {zatv.s[ws, #imm]}, pg/z, diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index b70f744639..eb2312f5a6 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -3421,6 +3421,44 @@ void Instruction::execute() { results_[sliceNum] = {out, 256}; break; } + case Opcode::AArch64_LD1_MXIPXX_H_Q: { // ld1q {zath.q[ws]}, pg/z, + // [{, xm, LSL #4}] + // SME, LOAD + // If not in right context mode, raise exception + if (!ZAenabled) return ZAdisabled(); + + const uint16_t partition_num = VL_bits / 128; + const uint32_t ws = sourceValues_[partition_num].get(); + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + + const uint32_t sliceNum = ws % partition_num; + // Use uint64_t as no 128-bit type + const uint64_t* data = memoryData_[0].getAsVector(); + + // Use uint64_t as no 128-bit type + uint64_t out[32] = {0}; + for (int i = 0; i < partition_num; i++) { + // For 128-bit there are 16-bit for each active element + uint64_t shifted_active = 1ull << ((i % 4) * 16); + if (pg[i / 4] & shifted_active) { + // As using uint64_t need to modify 2 elements + out[2 * i] = data[2 * i]; + out[2 * i + 1] = data[2 * i + 1]; + } else { + out[2 * i] = 0; + out[2 * i + 1] = 0; + } + } + + // All Slice vectors are added to results[] so need to update the + // correct one + for (uint16_t i = 0; i < partition_num; i++) { + results_[i] = sourceValues_[i]; + } + results_[sliceNum] = {out, 256}; + break; + } case Opcode::AArch64_LD1_MXIPXX_H_S: { // ld1w {zath.s[ws, #imm]}, pg/z, // [{, xm, LSL #2}] // SME, LOAD @@ -3538,6 +3576,40 @@ void Instruction::execute() { } break; } + case Opcode::AArch64_LD1_MXIPXX_V_Q: { // ld1q {zatv.q[ws]}, pg/z, + // [{, xm, lsl #4}] + // SME, LOAD + // If not in right context mode, raise exception + if (!ZAenabled) return ZAdisabled(); + + const uint16_t partition_num = VL_bits / 128; + const uint32_t ws = sourceValues_[partition_num].get(); + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + + const uint32_t sliceNum = ws % partition_num; + // Using uint64_t as no 128-bit data type + const uint64_t* data = memoryData_[0].getAsVector(); + + for (int i = 0; i < partition_num; i++) { + // Using uint64_t as no 128-bit data type + uint64_t* row = + const_cast(sourceValues_[i].getAsVector()); + // For 128-bit there are 16-bit for each active element + uint64_t shifted_active = 1ull << ((i % 4) * 16); + if (pg[i / 4] & shifted_active) { + // As using uint64_t need to modify 2 elements + row[2 * sliceNum] = data[2 * i]; + row[2 * sliceNum + 1] = data[2 * i + 1]; + } else { + // As using uint64_t need to modify 2 elements + row[2 * sliceNum] = 0; + row[2 * sliceNum + 1] = 0; + } + results_[i] = RegisterValue(reinterpret_cast(row), 256); + } + break; + } case Opcode::AArch64_LD1_MXIPXX_V_S: { // ld1w {zatv.s[ws, #imm]}, pg/z, // [{, xm, LSL #2}] // SME, LOAD @@ -5557,6 +5629,49 @@ void Instruction::execute() { memoryData_ = sve_merge_store_data(tileSlice, pg, VL_bits); break; } + case Opcode::AArch64_ST1_MXIPXX_H_Q: { // st1q {zath.q[ws]}, pg, + // [{, xm, lsl #4}] + // SME, STORE + // If not in right context mode, raise exception + if (!ZAenabled) return ZAdisabled(); + + const uint16_t partition_num = VL_bits / 128; + const uint32_t ws = sourceValues_[partition_num].get(); + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + + const uint32_t sliceNum = ws % partition_num; + + // Using uint64_t as no 128-bit type + const uint64_t* tileSlice = + sourceValues_[sliceNum].getAsVector(); + + // Need to combine active adjacent elements into RegisterValues and + // place into each memoryData_ index. + int index = 0; + std::vector memData; + for (uint16_t i = 0; i < partition_num; i++) { + // For 128-bit there are 16-bit for each active element + uint64_t shifted_active = 1ull << ((i % 4) * 16); + if (pg[i / 4] & shifted_active) { + // As using uint64_t need to push_back 2 elements + memData.push_back(tileSlice[2 * i]); + memData.push_back(tileSlice[2 * i + 1]); + } else if (memData.size() > 0) { + // Predicate false, save current data + memoryData_[index] = RegisterValue( + (char*)memData.data(), memData.size() * sizeof(uint64_t)); + index++; + memData.clear(); + } + } + // Check if final data needs putting into memoryData_ + if (memData.size() > 0) { + memoryData_[index] = RegisterValue((char*)memData.data(), + memData.size() * sizeof(uint64_t)); + } + break; + } case Opcode::AArch64_ST1_MXIPXX_H_S: { // st1w {zath.s[ws, #imm]}, pg, // [{, xm, lsl #2}] // SME, STORE @@ -5684,6 +5799,48 @@ void Instruction::execute() { } break; } + case Opcode::AArch64_ST1_MXIPXX_V_Q: { // st1h {zatv.q[ws]}, pg, + // [{, xm, LSL #4}] + // SME, STORE + // Not in right context mode. Raise exception + if (!ZAenabled) return ZAdisabled(); + + const uint16_t partition_num = VL_bits / 128; + const uint32_t ws = sourceValues_[partition_num].get(); + const uint64_t* pg = + sourceValues_[partition_num + 1].getAsVector(); + + const uint32_t sliceNum = ws % partition_num; + + // Need to combine active adjacent elements into RegisterValues and + // place into each memoryData_ index. + std::vector memData; + uint16_t index = 0; + for (uint16_t x = 0; x < partition_num; x++) { + // For 128-bit there are 16-bit for each active element + uint64_t shifted_active = 1ull << ((x % 4) * 16); + if (pg[x / 4] & shifted_active) { + // As using uint64_t need to push_back 2 elements + memData.push_back( + sourceValues_[x].getAsVector()[2 * sliceNum]); + memData.push_back( + sourceValues_[x].getAsVector()[2 * sliceNum + 1]); + } else if (memData.size() > 0) { + // Predicate false, save current data + memoryData_[index] = RegisterValue( + (char*)memData.data(), memData.size() * sizeof(uint64_t)); + index++; + memData.clear(); + } + } + + // Check if final data needs putting into memoryData_ + if (memData.size() > 0) { + memoryData_[index] = RegisterValue((char*)memData.data(), + memData.size() * sizeof(uint64_t)); + } + break; + } case Opcode::AArch64_ST1_MXIPXX_V_S: { // st1w {zatv.s[ws, #imm]}, pg, // [{, xm, LSL #2}] // SME, STORE diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index 23a54a9080..caca903a21 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -1573,6 +1573,92 @@ TEST_P(InstSme, ld1h) { {0}, SVL / 8)); } +TEST_P(InstSme, ld1q) { + // Horizontal + initialHeapData_.resize(SVL / 4); + uint64_t* heap64 = reinterpret_cast(initialHeapData_.data()); + std::vector src = {0xDEADBEEF12345678, 0x98765432ABCDEF01, + 0x98765432ABCDEF01, 0xDEADBEEF12345678}; + fillHeap(heap64, src, SVL / 32); + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + mov x1, #1 + ptrue p0.b + mov w12, #1 + # Load and broadcast values from heap + ld1q {za0h.q[w12, 0]}, p0/z, [x0, x1, lsl #4] + + # Test for inactive lanes - zip twice to get on-off for 128-bits + pfalse p1.b + zip1 p0.d, p0.d, p1.d + zip1 p0.d, p0.d, p0.d + ld1q {za15h.q[w12, 0]}, p0/z, [x0] + )"); + CHECK_MAT_ROW(ARM64_REG_ZAQ0, 1 % (SVL / 128), uint64_t, + fillNeon({0x98765432ABCDEF01, 0xDEADBEEF12345678, + 0xDEADBEEF12345678, 0x98765432ABCDEF01}, + SVL / 8)); + CHECK_MAT_ROW(ARM64_REG_ZAQ15, 1 % (SVL / 128), uint64_t, + fillNeon( + {0xDEADBEEF12345678, 0x98765432ABCDEF01, 0, 0}, SVL / 8)); + + // Vertical + initialHeapData_.resize(SVL / 4); + heap64 = reinterpret_cast(initialHeapData_.data()); + fillHeap(heap64, src, SVL / 32); + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + mov x1, #1 + ptrue p0.b + mov w12, #1 + # Load and broadcast values from heap + ld1q {za0v.q[w12, 0]}, p0/z, [x0, x1, lsl #4] + + # Test for inactive lanes - zip twice to get on-off for 128-bits + pfalse p1.b + zip1 p0.d, p0.d, p1.d + zip1 p0.d, p0.d, p0.d + ld1q {za15v.q[w12, 0]}, p0/z, [x0] + )"); + // Can't check Q columns as CHECK_MAT_COL isn't set up for doing this with + // uint64_t. + // Instead, manually place values into 1st column of Q tile (as per + // asm above) and check each Q row. + auto row0 = fillNeon({0}, (SVL / 8)); + auto row1 = fillNeon({0}, (SVL / 8)); + auto zeroRow = fillNeon({0}, (SVL / 8)); + // MOD SVL / 64 as dealing with uint64_t even though its a 128-bit tile + row0[2 % (SVL / 64)] = 0x98765432ABCDEF01; + row0[3 % (SVL / 64)] = 0xDEADBEEF12345678; + row1[2 % (SVL / 64)] = 0xDEADBEEF12345678; + row1[3 % (SVL / 64)] = 0x98765432ABCDEF01; + for (uint16_t i = 0; i < SVL / 128; i++) { + if (i % 2 == 0) { + CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, row0); + CHECK_MAT_ROW(ARM64_REG_ZAQ15, i, uint64_t, row1); + } else { + CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, row1); + CHECK_MAT_ROW(ARM64_REG_ZAQ15, i, uint64_t, zeroRow); + } + } +} + TEST_P(InstSme, ld1w) { // Horizontal initialHeapData_.resize(SVL / 4); @@ -2286,6 +2372,192 @@ TEST_P(InstSme, st1h) { } } +TEST_P(InstSme, st1q) { + // Horizontal + initialHeapData_.resize(SVL); + uint64_t* heap64 = reinterpret_cast(initialHeapData_.data()); + std::vector src = {0xDEADBEEF12345678, 0x98765432ABCDEF01}; + fillHeap(heap64, src, SVL / 8); + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + sub sp, sp, #4095 + mov x1, #0 + mov x4, #0 + addvl x4, x4, #1 + ptrue p0.b + + mov w12, #0 + mov w13, #1 + ld1q {za0h.q[w12, 0]}, p0/z, [x0, x1, lsl #4] + ld1q {za1h.q[w13, 0]}, p0/z, [x0, x1, lsl #4] + st1q {za0h.q[w12, 0]}, p0, [sp, x1, lsl #4] + st1q {za1h.q[w13, 0]}, p0, [x4] + )"); + for (uint64_t i = 0; i < (SVL / 128); i++) { + EXPECT_EQ(getMemoryValue(process_->getInitialStackPointer() - + 4095 + ((2 * i) * 8)), + src[(2 * i) % 2]); + EXPECT_EQ(getMemoryValue(process_->getInitialStackPointer() - + 4095 + ((2 * i + 1) * 8)), + src[(2 * i + 1) % 2]); + + EXPECT_EQ(getMemoryValue((SVL / 8) + ((2 * i) * 8)), + src[(2 * i) % 2]); + EXPECT_EQ(getMemoryValue((SVL / 8) + ((2 * i + 1) * 8)), + src[(2 * i + 1) % 2]); + } + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + mov x3, #2 + ptrue p0.d + pfalse p1.b + # Do zip1 twice to get on-off for 128-bit + zip1 p1.d, p0.d, p1.d + zip1 p1.d, p1.d, p1.d + mov x5, #400 + mov x6, #800 + + mov w12, #0 + mov w13, #2 + # Load entire row + ld1q {za3h.q[w12, 0]}, p0/z, [x0, x3, lsl #4] + # Store all 0s to memory + st1q {za0h.q[w12, 0]}, p0, [x5] + # Store odd indexed elements to memory + st1q {za3h.q[w12, 0]}, p1, [x5] + + # Load entire row + ld1q {za1h.q[w13, 0]}, p0/z, [x0, x3, lsl #4] + # Store all 0s to memory + st1q {za0h.q[w12, 0]}, p0, [x6, x3, lsl #4] + # Store odd indexed elements to memory + st1q {za1h.q[w13, 0]}, p1, [x6, x3, lsl #4] + )"); + for (uint64_t i = 0; i < (SVL / 128); i += 2) { + EXPECT_EQ(getMemoryValue(400 + ((2 * i) * 8)), src[(2 * i) % 2]); + EXPECT_EQ(getMemoryValue(400 + ((2 * i + 1) * 8)), + src[(2 * i + 1) % 2]); + EXPECT_EQ(getMemoryValue(400 + (((2 * i) + 2) * 8)), 0); + EXPECT_EQ(getMemoryValue(400 + (((2 * i + 1) + 2) * 8)), 0); + + EXPECT_EQ(getMemoryValue(800 + 32 + ((2 * i) * 8)), + src[(2 * i) % 2]); + EXPECT_EQ(getMemoryValue(800 + 32 + ((2 * i + 1) * 8)), + src[(2 * i + 1) % 2]); + EXPECT_EQ(getMemoryValue(800 + 32 + (((2 * i) + 2) * 8)), 0); + EXPECT_EQ(getMemoryValue(800 + 32 + (((2 * i + 1) + 2) * 8)), 0); + } + + // Vertical + initialHeapData_.resize(SVL); + uint64_t* heap64_vert = reinterpret_cast(initialHeapData_.data()); + std::vector src_vert = {0xDEADBEEF12345678, 0x98765432ABCDEF01}; + fillHeap(heap64_vert, src_vert, SVL / 8); + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + sub sp, sp, #4095 + mov x1, #0 + mov x4, #0 + addvl x4, x4, #1 + ptrue p0.b + + mov w12, #0 + mov w13, #1 + ld1q {za0v.q[w12, 0]}, p0/z, [x0, x1, lsl #4] + ld1q {za1v.q[w13, 0]}, p0/z, [x0, x1, lsl #4] + st1q {za0v.q[w12, 0]}, p0, [sp, x1, lsl #4] + st1q {za1v.q[w13, 0]}, p0, [x4] + )"); + for (uint64_t i = 0; i < (SVL / 128); i++) { + EXPECT_EQ(getMemoryValue(process_->getInitialStackPointer() - + 4095 + ((2 * i) * 8)), + src_vert[(2 * i) % 2]); + EXPECT_EQ(getMemoryValue(process_->getInitialStackPointer() - + 4095 + ((2 * i + 1) * 8)), + src_vert[(2 * i + 1) % 2]); + + EXPECT_EQ(getMemoryValue((SVL / 8) + ((2 * i) * 8)), + src_vert[(2 * i) % 2]); + EXPECT_EQ(getMemoryValue((SVL / 8) + ((2 * i + 1) * 8)), + src_vert[(2 * i + 1) % 2]); + } + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + smstart + + zero {za} + + mov x3, #2 + ptrue p0.d + pfalse p1.b + # Do zip1 twice to get on-off for 128-bit + zip1 p1.d, p0.d, p1.d + zip1 p1.d, p1.d, p1.d + mov x5, #400 + mov x6, #800 + + mov w12, #0 + mov w13, #2 + # Load entire row + ld1q {za3v.q[w12, 0]}, p0/z, [x0, x3, lsl #4] + # Store all 0s to memory + st1q {za0v.q[w12, 0]}, p0, [x5] + # Store odd indexed elements to memory + st1q {za3v.q[w12, 0]}, p1, [x5] + + # Load entire row + ld1q {za1v.q[w13, 0]}, p0/z, [x0, x3, lsl #4] + # Store all 0s to memory + st1q {za0v.q[w12, 0]}, p0, [x6, x3, lsl #4] + # Store odd indexed elements to memory + st1q {za1v.q[w13, 0]}, p1, [x6, x3, lsl #4] + )"); + for (uint64_t i = 0; i < (SVL / 128); i += 2) { + EXPECT_EQ(getMemoryValue(400 + ((2 * i) * 8)), src[(2 * i) % 2]); + EXPECT_EQ(getMemoryValue(400 + ((2 * i + 1) * 8)), + src[(2 * i + 1) % 2]); + EXPECT_EQ(getMemoryValue(400 + (((2 * i) + 2) * 8)), 0); + EXPECT_EQ(getMemoryValue(400 + (((2 * i + 1) + 2) * 8)), 0); + + EXPECT_EQ(getMemoryValue(800 + 32 + ((2 * i) * 8)), + src[(2 * i) % 2]); + EXPECT_EQ(getMemoryValue(800 + 32 + ((2 * i + 1) * 8)), + src[(2 * i + 1) % 2]); + EXPECT_EQ(getMemoryValue(800 + 32 + (((2 * i) + 2) * 8)), 0); + EXPECT_EQ(getMemoryValue(800 + 32 + (((2 * i + 1) + 2) * 8)), 0); + } +} + TEST_P(InstSme, st1w) { // Horizontal initialHeapData_.resize(SVL / 4); From d33d1c19b34d5b412173d89b440214669d621460 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Mon, 2 Sep 2024 18:36:29 +0200 Subject: [PATCH 40/48] Removed werror. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b8f4379b98..97d712519c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,7 +66,7 @@ set(CMAKE_MACOSX_RPATH 1) set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Create variable to enable additional compiler warnings for SimEng targets only -set(SIMENG_COMPILE_OPTIONS -Wall -pedantic -Werror) #-Wextra +set(SIMENG_COMPILE_OPTIONS -Wall -pedantic) #-Wextra # Disable RTTI for all targets add_compile_options($<$:-fno-rtti>) From b5c4cda6f4094dd9bc7743110fab271ed156fb06 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Mon, 14 Oct 2024 10:47:36 +0100 Subject: [PATCH 41/48] NEON instruction logic fixes. --- .../simeng/arch/aarch64/helpers/neon.hh | 14 ++++++++++++-- src/lib/arch/aarch64/Instruction_execute.cc | 4 ++-- test/regression/aarch64/instructions/neon.cc | 18 +++++++++--------- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/include/simeng/arch/aarch64/helpers/neon.hh b/src/include/simeng/arch/aarch64/helpers/neon.hh index c2626b7e91..17137dcb55 100644 --- a/src/include/simeng/arch/aarch64/helpers/neon.hh +++ b/src/include/simeng/arch/aarch64/helpers/neon.hh @@ -568,9 +568,14 @@ RegisterValue vecUMaxP(srcValContainer& sourceValues) { const T* n = sourceValues[0].getAsVector(); const T* m = sourceValues[1].getAsVector(); + // Concatenate the vectors + T temp[2 * I]; + memcpy(temp, m, sizeof(T) * I); + memcpy(temp + (sizeof(T) * I), n, sizeof(T) * I); + // Compare each adjacent pair of elements T out[I]; for (int i = 0; i < I; i++) { - out[i] = std::max(n[i], m[i]); + out[i] = std::max(temp[2 * i], temp[2 * i + 1]); } return {out, 256}; } @@ -585,9 +590,14 @@ RegisterValue vecUMinP(srcValContainer& sourceValues) { const T* n = sourceValues[0].getAsVector(); const T* m = sourceValues[1].getAsVector(); + // Concatenate the vectors + T temp[2 * I]; + memcpy(temp, m, sizeof(T) * I); + memcpy(temp + (sizeof(T) * I), n, sizeof(T) * I); + T out[I]; for (int i = 0; i < I; i++) { - out[i] = std::min(n[i], m[i]); + out[i] = std::min(temp[2 * i], temp[2 * i + 1]); } return {out, 256}; } diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index eb2312f5a6..189cff3091 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -838,9 +838,9 @@ void Instruction::execute() { break; } case Opcode::AArch64_CMHSv16i8: { // cmhs vd.16b, vn.16b, vm.16b - results_[0] = vecCompare( + results_[0] = vecCompare( sourceValues_, false, - [](int8_t x, int8_t y) -> bool { return (x >= y); }); + [](uint8_t x, uint8_t y) -> bool { return (x >= y); }); break; } case Opcode::AArch64_CMPEQ_PPzZI_B: { // cmpeq pd.b, pg/z, zn.b, #imm diff --git a/test/regression/aarch64/instructions/neon.cc b/test/regression/aarch64/instructions/neon.cc index a4731f388f..2a28a4e22b 100644 --- a/test/regression/aarch64/instructions/neon.cc +++ b/test/regression/aarch64/instructions/neon.cc @@ -727,8 +727,8 @@ TEST_P(InstNeon, cmhs) { heap[1] = 0x7F; heap[2] = INT8_MAX; heap[3] = 1; - heap[4] = -128; - heap[5] = -1; + heap[4] = 128; + heap[5] = 1; heap[6] = 0xAA; heap[7] = 0xBB; heap[8] = 0xCC; @@ -744,7 +744,7 @@ TEST_P(InstNeon, cmhs) { heap[16] = INT8_MAX; heap[17] = 0x7F; heap[18] = 0; - heap[19] = -128; + heap[19] = 128; heap[20] = 1; heap[21] = 0; heap[22] = 0xAA; @@ -772,10 +772,10 @@ TEST_P(InstNeon, cmhs) { )"); CHECK_NEON(2, uint8_t, - {0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + {0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}); CHECK_NEON(3, uint8_t, - {0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, + {0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}); } @@ -2684,8 +2684,8 @@ TEST_P(InstNeon, uminp) { )"); CHECK_NEON(2, uint8_t, - {0x00, 0x00, 0xEE, 0x11, 0x22, 0x33, 0x44, 0x55, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, 0x08}); + {0x00, 0x11, 0x22, 0x44, 0xEE, 0xCC, 0xAA, 0x88, 0x00, 0xAA, 0xBB, + 0xDD, 0x01, 0x03, 0x05, 0x07}); } TEST_P(InstNeon, umaxp) { // umaxp vd.16b vn.16b vm.16b @@ -2742,8 +2742,8 @@ TEST_P(InstNeon, umaxp) { )"); CHECK_NEON(2, uint8_t, - {0x01, 0x00, 0xFF, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xEE, 0xDD, - 0xCC, 0xBB, 0xAA, 0x99, 0x88}); + {0x00, 0xEE, 0x33, 0x55, 0xFF, 0xDD, 0xBB, 0x99, 0x01, 0xFF, 0xCC, + 0xEE, 0x02, 0x04, 0x06, 0x08}); } TEST_P(InstNeon, smax) { From 7b74b3478d4eb4dde7c457a7406d3f6a1d28ef64 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Tue, 29 Oct 2024 14:46:03 +0000 Subject: [PATCH 42/48] Attended PR comments. --- CMakeLists.txt | 2 +- configs/a64fx_SME.yaml | 35 +-- .../assets/instruction_groups_AArch64.png | Bin 152824 -> 145502 bytes src/include/simeng/Register.hh | 1 - .../simeng/arch/aarch64/Architecture.hh | 2 +- .../simeng/arch/aarch64/Instruction.hh | 2 +- .../simeng/arch/aarch64/InstructionGroups.hh | 28 +- src/lib/arch/aarch64/Architecture.cc | 4 +- src/lib/arch/aarch64/Instruction.cc | 2 +- src/lib/arch/aarch64/Instruction_address.cc | 248 ++++++++++++------ src/lib/arch/aarch64/Instruction_decode.cc | 2 +- src/lib/arch/aarch64/Instruction_execute.cc | 130 ++++----- src/lib/arch/aarch64/MicroDecoder.cc | 2 +- test/unit/aarch64/ArchitectureTest.cc | 10 +- test/unit/aarch64/InstructionTest.cc | 38 +-- 15 files changed, 297 insertions(+), 209 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 97d712519c..b8f4379b98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,7 +66,7 @@ set(CMAKE_MACOSX_RPATH 1) set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Create variable to enable additional compiler warnings for SimEng targets only -set(SIMENG_COMPILE_OPTIONS -Wall -pedantic) #-Wextra +set(SIMENG_COMPILE_OPTIONS -Wall -pedantic -Werror) #-Wextra # Disable RTTI for all targets add_compile_options($<$:-fno-rtti>) diff --git a/configs/a64fx_SME.yaml b/configs/a64fx_SME.yaml index 4408e195c0..3cf55a525b 100644 --- a/configs/a64fx_SME.yaml +++ b/configs/a64fx_SME.yaml @@ -65,12 +65,7 @@ Ports: Instruction-Group-Support: - INT_SIMPLE - INT_MUL - - STORE_DATA_INT - - STORE_DATA_SCALAR - - STORE_DATA_VECTOR - - STORE_DATA_SVE - - STORE_DATA_STREAMING_SVE - - STORE_DATA_SME + - STORE_DATA 3: Portname: FLB Instruction-Group-Support: @@ -86,36 +81,16 @@ Ports: 5: Portname: EAGA Instruction-Group-Support: - - LOAD_INT - - LOAD_SCALAR - - LOAD_VECTOR - - LOAD_SVE - - LOAD_STREAMING_SVE - - LOAD_SME - - STORE_ADDRESS_INT - - STORE_ADDRESS_SCALAR - - STORE_ADDRESS_VECTOR - - STORE_ADDRESS_SVE - - STORE_ADDRESS_STREAMING_SVE - - STORE_ADDRESS_SME + - LOAD + - STORE_ADDRESS - INT_SIMPLE_ARTH_NOSHIFT - INT_SIMPLE_LOGICAL_NOSHIFT - INT_SIMPLE_CMP 6: Portname: EAGB Instruction-Group-Support: - - LOAD_INT - - LOAD_SCALAR - - LOAD_VECTOR - - LOAD_SVE - - LOAD_STREAMING_SVE - - LOAD_SME - - STORE_ADDRESS_INT - - STORE_ADDRESS_SCALAR - - STORE_ADDRESS_VECTOR - - STORE_ADDRESS_SVE - - STORE_ADDRESS_STREAMING_SVE - - STORE_ADDRESS_SME + - LOAD + - STORE_ADDRESS - INT_SIMPLE_ARTH_NOSHIFT - INT_SIMPLE_LOGICAL_NOSHIFT - INT_SIMPLE_CMP diff --git a/docs/sphinx/assets/instruction_groups_AArch64.png b/docs/sphinx/assets/instruction_groups_AArch64.png index ba3319435f5c081edd98edf8811e0784519cf80d..f877fd7795c68fe8113f1816c44eab082176997e 100644 GIT binary patch literal 145502 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 z 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 N{;YB}N6zH#{{d>~hZz6> literal 152824 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 Qg#R?vHgC*Pu{rpE026zjtN;K2 diff --git a/src/include/simeng/Register.hh b/src/include/simeng/Register.hh index 5758d8e67b..0152813268 100644 --- a/src/include/simeng/Register.hh +++ b/src/include/simeng/Register.hh @@ -1,6 +1,5 @@ #pragma once #include -#include namespace simeng { diff --git a/src/include/simeng/arch/aarch64/Architecture.hh b/src/include/simeng/arch/aarch64/Architecture.hh index 1041bf85fe..a654fc897a 100644 --- a/src/include/simeng/arch/aarch64/Architecture.hh +++ b/src/include/simeng/arch/aarch64/Architecture.hh @@ -74,7 +74,7 @@ class Architecture : public arch::Architecture { bool isStreamingModeEnabled() const; /** Returns if the SME ZA Register is enabled. */ - bool isZA_RegisterEnabled() const; + bool isZARegisterEnabled() const; /** Update the value of SVCRval_. */ void setSVCRval(const uint64_t newVal) const; diff --git a/src/include/simeng/arch/aarch64/Instruction.hh b/src/include/simeng/arch/aarch64/Instruction.hh index 9cb6eea9ee..73a15efb9e 100644 --- a/src/include/simeng/arch/aarch64/Instruction.hh +++ b/src/include/simeng/arch/aarch64/Instruction.hh @@ -395,7 +395,7 @@ class Instruction : public simeng::Instruction { * this instruction was first decoded, and updates the instruction group * accordingly if required. * Returns TRUE if the group was updated, FALSE otherwise. */ - bool checkStreamingGroup(); + bool checkStreamingGroupAndUpdate(); private: /** Process the instruction's metadata to determine source/destination diff --git a/src/include/simeng/arch/aarch64/InstructionGroups.hh b/src/include/simeng/arch/aarch64/InstructionGroups.hh index 3c28712537..6c58ff4976 100644 --- a/src/include/simeng/arch/aarch64/InstructionGroups.hh +++ b/src/include/simeng/arch/aarch64/InstructionGroups.hh @@ -4,7 +4,33 @@ namespace simeng { namespace arch { namespace aarch64 { -/** The IDs of the instruction groups for AArch64 instructions. */ +/** The IDs of the instruction groups for AArch64 instructions. + * Each new group must contain 14 entries to ensure correct group assignment and + * general functionality. + * Their order must be as follows: + * - BASE + * - BASE_SIMPLE + * - BASE_SIMPLE_ARTH + * - BASE_SIMPLE_ARTH_NOSHIFT + * - BASE_SIMPLE_LOGICAL + * - BASE_SIMPLE_LOGICAL_NOSHIFT + * - BASE_SIMPLE_CMP + * - BASE_SIMPLE_CVT + * - BASE_MUL + * - BASE_DIV_OR_SQRT + * - LOAD_BASE + * - STORE_ADDRESS_BASE + * - STORE_DATA_BASE + * - STORE_BASE + * + * An exception to the above is "Parent" groups which do not require the LOAD_* + * or STORE_* groups. + * "Parent" groups allow for easier grouping of similar groups that may have + * identical execution latencies, ports, etc. For example, FP is the parent + * group of SCALAR and VECTOR. + * In simulation, an instruction's allocated group will never be a "Parent" + * group; they are only used to simplify config file creation and management. + */ namespace InstructionGroups { const uint16_t INT = 0; const uint16_t INT_SIMPLE = 1; diff --git a/src/lib/arch/aarch64/Architecture.cc b/src/lib/arch/aarch64/Architecture.cc index ff0282e9c3..cf847b1f65 100644 --- a/src/lib/arch/aarch64/Architecture.cc +++ b/src/lib/arch/aarch64/Architecture.cc @@ -196,7 +196,7 @@ uint8_t Architecture::predecode(const uint8_t* ptr, uint16_t bytesAvailable, // Check if SVE or Predicate instructions need their group updating due to // SVE Streaming Mode activeness being different from when the instruction // was first decoded. - if (cachedInsn.checkStreamingGroup()) { + if (cachedInsn.checkStreamingGroupAndUpdate()) { // If the instruction's group has changed then update its execution info. // The newly set group is most likely to be the most accurate, as an // incorrect group allocation is only achieved when an exception/flush is @@ -302,7 +302,7 @@ void Architecture::setSVCRval(const uint64_t newVal) const { bool Architecture::isStreamingModeEnabled() const { return SVCRval_ & 1; } // 1st bit of SVCR register determines if ZA register is enabled. -bool Architecture::isZA_RegisterEnabled() const { return SVCRval_ & 2; } +bool Architecture::isZARegisterEnabled() const { return SVCRval_ & 2; } } // namespace aarch64 } // namespace arch diff --git a/src/lib/arch/aarch64/Instruction.cc b/src/lib/arch/aarch64/Instruction.cc index 967a72b7ba..2811c72625 100644 --- a/src/lib/arch/aarch64/Instruction.cc +++ b/src/lib/arch/aarch64/Instruction.cc @@ -164,7 +164,7 @@ const Architecture& Instruction::getArchitecture() const { InstructionException Instruction::getException() const { return exception_; } -bool Instruction::checkStreamingGroup() { +bool Instruction::checkStreamingGroupAndUpdate() { // Only instruction groups that depend on SVE Streaming Mode are SVE and // PREDICATE const uint16_t currentGroup = instructionGroup_; diff --git a/src/lib/arch/aarch64/Instruction_address.cc b/src/lib/arch/aarch64/Instruction_address.cc index 956939859f..ec4f269a8f 100644 --- a/src/lib/arch/aarch64/Instruction_address.cc +++ b/src/lib/arch/aarch64/Instruction_address.cc @@ -91,8 +91,10 @@ span Instruction::generateAddresses() { setMemoryAddresses({{sourceValues_[2].get(), 8}}); break; } - case Opcode::AArch64_LD1_MXIPXX_V_B: // ld1b {zatv.b[ws, #imm]}, pg/z, - // [{, xm}] + case Opcode::AArch64_LD1_MXIPXX_V_B: // ld1b {zatv.b[ws, #imm]}, pg/z, + // [{, xm}] + // SME + [[fallthrough]]; case Opcode::AArch64_LD1_MXIPXX_H_B: { // ld1b {zath.b[ws, #imm]}, pg/z, // [{, xm}] // SME @@ -104,8 +106,10 @@ span Instruction::generateAddresses() { setMemoryAddresses({(n + m), static_cast(VL_bits / 8)}); break; } - case Opcode::AArch64_LD1_MXIPXX_V_D: // ld1d {zatv.d[ws, #imm]}, pg/z, - // [{, xm, lsl #3}] + case Opcode::AArch64_LD1_MXIPXX_V_D: // ld1d {zatv.d[ws, #imm]}, pg/z, + // [{, xm, lsl #3}] + // SME + [[fallthrough]]; case Opcode::AArch64_LD1_MXIPXX_H_D: { // ld1d {zath.d[ws, #imm]}, pg/z, // [{, xm, lsl #3}] // SME @@ -117,8 +121,10 @@ span Instruction::generateAddresses() { setMemoryAddresses({(n + m), static_cast(VL_bits / 8)}); break; } - case Opcode::AArch64_LD1_MXIPXX_V_H: // ld1h {zatv.h[ws, #imm]}, pg/z, - // [{, xm, lsl #1}] + case Opcode::AArch64_LD1_MXIPXX_V_H: // ld1h {zatv.h[ws, #imm]}, pg/z, + // [{, xm, lsl #1}] + // SME + [[fallthrough]]; case Opcode::AArch64_LD1_MXIPXX_H_H: { // ld1h {zath.h[ws, #imm]}, pg/z, // [{, xm, lsl #1}] // SME @@ -130,8 +136,10 @@ span Instruction::generateAddresses() { setMemoryAddresses({(n + m), static_cast(VL_bits / 8)}); break; } - case Opcode::AArch64_LD1_MXIPXX_V_Q: // ld1q {zatv.q[ws]}, pg/z, - // [{, xm, lsl #4}] + case Opcode::AArch64_LD1_MXIPXX_V_Q: // ld1q {zatv.q[ws]}, pg/z, + // [{, xm, lsl #4}] + // SME + [[fallthrough]]; case Opcode::AArch64_LD1_MXIPXX_H_Q: { // ld1q {zath.q[ws]}, pg/z, // [{, xm, lsl #4}] // SME @@ -143,8 +151,10 @@ span Instruction::generateAddresses() { setMemoryAddresses({(n + m), static_cast(VL_bits / 8)}); break; } - case Opcode::AArch64_LD1_MXIPXX_V_S: // ld1w {zatv.s[ws, #imm]}, pg/z, - // [{, xm, LSL #2}] + case Opcode::AArch64_LD1_MXIPXX_V_S: // ld1w {zatv.s[ws, #imm]}, pg/z, + // [{, xm, LSL #2}] + // SME + [[fallthrough]]; case Opcode::AArch64_LD1_MXIPXX_H_S: { // ld1w {zath.s[ws, #imm]}, pg/z, // [{, xm, LSL #2}] // SME @@ -551,19 +561,32 @@ span Instruction::generateAddresses() { setMemoryAddresses({{sourceValues_[0].get() + offset, 8}}); break; } - case Opcode::AArch64_LDRBui: // ldr bt, [xn, #imm] - case Opcode::AArch64_LDRBpre: // ldr bt, [xn, #imm]! - case Opcode::AArch64_LDRDui: // ldr dt, [xn, #imm] - case Opcode::AArch64_LDRDpre: // ldr dt, [xn, #imm]! - case Opcode::AArch64_LDRHui: // ldr ht, [xn, #imm] - case Opcode::AArch64_LDRHpre: // ldr ht, [xn, #imm]! - case Opcode::AArch64_LDRQui: // ldr qt, [xn, #imm] - case Opcode::AArch64_LDRQpre: // ldr qt, [xn, #imm]! - case Opcode::AArch64_LDRSui: // ldr st, [xn, #imm] - case Opcode::AArch64_LDRSpre: // ldr st, [xn, #imm]! - case Opcode::AArch64_LDRWui: // ldr wt, [xn, #imm] - case Opcode::AArch64_LDRWpre: // ldr wt, [xn, #imm]! - case Opcode::AArch64_LDRXui: // ldr xt, [xn, #imm] + case Opcode::AArch64_LDRBui: // ldr bt, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_LDRBpre: // ldr bt, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_LDRDui: // ldr dt, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_LDRDpre: // ldr dt, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_LDRHui: // ldr ht, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_LDRHpre: // ldr ht, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_LDRQui: // ldr qt, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_LDRQpre: // ldr qt, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_LDRSui: // ldr st, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_LDRSpre: // ldr st, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_LDRWui: // ldr wt, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_LDRWpre: // ldr wt, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_LDRXui: // ldr xt, [xn, #imm] + [[fallthrough]]; case Opcode::AArch64_LDRXpre: { // ldr xt, [xn, #imm]! std::vector addresses; generateContiguousAddresses( @@ -572,12 +595,18 @@ span Instruction::generateAddresses() { setMemoryAddresses(addresses); break; } - case Opcode::AArch64_LDRBpost: // ldr bt, [xn], #imm - case Opcode::AArch64_LDRDpost: // ldr dt, [xn], #imm - case Opcode::AArch64_LDRHpost: // ldr ht, [xn], #imm - case Opcode::AArch64_LDRQpost: // ldr qt, [xn], #imm - case Opcode::AArch64_LDRSpost: // ldr st, [xn], #imm - case Opcode::AArch64_LDRWpost: // ldr wt, [xn], #imm + case Opcode::AArch64_LDRBpost: // ldr bt, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_LDRDpost: // ldr dt, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_LDRHpost: // ldr ht, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_LDRQpost: // ldr qt, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_LDRSpost: // ldr st, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_LDRWpost: // ldr wt, [xn], #imm + [[fallthrough]]; case Opcode::AArch64_LDRXpost: { // ldr xt, [xn], #imm std::vector addresses; generateContiguousAddresses(sourceValues_[0].get(), 1, @@ -695,15 +724,24 @@ span Instruction::generateAddresses() { setMemoryAddresses({{base, 4}, {base + 4, 4}}); break; } - case Opcode::AArch64_LDPDi: // ldp dt1, dt2, [xn, #imm] - case Opcode::AArch64_LDPDpre: // ldp dt1, dt2, [xn, #imm!] - case Opcode::AArch64_LDPQi: // ldp qt1, qt2, [xn, #imm] - case Opcode::AArch64_LDPQpre: // ldp qt1, qt2, [xn, #imm!] - case Opcode::AArch64_LDPSi: // ldp st1, st2, [xn, #imm] - case Opcode::AArch64_LDPSpre: // ldp st1, st2, [xn, #imm!] - case Opcode::AArch64_LDPWi: // ldp wt1, wt2, [xn, #imm] - case Opcode::AArch64_LDPWpre: // ldp wt1, wt2, [xn, #imm!] - case Opcode::AArch64_LDPXi: // ldp xt1, xt2, [xn, #imm] + case Opcode::AArch64_LDPDi: // ldp dt1, dt2, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_LDPDpre: // ldp dt1, dt2, [xn, #imm!] + [[fallthrough]]; + case Opcode::AArch64_LDPQi: // ldp qt1, qt2, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_LDPQpre: // ldp qt1, qt2, [xn, #imm!] + [[fallthrough]]; + case Opcode::AArch64_LDPSi: // ldp st1, st2, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_LDPSpre: // ldp st1, st2, [xn, #imm!] + [[fallthrough]]; + case Opcode::AArch64_LDPWi: // ldp wt1, wt2, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_LDPWpre: // ldp wt1, wt2, [xn, #imm!] + [[fallthrough]]; + case Opcode::AArch64_LDPXi: // ldp xt1, xt2, [xn, #imm] + [[fallthrough]]; case Opcode::AArch64_LDPXpre: { // ldp xt1, xt2, [xn, #imm!] std::vector addresses; generateContiguousAddresses( @@ -712,10 +750,14 @@ span Instruction::generateAddresses() { setMemoryAddresses(addresses); break; } - case Opcode::AArch64_LDPDpost: // ldp dt1, dt2, [xn], #imm - case Opcode::AArch64_LDPQpost: // ldp qt1, qt2, [xn], #imm - case Opcode::AArch64_LDPSpost: // ldp st1, st2, [xn], #imm - case Opcode::AArch64_LDPWpost: // ldp wt1, wt2, [xn], #imm + case Opcode::AArch64_LDPDpost: // ldp dt1, dt2, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_LDPQpost: // ldp qt1, qt2, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_LDPSpost: // ldp st1, st2, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_LDPWpost: // ldp wt1, wt2, [xn], #imm + [[fallthrough]]; case Opcode::AArch64_LDPXpost: { // ldp xt1, xt2, [xn], #imm std::vector addresses; generateContiguousAddresses(sourceValues_[0].get(), 2, @@ -1008,8 +1050,10 @@ span Instruction::generateAddresses() { setMemoryAddresses(std::move(addresses)); break; } - case Opcode::AArch64_ST1_MXIPXX_H_B: // st1b {zath.b[ws, #imm]}, pg, - // [{, xm}] + case Opcode::AArch64_ST1_MXIPXX_H_B: // st1b {zath.b[ws, #imm]}, pg, + // [{, xm}] + // SME + [[fallthrough]]; case Opcode::AArch64_ST1_MXIPXX_V_B: { // st1b {zatv.b[ws, #imm]}, pg, // [{, xm}] // SME @@ -1029,8 +1073,10 @@ span Instruction::generateAddresses() { setMemoryAddresses(std::move(addresses)); break; } - case Opcode::AArch64_ST1_MXIPXX_H_D: // st1d {zath.d[ws, #imm]}, pg, - // [{, xm, lsl #3}] + case Opcode::AArch64_ST1_MXIPXX_H_D: // st1d {zath.d[ws, #imm]}, pg, + // [{, xm, lsl #3}] + // SME + [[fallthrough]]; case Opcode::AArch64_ST1_MXIPXX_V_D: { // st1d {zatv.d[ws, #imm]}, pg, // [{, xm, lsl #3}] // SME @@ -1050,8 +1096,10 @@ span Instruction::generateAddresses() { setMemoryAddresses(std::move(addresses)); break; } - case Opcode::AArch64_ST1_MXIPXX_H_H: // st1h {zath.h[ws, #imm]}, pg, - // [{, xm, lsl #1}] + case Opcode::AArch64_ST1_MXIPXX_H_H: // st1h {zath.h[ws, #imm]}, pg, + // [{, xm, lsl #1}] + // SME + [[fallthrough]]; case Opcode::AArch64_ST1_MXIPXX_V_H: { // st1h {zatv.h[ws, #imm]}, pg, // [{, xm, lsl #1}] // SME @@ -1073,6 +1121,8 @@ span Instruction::generateAddresses() { } case Opcode::AArch64_ST1_MXIPXX_H_Q: // st1q {zath.q[ws]}, pg, [{, // xm, lsl #4}] + // SME + [[fallthrough]]; case Opcode::AArch64_ST1_MXIPXX_V_Q: { // st1q {zatv.q[ws]}, pg, // [{, xm, lsl #4}] // SME @@ -1092,8 +1142,10 @@ span Instruction::generateAddresses() { setMemoryAddresses(std::move(addresses)); break; } - case Opcode::AArch64_ST1_MXIPXX_H_S: // st1w {zath.s[ws, #imm]}, pg/z, - // [{, xm, LSL #2}] + case Opcode::AArch64_ST1_MXIPXX_H_S: // st1w {zath.s[ws, #imm]}, pg/z, + // [{, xm, LSL #2}] + // SME + [[fallthrough]]; case Opcode::AArch64_ST1_MXIPXX_V_S: { // st1w {zatv.s[ws, #imm]}, pg/z, // [{, xm, LSL #2}] // SME @@ -1471,15 +1523,24 @@ span Instruction::generateAddresses() { setMemoryAddresses({{sourceValues_[1].get(), 8}}); break; } - case Opcode::AArch64_STPDi: // stp dt1, dt2, [xn, #imm] - case Opcode::AArch64_STPDpre: // stp dt1, dt2, [xn, #imm]! - case Opcode::AArch64_STPQi: // stp qt1, qt2, [xn, #imm] - case Opcode::AArch64_STPQpre: // stp qt1, qt2, [xn, #imm]! - case Opcode::AArch64_STPSi: // stp st1, st2, [xn, #imm] - case Opcode::AArch64_STPSpre: // stp st1, st2, [xn, #imm]! - case Opcode::AArch64_STPWi: // stp wt1, wt2, [xn, #imm] - case Opcode::AArch64_STPWpre: // stp wt1, wt2, [xn, #imm]! - case Opcode::AArch64_STPXi: // stp xt1, xt2, [xn, #imm] + case Opcode::AArch64_STPDi: // stp dt1, dt2, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_STPDpre: // stp dt1, dt2, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_STPQi: // stp qt1, qt2, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_STPQpre: // stp qt1, qt2, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_STPSi: // stp st1, st2, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_STPSpre: // stp st1, st2, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_STPWi: // stp wt1, wt2, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_STPWpre: // stp wt1, wt2, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_STPXi: // stp xt1, xt2, [xn, #imm] + [[fallthrough]]; case Opcode::AArch64_STPXpre: { // stp xt1, xt2, [xn, #imm]! std::vector addresses; generateContiguousAddresses( @@ -1488,10 +1549,14 @@ span Instruction::generateAddresses() { setMemoryAddresses(addresses); break; } - case Opcode::AArch64_STPDpost: // stp dt1, dt2, [xn], #imm - case Opcode::AArch64_STPQpost: // stp qt1, qt2, [xn], #imm - case Opcode::AArch64_STPSpost: // stp st1, st2, [xn], #imm - case Opcode::AArch64_STPWpost: // stp wt1, wt2, [xn], #imm + case Opcode::AArch64_STPDpost: // stp dt1, dt2, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_STPQpost: // stp qt1, qt2, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_STPSpost: // stp st1, st2, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_STPWpost: // stp wt1, wt2, [xn], #imm + [[fallthrough]]; case Opcode::AArch64_STPXpost: { // stp xt1, xt2, [xn], #imm std::vector addresses; generateContiguousAddresses(sourceValues_[2].get(), 2, @@ -1541,19 +1606,32 @@ span Instruction::generateAddresses() { setMemoryAddresses({{sourceValues_[1].get() + offset, 8}}); break; } - case Opcode::AArch64_STRBui: // str bt, [xn, #imm] - case Opcode::AArch64_STRBpre: // str bt, [xn, #imm]! - case Opcode::AArch64_STRDui: // str dt, [xn, #imm] - case Opcode::AArch64_STRDpre: // str dt, [xn, #imm]! - case Opcode::AArch64_STRHui: // str ht, [xn, #imm] - case Opcode::AArch64_STRHpre: // str ht, [xn, #imm]! - case Opcode::AArch64_STRQui: // str qt, [xn, #imm] - case Opcode::AArch64_STRQpre: // str qt, [xn, #imm]! - case Opcode::AArch64_STRSui: // str st, [xn, #imm] - case Opcode::AArch64_STRSpre: // str st, [xn, #imm]! - case Opcode::AArch64_STRWui: // str wt, [xn, #imm] - case Opcode::AArch64_STRWpre: // str wt, [xn, #imm]! - case Opcode::AArch64_STRXui: // str xt, [xn, #imm] + case Opcode::AArch64_STRBui: // str bt, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_STRBpre: // str bt, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_STRDui: // str dt, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_STRDpre: // str dt, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_STRHui: // str ht, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_STRHpre: // str ht, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_STRQui: // str qt, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_STRQpre: // str qt, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_STRSui: // str st, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_STRSpre: // str st, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_STRWui: // str wt, [xn, #imm] + [[fallthrough]]; + case Opcode::AArch64_STRWpre: // str wt, [xn, #imm]! + [[fallthrough]]; + case Opcode::AArch64_STRXui: // str xt, [xn, #imm] + [[fallthrough]]; case Opcode::AArch64_STRXpre: { // str xt, [xn, #imm]! std::vector addresses; generateContiguousAddresses( @@ -1562,12 +1640,18 @@ span Instruction::generateAddresses() { setMemoryAddresses(addresses); break; } - case Opcode::AArch64_STRBpost: // str bt, [xn], #imm - case Opcode::AArch64_STRDpost: // str dt, [xn], #imm - case Opcode::AArch64_STRHpost: // str ht, [xn], #imm - case Opcode::AArch64_STRQpost: // str qt, [xn], #imm - case Opcode::AArch64_STRSpost: // str st, [xn], #imm - case Opcode::AArch64_STRWpost: // str wt, [xn], #imm + case Opcode::AArch64_STRBpost: // str bt, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_STRDpost: // str dt, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_STRHpost: // str ht, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_STRQpost: // str qt, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_STRSpost: // str st, [xn], #imm + [[fallthrough]]; + case Opcode::AArch64_STRWpost: // str wt, [xn], #imm + [[fallthrough]]; case Opcode::AArch64_STRXpost: { // str xt, [xn], #imm std::vector addresses; generateContiguousAddresses(sourceValues_[1].get(), 1, diff --git a/src/lib/arch/aarch64/Instruction_decode.cc b/src/lib/arch/aarch64/Instruction_decode.cc index 2bd3a6e6d0..ad5b4d83c3 100644 --- a/src/lib/arch/aarch64/Instruction_decode.cc +++ b/src/lib/arch/aarch64/Instruction_decode.cc @@ -688,7 +688,7 @@ void Instruction::decode() { } else if (isInstruction(InsnType::isShift)) group += 2; else - group += 3; // Default is {Data type}_SIMPLE_ARTH + group += 3; // Default is {Data type}_SIMPLE_ARTH_NOSHIFT instructionGroup_ = group; } diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 189cff3091..b99cd2fce5 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -69,7 +69,7 @@ void Instruction::execute() { // 0th bit of SVCR register determines if streaming-mode is enabled. const bool SMenabled = architecture_.isStreamingModeEnabled(); // 1st bit of SVCR register determines if ZA register is enabled. - const bool ZAenabled = architecture_.isZA_RegisterEnabled(); + const bool ZAenabled = architecture_.isZARegisterEnabled(); // When streaming mode is enabled, the architectural vector length goes from // SVE's VL to SME's SVL. const uint16_t VL_bits = SMenabled ? architecture_.getStreamingVectorLength() @@ -125,8 +125,9 @@ void Instruction::execute() { const uint64_t* zaRow = sourceValues_[row].getAsVector(); uint64_t out[32] = {0}; std::memcpy(out, zaRow, rowCount * sizeof(uint64_t)); - // Slice element is active IFF: - // - Element in 1st source pred corresponding to horiz. slice is TRUE + // Slice element is active IFF all of the following conditions hold: + // - Element in 1st source pred corresponding to horizontal + // slice is TRUE // - Corresponding element in 2nd source pred is TRUE const uint64_t shifted_active_pn = 1ull << ((row % 8) * 8); if (pn[row / 8] & shifted_active_pn) { @@ -158,8 +159,9 @@ void Instruction::execute() { const uint32_t* zaRow = sourceValues_[row].getAsVector(); uint32_t out[64] = {0}; std::memcpy(out, zaRow, rowCount * sizeof(uint32_t)); - // Slice element is active IFF: - // - Element in 1st source pred corresponding to horiz. slice is TRUE + // Slice element is active IFF all of the following conditions hold: + // - Element in 1st source pred corresponding to horizontal + // slice is TRUE // - Corresponding element in 2nd source pred is TRUE const uint64_t shifted_active_pn = 1ull << ((row % 16) * 4); if (pn[row / 16] & shifted_active_pn) { @@ -191,9 +193,10 @@ void Instruction::execute() { const uint64_t* zaRow = sourceValues_[row].getAsVector(); uint64_t out[32] = {0}; std::memcpy(out, zaRow, rowCount * sizeof(uint64_t)); - // Slice element is active IFF: + // Slice element is active IFF all of the following conditions hold: // - Corresponding element in 1st source pred is TRUE - // - Element in 2nd source pred corresponding to vert. slice is TRUE + // - Element in 2nd source pred corresponding to vertical + // slice is TRUE const uint64_t shifted_active_pn = 1ull << ((row % 8) * 8); if (pn[row / 8] & shifted_active_pn) { // Corresponding slice element is active (i.e. all elements in row). @@ -227,9 +230,10 @@ void Instruction::execute() { const uint32_t* zaRow = sourceValues_[row].getAsVector(); uint32_t out[64] = {0}; std::memcpy(out, zaRow, rowCount * sizeof(uint32_t)); - // Slice element is active IFF: + // Slice element is active IFF all of the following conditions hold: // - Corresponding element in 1st source pred is TRUE - // - Element in 2nd source pred corresponding to vert. slice is TRUE + // - Element in 2nd source pred corresponding to vertical + // slice is TRUE const uint64_t shifted_active_pn = 1ull << ((row % 16) * 4); if (pn[row / 16] & shifted_active_pn) { // Corresponding slice element is active (i.e. all elements in row). @@ -3178,11 +3182,12 @@ void Instruction::execute() { const uint8_t* zn = sourceValues_[rowCount + 2].getAsVector(); for (uint16_t i = 0; i < rowCount; i++) { - uint8_t* row = - const_cast(sourceValues_[i].getAsVector()); + const uint8_t* row = sourceValues_[i].getAsVector(); + uint8_t out[256] = {0}; + memcpy(out, row, rowCount * sizeof(uint8_t)); uint64_t shifted_active = 1ull << (i % 64); - if (pg[i / 64] & shifted_active) row[sliceNum] = zn[i]; - results_[i] = {(char*)row, 256}; + if (pg[i / 64] & shifted_active) out[sliceNum] = zn[i]; + results_[i] = {out, 256}; } break; } @@ -3204,11 +3209,12 @@ void Instruction::execute() { sourceValues_[rowCount + 2].getAsVector(); for (uint16_t i = 0; i < rowCount; i++) { - uint64_t* row = - const_cast(sourceValues_[i].getAsVector()); + const uint64_t* row = sourceValues_[i].getAsVector(); + uint64_t out[32] = {0}; + memcpy(out, row, rowCount * sizeof(uint64_t)); uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (pg[i / 8] & shifted_active) row[sliceNum] = zn[i]; - results_[i] = {(char*)row, 256}; + if (pg[i / 8] & shifted_active) out[sliceNum] = zn[i]; + results_[i] = {out, 256}; } break; } @@ -3230,11 +3236,12 @@ void Instruction::execute() { sourceValues_[rowCount + 2].getAsVector(); for (uint16_t i = 0; i < rowCount; i++) { - uint16_t* row = - const_cast(sourceValues_[i].getAsVector()); + const uint16_t* row = sourceValues_[i].getAsVector(); + uint16_t out[128] = {0}; + memcpy(out, row, rowCount * sizeof(uint16_t)); uint64_t shifted_active = 1ull << ((i % 32) * 2); - if (pg[i / 32] & shifted_active) row[sliceNum] = zn[i]; - results_[i] = {(char*)row, 256}; + if (pg[i / 32] & shifted_active) out[sliceNum] = zn[i]; + results_[i] = {out, 256}; } break; } @@ -3255,16 +3262,18 @@ void Instruction::execute() { for (uint16_t i = 0; i < rowCount; i++) { // Use uint64_t in place of 128-bit - uint64_t* row = - const_cast(sourceValues_[i].getAsVector()); + const uint64_t* row = sourceValues_[i].getAsVector(); + uint64_t out[32] = {0}; + // *2 in memcpy as need 128-bit elements but using uint64_t + memcpy(out, row, rowCount * sizeof(uint64_t) * 2); // For 128-bit there are 16-bit for each active element uint64_t shifted_active = 1ull << ((i % 4) * 16); if (pg[i / 4] & shifted_active) { // Need to move two consecutive 64-bit elements - row[2 * sliceNum] = zn[2 * i]; - row[2 * sliceNum + 1] = zn[2 * i + 1]; + out[2 * sliceNum] = zn[2 * i]; + out[2 * sliceNum + 1] = zn[2 * i + 1]; } - results_[i] = {(char*)row, 256}; + results_[i] = {out, 256}; } break; } @@ -3286,11 +3295,12 @@ void Instruction::execute() { sourceValues_[rowCount + 2].getAsVector(); for (uint16_t i = 0; i < rowCount; i++) { - uint32_t* row = - const_cast(sourceValues_[i].getAsVector()); + const uint32_t* row = sourceValues_[i].getAsVector(); + uint32_t out[64] = {0}; + memcpy(out, row, rowCount * sizeof(uint32_t)); uint64_t shifted_active = 1ull << ((i % 16) * 4); - if (pg[i / 16] & shifted_active) row[sliceNum] = zn[i]; - results_[i] = {(char*)row, 256}; + if (pg[i / 16] & shifted_active) out[sliceNum] = zn[i]; + results_[i] = {out, 256}; } break; } @@ -3508,15 +3518,14 @@ void Instruction::execute() { const uint8_t* data = memoryData_[0].getAsVector(); for (int i = 0; i < partition_num; i++) { - uint8_t* row = - const_cast(sourceValues_[i].getAsVector()); + const uint8_t* row = sourceValues_[i].getAsVector(); + uint8_t out[256] = {0}; + memcpy(out, row, partition_num * sizeof(uint8_t)); uint64_t shifted_active = 1ull << (i % 64); if (pg[i / 64] & shifted_active) { - row[sliceNum] = data[i]; - } else { - row[sliceNum] = 0; + out[sliceNum] = data[i]; } - results_[i] = RegisterValue(reinterpret_cast(row), 256); + results_[i] = RegisterValue(out, 256); } break; } @@ -3536,15 +3545,14 @@ void Instruction::execute() { const uint64_t* data = memoryData_[0].getAsVector(); for (int i = 0; i < partition_num; i++) { - uint64_t* row = - const_cast(sourceValues_[i].getAsVector()); + const uint64_t* row = sourceValues_[i].getAsVector(); + uint64_t out[32] = {0}; + memcpy(out, row, partition_num * sizeof(uint64_t)); uint64_t shifted_active = 1ull << ((i % 8) * 8); if (pg[i / 8] & shifted_active) { - row[sliceNum] = data[i]; - } else { - row[sliceNum] = 0; + out[sliceNum] = data[i]; } - results_[i] = RegisterValue(reinterpret_cast(row), 256); + results_[i] = RegisterValue(out, 256); } break; } @@ -3564,15 +3572,14 @@ void Instruction::execute() { const uint16_t* data = memoryData_[0].getAsVector(); for (int i = 0; i < partition_num; i++) { - uint16_t* row = - const_cast(sourceValues_[i].getAsVector()); + const uint16_t* row = sourceValues_[i].getAsVector(); + uint16_t out[128] = {0}; + memcpy(out, row, partition_num * sizeof(uint16_t)); uint64_t shifted_active = 1ull << ((i % 32) * 2); if (pg[i / 32] & shifted_active) { - row[sliceNum] = data[i]; - } else { - row[sliceNum] = 0; + out[sliceNum] = data[i]; } - results_[i] = RegisterValue(reinterpret_cast(row), 256); + results_[i] = RegisterValue(out, 256); } break; } @@ -3593,20 +3600,18 @@ void Instruction::execute() { for (int i = 0; i < partition_num; i++) { // Using uint64_t as no 128-bit data type - uint64_t* row = - const_cast(sourceValues_[i].getAsVector()); + const uint64_t* row = sourceValues_[i].getAsVector(); + uint64_t out[32] = {0}; + // *2 in memcpy as need 128-bit but using uint64_t + memcpy(out, row, partition_num * sizeof(uint64_t) * 2); // For 128-bit there are 16-bit for each active element uint64_t shifted_active = 1ull << ((i % 4) * 16); if (pg[i / 4] & shifted_active) { // As using uint64_t need to modify 2 elements - row[2 * sliceNum] = data[2 * i]; - row[2 * sliceNum + 1] = data[2 * i + 1]; - } else { - // As using uint64_t need to modify 2 elements - row[2 * sliceNum] = 0; - row[2 * sliceNum + 1] = 0; + out[2 * sliceNum] = data[2 * i]; + out[2 * sliceNum + 1] = data[2 * i + 1]; } - results_[i] = RegisterValue(reinterpret_cast(row), 256); + results_[i] = RegisterValue(out, 256); } break; } @@ -3626,15 +3631,14 @@ void Instruction::execute() { const uint32_t* data = memoryData_[0].getAsVector(); for (int i = 0; i < partition_num; i++) { - uint32_t* row = - const_cast(sourceValues_[i].getAsVector()); + const uint32_t* row = sourceValues_[i].getAsVector(); + uint32_t out[64] = {0}; + memcpy(out, row, partition_num * sizeof(uint64_t)); uint64_t shifted_active = 1ull << ((i % 16) * 4); if (pg[i / 16] & shifted_active) { - row[sliceNum] = data[i]; - } else { - row[sliceNum] = 0; + out[sliceNum] = data[i]; } - results_[i] = RegisterValue(reinterpret_cast(row), 256); + results_[i] = RegisterValue(out, 256); } break; } diff --git a/src/lib/arch/aarch64/MicroDecoder.cc b/src/lib/arch/aarch64/MicroDecoder.cc index 7e98866d7c..6f93566784 100644 --- a/src/lib/arch/aarch64/MicroDecoder.cc +++ b/src/lib/arch/aarch64/MicroDecoder.cc @@ -625,7 +625,7 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // Check if SVE or Predicate instructions need their group updating due // to SVE Streaming Mode activeness being different from when the // instruction was first decoded. - if (cachedUops[uop].checkStreamingGroup()) { + if (cachedUops[uop].checkStreamingGroupAndUpdate()) { // If the instruction's group has changed then update its execution // info. The newly set group is most likely to be the most accurate, // as an incorrect group allocation is only achieved when an diff --git a/test/unit/aarch64/ArchitectureTest.cc b/test/unit/aarch64/ArchitectureTest.cc index a9d4c32c1f..779f3806ac 100644 --- a/test/unit/aarch64/ArchitectureTest.cc +++ b/test/unit/aarch64/ArchitectureTest.cc @@ -286,19 +286,19 @@ TEST_F(AArch64ArchitectureTest, get_set_SVCRVal) { TEST_F(AArch64ArchitectureTest, isSM_ZA_enabled) { EXPECT_FALSE(arch->isStreamingModeEnabled()); - EXPECT_FALSE(arch->isZA_RegisterEnabled()); + EXPECT_FALSE(arch->isZARegisterEnabled()); arch->setSVCRval(1); EXPECT_TRUE(arch->isStreamingModeEnabled()); - EXPECT_FALSE(arch->isZA_RegisterEnabled()); + EXPECT_FALSE(arch->isZARegisterEnabled()); arch->setSVCRval(2); EXPECT_FALSE(arch->isStreamingModeEnabled()); - EXPECT_TRUE(arch->isZA_RegisterEnabled()); + EXPECT_TRUE(arch->isZARegisterEnabled()); arch->setSVCRval(3); EXPECT_TRUE(arch->isStreamingModeEnabled()); - EXPECT_TRUE(arch->isZA_RegisterEnabled()); + EXPECT_TRUE(arch->isZARegisterEnabled()); arch->setSVCRval(0); EXPECT_FALSE(arch->isStreamingModeEnabled()); - EXPECT_FALSE(arch->isZA_RegisterEnabled()); + EXPECT_FALSE(arch->isZARegisterEnabled()); } } // namespace aarch64 diff --git a/test/unit/aarch64/InstructionTest.cc b/test/unit/aarch64/InstructionTest.cc index 83dae83cd8..33b4c108cd 100644 --- a/test/unit/aarch64/InstructionTest.cc +++ b/test/unit/aarch64/InstructionTest.cc @@ -642,7 +642,7 @@ TEST_F(AArch64InstructionTest, setters) { EXPECT_TRUE(insn.isWaitingCommit()); } -TEST_F(AArch64InstructionTest, checkStreamingGroup) { +TEST_F(AArch64InstructionTest, checkStreamingGroupAndUpdate) { EXPECT_FALSE(arch.isStreamingModeEnabled()); // Insn is `fdivr z1.s, p0/m, z1.s, z0.s` Instruction SVE_insn = Instruction(arch, *fdivMetadata.get(), MicroOpInfo()); @@ -655,42 +655,42 @@ TEST_F(AArch64InstructionTest, checkStreamingGroup) { Instruction PRED_insn = Instruction(arch, *pselMetadata.get(), MicroOpInfo()); EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::PREDICATE); - // Without changing SVE Streaming Mode, calling checkStreamingGroup should - // have no effect + // Without changing SVE Streaming Mode, calling checkStreamingGroupAndUpdate + // should have no effect EXPECT_FALSE(arch.isStreamingModeEnabled()); EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::PREDICATE); - EXPECT_FALSE(SVE_insn.checkStreamingGroup()); - EXPECT_FALSE(nonSVE_insn.checkStreamingGroup()); - EXPECT_FALSE(PRED_insn.checkStreamingGroup()); + EXPECT_FALSE(SVE_insn.checkStreamingGroupAndUpdate()); + EXPECT_FALSE(nonSVE_insn.checkStreamingGroupAndUpdate()); + EXPECT_FALSE(PRED_insn.checkStreamingGroupAndUpdate()); EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::PREDICATE); - // Updating SVE Streaming Mode should mean calling checkStreamingGroup changes - // SVE and PRED groups + // Updating SVE Streaming Mode should mean calling + // checkStreamingGroupAndUpdate changes SVE and PRED groups arch.setSVCRval(3); EXPECT_TRUE(arch.isStreamingModeEnabled()); EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::PREDICATE); - EXPECT_TRUE(SVE_insn.checkStreamingGroup()); - EXPECT_FALSE(nonSVE_insn.checkStreamingGroup()); - EXPECT_TRUE(PRED_insn.checkStreamingGroup()); + EXPECT_TRUE(SVE_insn.checkStreamingGroupAndUpdate()); + EXPECT_FALSE(nonSVE_insn.checkStreamingGroupAndUpdate()); + EXPECT_TRUE(PRED_insn.checkStreamingGroupAndUpdate()); EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::STREAMING_PREDICATE); - // Calling checkStreamingGroup again should have no effect on SVE and PRED - // groups, and should return false as a result + // Calling checkStreamingGroupAndUpdate again should have no effect on SVE and + // PRED groups, and should return false as a result EXPECT_TRUE(arch.isStreamingModeEnabled()); EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::STREAMING_PREDICATE); - EXPECT_FALSE(SVE_insn.checkStreamingGroup()); - EXPECT_FALSE(nonSVE_insn.checkStreamingGroup()); - EXPECT_FALSE(PRED_insn.checkStreamingGroup()); + EXPECT_FALSE(SVE_insn.checkStreamingGroupAndUpdate()); + EXPECT_FALSE(nonSVE_insn.checkStreamingGroupAndUpdate()); + EXPECT_FALSE(PRED_insn.checkStreamingGroupAndUpdate()); EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::STREAMING_PREDICATE); @@ -702,9 +702,9 @@ TEST_F(AArch64InstructionTest, checkStreamingGroup) { EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::STREAMING_PREDICATE); - EXPECT_TRUE(SVE_insn.checkStreamingGroup()); - EXPECT_FALSE(nonSVE_insn.checkStreamingGroup()); - EXPECT_TRUE(PRED_insn.checkStreamingGroup()); + EXPECT_TRUE(SVE_insn.checkStreamingGroupAndUpdate()); + EXPECT_FALSE(nonSVE_insn.checkStreamingGroupAndUpdate()); + EXPECT_TRUE(PRED_insn.checkStreamingGroupAndUpdate()); EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::PREDICATE); From 790f3df728ebd1ddd185252602634cb90d35bcb5 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Mon, 4 Nov 2024 17:43:27 +0000 Subject: [PATCH 43/48] Switched order of concatonation for NEON UMAXP instruction to match Hardware. --- src/include/simeng/arch/aarch64/helpers/neon.hh | 4 ++-- test/regression/aarch64/instructions/neon.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/include/simeng/arch/aarch64/helpers/neon.hh b/src/include/simeng/arch/aarch64/helpers/neon.hh index 17137dcb55..4ada414951 100644 --- a/src/include/simeng/arch/aarch64/helpers/neon.hh +++ b/src/include/simeng/arch/aarch64/helpers/neon.hh @@ -570,8 +570,8 @@ RegisterValue vecUMaxP(srcValContainer& sourceValues) { // Concatenate the vectors T temp[2 * I]; - memcpy(temp, m, sizeof(T) * I); - memcpy(temp + (sizeof(T) * I), n, sizeof(T) * I); + memcpy(temp, n, sizeof(T) * I); + memcpy(temp + (sizeof(T) * I), m, sizeof(T) * I); // Compare each adjacent pair of elements T out[I]; for (int i = 0; i < I; i++) { diff --git a/test/regression/aarch64/instructions/neon.cc b/test/regression/aarch64/instructions/neon.cc index 2a28a4e22b..572ad842d5 100644 --- a/test/regression/aarch64/instructions/neon.cc +++ b/test/regression/aarch64/instructions/neon.cc @@ -2738,7 +2738,7 @@ TEST_P(InstNeon, umaxp) { ldr q0, [x0] ldr q1, [x0, #16] - umaxp v2.16b, v0.16b, v1.16b + umaxp v2.16b, v1.16b, v0.16b )"); CHECK_NEON(2, uint8_t, From e1ab10cb0d111bcc9aec347ca58e7b093afa8f83 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Fri, 8 Nov 2024 13:10:00 +0000 Subject: [PATCH 44/48] Fixed LD1W (into ZA, 32-bit) buffer overflow error. --- src/lib/arch/aarch64/Instruction_execute.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index b99cd2fce5..604c90f8fc 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -3633,7 +3633,7 @@ void Instruction::execute() { for (int i = 0; i < partition_num; i++) { const uint32_t* row = sourceValues_[i].getAsVector(); uint32_t out[64] = {0}; - memcpy(out, row, partition_num * sizeof(uint64_t)); + memcpy(out, row, partition_num * sizeof(uint32_t)); uint64_t shifted_active = 1ull << ((i % 16) * 4); if (pg[i / 16] & shifted_active) { out[sliceNum] = data[i]; From a39dd23301677e3322a3015b41ceed790cb152a2 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Thu, 5 Dec 2024 13:35:31 +0000 Subject: [PATCH 45/48] Removed STREAMING_SVE and STREAMING_PREDICATE groups and associated logic. --- configs/a64fx_SME.yaml | 48 +---------- .../simeng/arch/aarch64/Instruction.hh | 9 -- .../simeng/arch/aarch64/InstructionGroups.hh | 86 ++++++------------- src/include/simeng/arch/riscv/Instruction.hh | 3 - src/lib/arch/aarch64/Architecture.cc | 14 --- src/lib/arch/aarch64/Instruction.cc | 57 ++++++------ src/lib/arch/aarch64/Instruction_decode.cc | 44 ---------- src/lib/arch/aarch64/MicroDecoder.cc | 23 ----- src/lib/arch/riscv/Instruction.cc | 19 +++- src/lib/arch/riscv/Instruction_decode.cc | 27 ------ src/lib/config/ModelConfig.cc | 27 ++---- .../aarch64/AArch64RegressionTest.hh | 2 +- test/regression/aarch64/Exception.cc | 3 +- test/unit/aarch64/ArchitectureTest.cc | 44 ---------- test/unit/aarch64/InstructionTest.cc | 72 +--------------- test/unit/riscv/InstructionTest.cc | 4 +- 16 files changed, 86 insertions(+), 396 deletions(-) diff --git a/configs/a64fx_SME.yaml b/configs/a64fx_SME.yaml index 3cf55a525b..4d1090ae82 100644 --- a/configs/a64fx_SME.yaml +++ b/configs/a64fx_SME.yaml @@ -98,24 +98,11 @@ Ports: Portname: BR Instruction-Group-Support: - BRANCH -# Define example SME / SVE Streaming Mode units +# Define example SME unit 8: Portname: SME Instruction-Group-Support: - SME - 9: - Portname: PR_S - Instruction-Group-Support: - - STREAMING_PREDICATE - 10: - Portname: FLA_S - Instruction-Group-Support: - - STREAMING_SVE - 11: - Portname: FLB_S - Instruction-Group-Support: - - STREAMING_SVE_SIMPLE - - STREAMING_SVE_MUL Reservation-Stations: 0: Size: 20 @@ -150,13 +137,6 @@ Reservation-Stations: Dispatch-Rate: 1 Ports: - SME - 6: - Size: 40 - Dispatch-Rate: 3 - Ports: - - FLA_S - - FLB_S - - PR_S Execution-Units: 0: Pipelined: True @@ -212,24 +192,6 @@ Execution-Units: - INT_DIV_OR_SQRT - FP_DIV_OR_SQRT - SVE_DIV_OR_SQRT - 9: - Pipelined: True - Blocking-Groups: - - INT_DIV_OR_SQRT - - FP_DIV_OR_SQRT - - SVE_DIV_OR_SQRT - 10: - Pipelined: True - Blocking-Groups: - - INT_DIV_OR_SQRT - - FP_DIV_OR_SQRT - - SVE_DIV_OR_SQRT - 11: - Pipelined: True - Blocking-Groups: - - INT_DIV_OR_SQRT - - FP_DIV_OR_SQRT - - SVE_DIV_OR_SQRT Latencies: 0: Instruction-Groups: @@ -258,11 +220,9 @@ Latencies: - SCALAR_SIMPLE - VECTOR_SIMPLE_LOGICAL - SVE_SIMPLE_LOGICAL - - STREAMING_SVE_SIMPLE_LOGICAL - SME_SIMPLE_LOGICAL - VECTOR_SIMPLE_CMP - SVE_SIMPLE_CMP - - STREAMING_SVE_SIMPLE_CMP - SME_SIMPLE_CMP Execution-Latency: 4 Execution-Throughput: 1 @@ -276,25 +236,21 @@ Latencies: - SCALAR_SIMPLE_CVT - VECTOR_SIMPLE - SVE_SIMPLE - - STREAMING_SVE_SIMPLE - SME_SIMPLE - FP_MUL - SVE_MUL - - STREAMING_SVE_MUL - SME_MUL Execution-Latency: 9 Execution-Throughput: 1 7: Instruction-Groups: - SVE_DIV_OR_SQRT - - STREAMING_SVE_DIV_OR_SQRT - SME_DIV_OR_SQRT Execution-Latency: 98 Execution-Throughput: 98 8: Instruction-Groups: - PREDICATE - - STREAMING_PREDICATE Execution-Latency: 3 Execution-Throughput: 1 9: @@ -308,10 +264,8 @@ Latencies: 10: Instruction-Groups: - LOAD_SVE - - LOAD_STREAMING_SVE - LOAD_SME - STORE_ADDRESS_SVE - - STORE_ADDRESS_STREAMING_SVE - STORE_ADDRESS_SME Execution-Latency: 6 Execution-Throughput: 1 diff --git a/src/include/simeng/arch/aarch64/Instruction.hh b/src/include/simeng/arch/aarch64/Instruction.hh index 73a15efb9e..b5f1f07cc5 100644 --- a/src/include/simeng/arch/aarch64/Instruction.hh +++ b/src/include/simeng/arch/aarch64/Instruction.hh @@ -391,12 +391,6 @@ class Instruction : public simeng::Instruction { * processing this instruction. */ InstructionException getException() const; - /** Checks whether the current SVE Streaming Mode status is different to when - * this instruction was first decoded, and updates the instruction group - * accordingly if required. - * Returns TRUE if the group was updated, FALSE otherwise. */ - bool checkStreamingGroupAndUpdate(); - private: /** Process the instruction's metadata to determine source/destination * registers. */ @@ -478,9 +472,6 @@ class Instruction : public simeng::Instruction { * the `InsnType` namespace allowing each bit to represent a unique * identifier such as `isLoad` or `isMultiply` etc. */ uint32_t instructionIdentifier_ = 0; - - /** The instruction group this instruction belongs to. */ - uint16_t instructionGroup_ = InstructionGroups::NONE; }; } // namespace aarch64 diff --git a/src/include/simeng/arch/aarch64/InstructionGroups.hh b/src/include/simeng/arch/aarch64/InstructionGroups.hh index 6c58ff4976..fc15e95230 100644 --- a/src/include/simeng/arch/aarch64/InstructionGroups.hh +++ b/src/include/simeng/arch/aarch64/InstructionGroups.hh @@ -98,53 +98,37 @@ const uint16_t LOAD_SVE = 62; const uint16_t STORE_ADDRESS_SVE = 63; const uint16_t STORE_DATA_SVE = 64; const uint16_t STORE_SVE = 65; -const uint16_t STREAMING_SVE = 66; -const uint16_t STREAMING_SVE_SIMPLE = 67; -const uint16_t STREAMING_SVE_SIMPLE_ARTH = 68; -const uint16_t STREAMING_SVE_SIMPLE_ARTH_NOSHIFT = 69; -const uint16_t STREAMING_SVE_SIMPLE_LOGICAL = 70; -const uint16_t STREAMING_SVE_SIMPLE_LOGICAL_NOSHIFT = 71; -const uint16_t STREAMING_SVE_SIMPLE_CMP = 72; -const uint16_t STREAMING_SVE_SIMPLE_CVT = 73; -const uint16_t STREAMING_SVE_MUL = 74; -const uint16_t STREAMING_SVE_DIV_OR_SQRT = 75; -const uint16_t LOAD_STREAMING_SVE = 76; -const uint16_t STORE_ADDRESS_STREAMING_SVE = 77; -const uint16_t STORE_DATA_STREAMING_SVE = 78; -const uint16_t STORE_STREAMING_SVE = 79; -const uint16_t SME = 80; -const uint16_t SME_SIMPLE = 81; -const uint16_t SME_SIMPLE_ARTH = 82; -const uint16_t SME_SIMPLE_ARTH_NOSHIFT = 83; -const uint16_t SME_SIMPLE_LOGICAL = 84; -const uint16_t SME_SIMPLE_LOGICAL_NOSHIFT = 85; -const uint16_t SME_SIMPLE_CMP = 86; -const uint16_t SME_SIMPLE_CVT = 87; -const uint16_t SME_MUL = 88; -const uint16_t SME_DIV_OR_SQRT = 89; -const uint16_t LOAD_SME = 90; -const uint16_t STORE_ADDRESS_SME = 91; -const uint16_t STORE_DATA_SME = 92; -const uint16_t STORE_SME = 93; -const uint16_t PREDICATE = 94; -const uint16_t STREAMING_PREDICATE = 95; -const uint16_t LOAD = 96; -const uint16_t STORE_ADDRESS = 97; -const uint16_t STORE_DATA = 98; -const uint16_t STORE = 99; -const uint16_t BRANCH = 100; -const uint16_t ALL = 101; -const uint16_t NONE = 102; +const uint16_t PREDICATE = 66; +const uint16_t LOAD = 67; +const uint16_t STORE_ADDRESS = 68; +const uint16_t STORE_DATA = 69; +const uint16_t STORE = 70; +const uint16_t BRANCH = 71; +const uint16_t SME = 72; +const uint16_t SME_SIMPLE = 73; +const uint16_t SME_SIMPLE_ARTH = 74; +const uint16_t SME_SIMPLE_ARTH_NOSHIFT = 75; +const uint16_t SME_SIMPLE_LOGICAL = 76; +const uint16_t SME_SIMPLE_LOGICAL_NOSHIFT = 77; +const uint16_t SME_SIMPLE_CMP = 78; +const uint16_t SME_SIMPLE_CVT = 79; +const uint16_t SME_MUL = 80; +const uint16_t SME_DIV_OR_SQRT = 81; +const uint16_t LOAD_SME = 82; +const uint16_t STORE_ADDRESS_SME = 83; +const uint16_t STORE_DATA_SME = 84; +const uint16_t STORE_SME = 85; +const uint16_t ALL = 86; +const uint16_t NONE = 87; } // namespace InstructionGroups /** The number of aarch64 instruction groups. */ -static constexpr uint8_t NUM_GROUPS = 103; +static constexpr uint8_t NUM_GROUPS = 88; const std::unordered_map> groupInheritance_ = { {InstructionGroups::ALL, {InstructionGroups::INT, InstructionGroups::FP, InstructionGroups::SVE, - InstructionGroups::STREAMING_SVE, InstructionGroups::SME, - InstructionGroups::PREDICATE, InstructionGroups::STREAMING_PREDICATE, + InstructionGroups::SME, InstructionGroups::PREDICATE, InstructionGroups::LOAD, InstructionGroups::STORE, InstructionGroups::BRANCH}}, {InstructionGroups::INT, @@ -218,19 +202,6 @@ const std::unordered_map> groupInheritance_ = { {InstructionGroups::SVE_SIMPLE_ARTH_NOSHIFT}}, {InstructionGroups::SVE_SIMPLE_LOGICAL, {InstructionGroups::SVE_SIMPLE_LOGICAL_NOSHIFT}}, - {InstructionGroups::STREAMING_SVE, - {InstructionGroups::STREAMING_SVE_SIMPLE, - InstructionGroups::STREAMING_SVE_DIV_OR_SQRT, - InstructionGroups::STREAMING_SVE_MUL}}, - {InstructionGroups::STREAMING_SVE_SIMPLE, - {InstructionGroups::STREAMING_SVE_SIMPLE_ARTH, - InstructionGroups::STREAMING_SVE_SIMPLE_LOGICAL, - InstructionGroups::STREAMING_SVE_SIMPLE_CMP, - InstructionGroups::STREAMING_SVE_SIMPLE_CVT}}, - {InstructionGroups::STREAMING_SVE_SIMPLE_ARTH, - {InstructionGroups::STREAMING_SVE_SIMPLE_ARTH_NOSHIFT}}, - {InstructionGroups::STREAMING_SVE_SIMPLE_LOGICAL, - {InstructionGroups::STREAMING_SVE_SIMPLE_LOGICAL_NOSHIFT}}, {InstructionGroups::SME, {InstructionGroups::SME_SIMPLE, InstructionGroups::SME_DIV_OR_SQRT, InstructionGroups::SME_MUL}}, @@ -244,11 +215,11 @@ const std::unordered_map> groupInheritance_ = { {InstructionGroups::LOAD, {InstructionGroups::LOAD_INT, InstructionGroups::LOAD_SCALAR, InstructionGroups::LOAD_VECTOR, InstructionGroups::LOAD_SVE, - InstructionGroups::LOAD_STREAMING_SVE, InstructionGroups::LOAD_SME}}, + InstructionGroups::LOAD_SME}}, {InstructionGroups::STORE, {InstructionGroups::STORE_INT, InstructionGroups::STORE_SCALAR, InstructionGroups::STORE_VECTOR, InstructionGroups::STORE_SVE, - InstructionGroups::STORE_STREAMING_SVE, InstructionGroups::STORE_SME}}, + InstructionGroups::STORE_SME}}, {InstructionGroups::STORE_INT, {InstructionGroups::STORE_ADDRESS_INT, InstructionGroups::STORE_DATA_INT}}, {InstructionGroups::STORE_SCALAR, @@ -259,9 +230,6 @@ const std::unordered_map> groupInheritance_ = { InstructionGroups::STORE_DATA_VECTOR}}, {InstructionGroups::STORE_SVE, {InstructionGroups::STORE_ADDRESS_SVE, InstructionGroups::STORE_DATA_SVE}}, - {InstructionGroups::STORE_STREAMING_SVE, - {InstructionGroups::STORE_ADDRESS_STREAMING_SVE, - InstructionGroups::STORE_DATA_STREAMING_SVE}}, {InstructionGroups::STORE_SME, {InstructionGroups::STORE_ADDRESS_SME, InstructionGroups::STORE_DATA_SME}}, {InstructionGroups::STORE_ADDRESS, @@ -269,12 +237,10 @@ const std::unordered_map> groupInheritance_ = { InstructionGroups::STORE_ADDRESS_SCALAR, InstructionGroups::STORE_ADDRESS_VECTOR, InstructionGroups::STORE_ADDRESS_SVE, - InstructionGroups::STORE_ADDRESS_STREAMING_SVE, InstructionGroups::STORE_ADDRESS_SME}}, {InstructionGroups::STORE_DATA, {InstructionGroups::STORE_DATA_INT, InstructionGroups::STORE_DATA_SCALAR, InstructionGroups::STORE_DATA_VECTOR, InstructionGroups::STORE_DATA_SVE, - InstructionGroups::STORE_DATA_STREAMING_SVE, InstructionGroups::STORE_DATA_SME}}}; } // namespace aarch64 diff --git a/src/include/simeng/arch/riscv/Instruction.hh b/src/include/simeng/arch/riscv/Instruction.hh index bff382df04..9e707449c6 100644 --- a/src/include/simeng/arch/riscv/Instruction.hh +++ b/src/include/simeng/arch/riscv/Instruction.hh @@ -252,9 +252,6 @@ class Instruction : public simeng::Instruction { * the `InsnType` namespace allowing each bit to represent a unique * identifier such as `isLoad` or `isMultiply` etc. */ uint16_t instructionIdentifier_ = 0; - - /** The instruction group this instruction belongs to. */ - uint16_t instructionGroup_ = InstructionGroups::NONE; }; } // namespace riscv diff --git a/src/lib/arch/aarch64/Architecture.cc b/src/lib/arch/aarch64/Architecture.cc index cf847b1f65..3ff09c5b5c 100644 --- a/src/lib/arch/aarch64/Architecture.cc +++ b/src/lib/arch/aarch64/Architecture.cc @@ -191,20 +191,6 @@ uint8_t Architecture::predecode(const uint8_t* ptr, uint16_t bytesAvailable, newInsn.setExecutionInfo(getExecutionInfo(newInsn)); // Cache the instruction iter = decodeCache_.insert({insn, newInsn}).first; - } else { - Instruction& cachedInsn = decodeCache_.at(insn); - // Check if SVE or Predicate instructions need their group updating due to - // SVE Streaming Mode activeness being different from when the instruction - // was first decoded. - if (cachedInsn.checkStreamingGroupAndUpdate()) { - // If the instruction's group has changed then update its execution info. - // The newly set group is most likely to be the most accurate, as an - // incorrect group allocation is only achieved when an exception/flush is - // triggered by changing the SVE Streaming Mode state. - cachedInsn.setExecutionInfo(getExecutionInfo(cachedInsn)); - } - // Need to re-set iterator after updating the decodeCache_ structure - iter = decodeCache_.find(insn); } // Split instruction into 1 or more defined micro-ops diff --git a/src/lib/arch/aarch64/Instruction.cc b/src/lib/arch/aarch64/Instruction.cc index 2811c72625..e3b697433e 100644 --- a/src/lib/arch/aarch64/Instruction.cc +++ b/src/lib/arch/aarch64/Instruction.cc @@ -131,7 +131,35 @@ bool Instruction::isLoad() const { return isInstruction(InsnType::isLoad); } bool Instruction::isBranch() const { return isInstruction(InsnType::isBranch); } -uint16_t Instruction::getGroup() const { return instructionGroup_; } +uint16_t Instruction::getGroup() const { + // Use identifiers to decide instruction group + // Set base + uint16_t base = InstructionGroups::INT; + if (isInstruction(InsnType::isScalarData)) + base = InstructionGroups::SCALAR; + else if (isInstruction(InsnType::isVectorData)) + base = InstructionGroups::VECTOR; + else if (isInstruction(InsnType::isSVEData)) + base = InstructionGroups::SVE; + else if (isInstruction(InsnType::isSMEData)) + base = InstructionGroups::SME; + + if (isInstruction(InsnType::isLoad)) return base + 10; + if (isInstruction(InsnType::isStoreAddress)) return base + 11; + if (isInstruction(InsnType::isStoreData)) return base + 12; + if (isInstruction(InsnType::isBranch)) return InstructionGroups::BRANCH; + if (isInstruction(InsnType::isPredicate)) return InstructionGroups::PREDICATE; + if (isInstruction(InsnType::isDivideOrSqrt)) return base + 9; + if (isInstruction(InsnType::isMultiply)) return base + 8; + if (isInstruction(InsnType::isConvert)) return base + 7; + if (isInstruction(InsnType::isCompare)) return base + 6; + if (isInstruction(InsnType::isLogical)) { + if (isInstruction(InsnType::isShift)) return base + 4; + return base + 5; + } + if (isInstruction(InsnType::isShift)) return base + 2; + return base + 3; // Default return is {Data type}_SIMPLE_ARTH +} bool Instruction::canExecute() const { return (sourceOperandsPending_ == 0); } @@ -164,33 +192,6 @@ const Architecture& Instruction::getArchitecture() const { InstructionException Instruction::getException() const { return exception_; } -bool Instruction::checkStreamingGroupAndUpdate() { - // Only instruction groups that depend on SVE Streaming Mode are SVE and - // PREDICATE - const uint16_t currentGroup = instructionGroup_; - const bool smEnabled = architecture_.isStreamingModeEnabled(); - if (isInstruction(InsnType::isPredicate)) { - // Decide on predicate group based on whether SVE Streaming Mode is enabled. - instructionGroup_ = smEnabled ? InstructionGroups::STREAMING_PREDICATE - : InstructionGroups::PREDICATE; - } else if (isInstruction(InsnType::isSVEData)) { - assert(((instructionGroup_ >= InstructionGroups::SVE && - instructionGroup_ <= InstructionGroups::STORE_SVE) || - (instructionGroup_ >= InstructionGroups::STREAMING_SVE && - instructionGroup_ <= InstructionGroups::STORE_STREAMING_SVE)) && - "Invalid instruction group for SVE instruction."); - // Get instruction group offset. - instructionGroup_ -= (instructionGroup_ >= InstructionGroups::STREAMING_SVE) - ? InstructionGroups::STREAMING_SVE - : InstructionGroups::SVE; - // Add instruction group base depending on whether SVE Streaming Mode is - // enabled. - instructionGroup_ += - smEnabled ? InstructionGroups::STREAMING_SVE : InstructionGroups::SVE; - } - return (currentGroup != instructionGroup_); -} - } // namespace aarch64 } // namespace arch } // namespace simeng diff --git a/src/lib/arch/aarch64/Instruction_decode.cc b/src/lib/arch/aarch64/Instruction_decode.cc index ad5b4d83c3..3535ce590f 100644 --- a/src/lib/arch/aarch64/Instruction_decode.cc +++ b/src/lib/arch/aarch64/Instruction_decode.cc @@ -646,50 +646,6 @@ void Instruction::decode() { sourceValues_.resize(sourceRegisterCount_); results_.resize(destinationRegisterCount_); } - - // Calculate the instruction's group based on identifiers - bool smEnabled = architecture_.isStreamingModeEnabled(); - // Set base group - uint16_t group = InstructionGroups::INT; - if (isInstruction(InsnType::isScalarData)) - group = InstructionGroups::SCALAR; - else if (isInstruction(InsnType::isVectorData)) - group = InstructionGroups::VECTOR; - else if (isInstruction(InsnType::isSVEData)) - group = - smEnabled ? InstructionGroups::STREAMING_SVE : InstructionGroups::SVE; - else if (isInstruction(InsnType::isSMEData)) - group = InstructionGroups::SME; - // Identify subgroup type - if (isInstruction(InsnType::isLoad)) - group += 10; - else if (isInstruction(InsnType::isStoreAddress)) - group += 11; - else if (isInstruction(InsnType::isStoreData)) - group += 12; - else if (isInstruction(InsnType::isBranch)) - group = InstructionGroups::BRANCH; - else if (isInstruction(InsnType::isPredicate)) - group = smEnabled ? InstructionGroups::STREAMING_PREDICATE - : InstructionGroups::PREDICATE; - else if (isInstruction(InsnType::isDivideOrSqrt)) - group += 9; - else if (isInstruction(InsnType::isMultiply)) - group += 8; - else if (isInstruction(InsnType::isConvert)) - group += 7; - else if (isInstruction(InsnType::isCompare)) - group += 6; - else if (isInstruction(InsnType::isLogical)) { - if (isInstruction(InsnType::isShift)) - group += 4; - else - group += 5; - } else if (isInstruction(InsnType::isShift)) - group += 2; - else - group += 3; // Default is {Data type}_SIMPLE_ARTH_NOSHIFT - instructionGroup_ = group; } } // namespace aarch64 diff --git a/src/lib/arch/aarch64/MicroDecoder.cc b/src/lib/arch/aarch64/MicroDecoder.cc index 6f93566784..ea181c8d66 100644 --- a/src/lib/arch/aarch64/MicroDecoder.cc +++ b/src/lib/arch/aarch64/MicroDecoder.cc @@ -615,29 +615,6 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, } } } - // TODO: When SVE instructions have micro-op support, include the - // following code to ensure instruction groups are correct in SVE - // Streaming Mode - // - /* else { - std::vector& cachedUops = microDecodeCache_.at(word); - for (size_t uop = 0; uop < iter->second.size(); uop++) { - // Check if SVE or Predicate instructions need their group updating due - // to SVE Streaming Mode activeness being different from when the - // instruction was first decoded. - if (cachedUops[uop].checkStreamingGroupAndUpdate()) { - // If the instruction's group has changed then update its execution - // info. The newly set group is most likely to be the most accurate, - // as an incorrect group allocation is only achieved when an - // exception/flush is triggered by changing the SVE Streaming Mode - // state. - cachedUops[uop].setExecutionInfo( - architecture.getExecutionInfo(cachedUops[uop])); - } - } - // Need to re-set iterator after updating the microDecodeCache_ - structure iter = microDecodeCache_.find(word); - } */ // Get the number of micro-operations split into and transfer into passed // output vector num_ops = iter->second.size(); diff --git a/src/lib/arch/riscv/Instruction.cc b/src/lib/arch/riscv/Instruction.cc index 472e7f7ad7..c71b581a60 100644 --- a/src/lib/arch/riscv/Instruction.cc +++ b/src/lib/arch/riscv/Instruction.cc @@ -126,7 +126,24 @@ bool Instruction::isLoad() const { return isInstruction(InsnType::isLoad); } bool Instruction::isBranch() const { return isInstruction(InsnType::isBranch); } -uint16_t Instruction::getGroup() const { return instructionGroup_; } +uint16_t Instruction::getGroup() const { + uint16_t base = InstructionGroups::INT; + + if (isInstruction(InsnType::isFloat)) { + base = InstructionGroups::FLOAT; + } + + if (isInstruction(InsnType::isBranch)) return InstructionGroups::BRANCH; + if (isInstruction(InsnType::isLoad)) return base + 8; + if (isInstruction(InsnType::isStore)) return base + 9; + if (isInstruction(InsnType::isDivide)) return base + 7; + if (isInstruction(InsnType::isMultiply)) return base + 6; + if (isInstruction(InsnType::isShift) || isInstruction(InsnType::isConvert)) + return base + 5; + if (isInstruction(InsnType::isLogical)) return base + 4; + if (isInstruction(InsnType::isCompare)) return base + 3; + return base + 2; // Default return is {Data type}_SIMPLE_ARTH +} bool Instruction::canExecute() const { return (sourceOperandsPending_ == 0); } diff --git a/src/lib/arch/riscv/Instruction_decode.cc b/src/lib/arch/riscv/Instruction_decode.cc index 5337cc095e..e8145d4c11 100644 --- a/src/lib/arch/riscv/Instruction_decode.cc +++ b/src/lib/arch/riscv/Instruction_decode.cc @@ -310,33 +310,6 @@ void Instruction::decode() { knownOffset_ = sourceImm_; break; } - - // Calculate the instruction's group based on identifiers - // Set base group - uint16_t group = InstructionGroups::INT; - if (isInstruction(InsnType::isFloat)) group = InstructionGroups::FLOAT; - // Identify subgroup type - if (isInstruction(InsnType::isBranch)) - group = InstructionGroups::BRANCH; - else if (isInstruction(InsnType::isLoad)) - group += 8; - else if (isInstruction(InsnType::isStore)) - group += 9; - else if (isInstruction(InsnType::isDivide)) - group += 7; - else if (isInstruction(InsnType::isMultiply)) - group += 6; - else if (isInstruction(InsnType::isShift) || - isInstruction(InsnType::isConvert)) - group += 5; - else if (isInstruction(InsnType::isLogical)) - group += 4; - else if (isInstruction(InsnType::isCompare)) - group += 3; - else - group += 2; // Default return is {Data type}_SIMPLE_ARTH - - instructionGroup_ = group; } } // namespace riscv diff --git a/src/lib/config/ModelConfig.cc b/src/lib/config/ModelConfig.cc index b911dc58b2..6d54b50d06 100644 --- a/src/lib/config/ModelConfig.cc +++ b/src/lib/config/ModelConfig.cc @@ -1186,20 +1186,12 @@ void ModelConfig::createGroupMapping() { "STORE_ADDRESS_SVE", "STORE_DATA_SVE", "STORE_SVE", - "STREAMING_SVE", - "STREAMING_SVE_SIMPLE", - "STREAMING_SVE_SIMPLE_ARTH", - "STREAMING_SVE_SIMPLE_ARTH_NOSHIFT", - "STREAMING_SVE_SIMPLE_LOGICAL", - "STREAMING_SVE_SIMPLE_LOGICAL_NOSHIFT", - "STREAMING_SVE_SIMPLE_CMP", - "STREAMING_SVE_SIMPLE_CVT", - "STREAMING_SVE_MUL", - "STREAMING_SVE_DIV_OR_SQRT", - "LOAD_STREAMING_SVE", - "STORE_ADDRESS_STREAMING_SVE", - "STORE_DATA_STREAMING_SVE", - "STORE_STREAMING_SVE", + "PREDICATE", + "LOAD", + "STORE_ADDRESS", + "STORE_DATA", + "STORE", + "BRANCH", "SME", "SME_SIMPLE", "SME_SIMPLE_ARTH", @@ -1214,13 +1206,6 @@ void ModelConfig::createGroupMapping() { "STORE_ADDRESS_SME", "STORE_DATA_SME", "STORE_SME", - "PREDICATE", - "STREAMING_PREDICATE", - "LOAD", - "STORE_ADDRESS", - "STORE_DATA", - "STORE", - "BRANCH", "ALL", "NONE"}; } else if (isa_ == ISA::RV64) { diff --git a/test/regression/aarch64/AArch64RegressionTest.hh b/test/regression/aarch64/AArch64RegressionTest.hh index fafe7f4f9a..32d975b09d 100644 --- a/test/regression/aarch64/AArch64RegressionTest.hh +++ b/test/regression/aarch64/AArch64RegressionTest.hh @@ -29,7 +29,7 @@ }, Ports: { - '0': { Portname: 0, Instruction-Group-Support: [INT, FP, SVE, PREDICATE, LOAD, STORE, BRANCH, SME, STREAMING_SVE, STREAMING_PREDICATE] }, + '0': { Portname: 0, Instruction-Group-Support: [INT, FP, SVE, PREDICATE, LOAD, STORE, BRANCH, SME] }, }, } )YAML"; diff --git a/test/regression/aarch64/Exception.cc b/test/regression/aarch64/Exception.cc index dd92f698a3..b987ae4429 100644 --- a/test/regression/aarch64/Exception.cc +++ b/test/regression/aarch64/Exception.cc @@ -389,8 +389,7 @@ INSTANTIATE_TEST_SUITE_P( "{Core: {Vector-Length: 512, Streaming-Vector-Length: 1024}, " "LSQ-L1-Interface: {Load-Bandwidth: 256, Store-Bandwidth: 256}, " "Ports: {'0': {Portname: 0, Instruction-Group-Support: [INT, SVE, " - "STREAMING_SVE, PREDICATE, STREAMING_PREDICATE, LOAD, STORE, " - "BRANCH, SME]}}}")), + "PREDICATE, LOAD, STORE, BRANCH, SME]}}}")), paramToString); } // namespace diff --git a/test/unit/aarch64/ArchitectureTest.cc b/test/unit/aarch64/ArchitectureTest.cc index 779f3806ac..8f2619a283 100644 --- a/test/unit/aarch64/ArchitectureTest.cc +++ b/test/unit/aarch64/ArchitectureTest.cc @@ -118,50 +118,6 @@ TEST_F(AArch64ArchitectureTest, predecode) { EXPECT_EQ(output[0]->getInstructionAddress(), 0x4); EXPECT_EQ(output[0]->exceptionEncountered(), false); EXPECT_EQ(output[0]->getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); - - // Test that a cached (when SVE Streaming Mode was disabled) SVE instruction - // has its group changed to a STREAMING group when SVE Streaming Mode is - // enabled - output = MacroOp(); - EXPECT_FALSE(arch->isStreamingModeEnabled()); - arch->setSVCRval(3); // SVCR.SMZA = 1 - EXPECT_TRUE(arch->isStreamingModeEnabled()); - result = arch->predecode(validInstrBytes.data(), validInstrBytes.size(), 0x4, - output); - EXPECT_EQ(result, 4); - EXPECT_EQ(output[0]->getInstructionAddress(), 0x4); - EXPECT_EQ(output[0]->exceptionEncountered(), false); - EXPECT_EQ(output[0]->getGroup(), - InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); - - // Test that the same cached SVE instruction has its group reverted to - // non-STREAMING when SVE Streaming Mode is disabled again - output = MacroOp(); - EXPECT_TRUE(arch->isStreamingModeEnabled()); - arch->setSVCRval(2); // SVCR.ZA = 1, SVCR.SM = 0 - EXPECT_FALSE(arch->isStreamingModeEnabled()); - result = arch->predecode(validInstrBytes.data(), validInstrBytes.size(), 0x4, - output); - EXPECT_EQ(result, 4); - EXPECT_EQ(output[0]->getInstructionAddress(), 0x4); - EXPECT_EQ(output[0]->exceptionEncountered(), false); - EXPECT_EQ(output[0]->getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); -} - -TEST_F(AArch64ArchitectureTest, predecode_streamingMode) { - // Test that an un-cached SVE instruction is put into a STREAMING group when - // SVE Streaming Mode is enabled - MacroOp output; - EXPECT_FALSE(arch->isStreamingModeEnabled()); - arch->setSVCRval(3); - EXPECT_TRUE(arch->isStreamingModeEnabled()); - uint8_t result = arch->predecode(validInstrBytes.data(), - validInstrBytes.size(), 0x4, output); - EXPECT_EQ(result, 4); - EXPECT_EQ(output[0]->getInstructionAddress(), 0x4); - EXPECT_EQ(output[0]->exceptionEncountered(), false); - EXPECT_EQ(output[0]->getGroup(), - InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); } TEST_F(AArch64ArchitectureTest, getSystemRegisterTag) { diff --git a/test/unit/aarch64/InstructionTest.cc b/test/unit/aarch64/InstructionTest.cc index 33b4c108cd..06ab76c1e3 100644 --- a/test/unit/aarch64/InstructionTest.cc +++ b/test/unit/aarch64/InstructionTest.cc @@ -198,7 +198,7 @@ TEST_F(AArch64InstructionTest, invalidInsn_1) { EXPECT_EQ(insn.getException(), InstructionException::EncodingUnallocated); EXPECT_EQ(insn.getGeneratedAddresses().size(), 0); // Default Group for instruction that is not decoded - EXPECT_EQ(insn.getGroup(), InstructionGroups::NONE); + EXPECT_EQ(insn.getGroup(), InstructionGroups::INT_SIMPLE_ARTH_NOSHIFT); EXPECT_EQ(insn.getInstructionAddress(), 0x44); EXPECT_EQ(insn.getInstructionId(), 13); EXPECT_EQ(insn.getKnownOffset(), 0); @@ -264,7 +264,7 @@ TEST_F(AArch64InstructionTest, invalidInsn_2) { EXPECT_EQ(insn.getException(), InstructionException::HypervisorCall); EXPECT_EQ(insn.getGeneratedAddresses().size(), 0); // Default Group for instruction that is not decoded - EXPECT_EQ(insn.getGroup(), InstructionGroups::NONE); + EXPECT_EQ(insn.getGroup(), InstructionGroups::INT_SIMPLE_ARTH_NOSHIFT); EXPECT_EQ(insn.getInstructionAddress(), 0x43); EXPECT_EQ(insn.getInstructionId(), 15); EXPECT_EQ(insn.getKnownOffset(), 0); @@ -642,74 +642,6 @@ TEST_F(AArch64InstructionTest, setters) { EXPECT_TRUE(insn.isWaitingCommit()); } -TEST_F(AArch64InstructionTest, checkStreamingGroupAndUpdate) { - EXPECT_FALSE(arch.isStreamingModeEnabled()); - // Insn is `fdivr z1.s, p0/m, z1.s, z0.s` - Instruction SVE_insn = Instruction(arch, *fdivMetadata.get(), MicroOpInfo()); - EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); - // insn is `cbz x2, #0x28` - Instruction nonSVE_insn = - Instruction(arch, *cbzMetadata.get(), MicroOpInfo()); - EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); - // insn is `psel p4, p0, p2.s[w13, 0]` - Instruction PRED_insn = Instruction(arch, *pselMetadata.get(), MicroOpInfo()); - EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::PREDICATE); - - // Without changing SVE Streaming Mode, calling checkStreamingGroupAndUpdate - // should have no effect - EXPECT_FALSE(arch.isStreamingModeEnabled()); - EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); - EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); - EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::PREDICATE); - EXPECT_FALSE(SVE_insn.checkStreamingGroupAndUpdate()); - EXPECT_FALSE(nonSVE_insn.checkStreamingGroupAndUpdate()); - EXPECT_FALSE(PRED_insn.checkStreamingGroupAndUpdate()); - EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); - EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); - EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::PREDICATE); - - // Updating SVE Streaming Mode should mean calling - // checkStreamingGroupAndUpdate changes SVE and PRED groups - arch.setSVCRval(3); - EXPECT_TRUE(arch.isStreamingModeEnabled()); - EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); - EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); - EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::PREDICATE); - EXPECT_TRUE(SVE_insn.checkStreamingGroupAndUpdate()); - EXPECT_FALSE(nonSVE_insn.checkStreamingGroupAndUpdate()); - EXPECT_TRUE(PRED_insn.checkStreamingGroupAndUpdate()); - EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); - EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); - EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::STREAMING_PREDICATE); - - // Calling checkStreamingGroupAndUpdate again should have no effect on SVE and - // PRED groups, and should return false as a result - EXPECT_TRUE(arch.isStreamingModeEnabled()); - EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); - EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); - EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::STREAMING_PREDICATE); - EXPECT_FALSE(SVE_insn.checkStreamingGroupAndUpdate()); - EXPECT_FALSE(nonSVE_insn.checkStreamingGroupAndUpdate()); - EXPECT_FALSE(PRED_insn.checkStreamingGroupAndUpdate()); - EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); - EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); - EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::STREAMING_PREDICATE); - - // Disabling SVE Streaming Mode should cause SVE and PRED groups to be updated - // again to non-STREAMING, and true returned as a result - arch.setSVCRval(0); - EXPECT_FALSE(arch.isStreamingModeEnabled()); - EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::STREAMING_SVE_DIV_OR_SQRT); - EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); - EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::STREAMING_PREDICATE); - EXPECT_TRUE(SVE_insn.checkStreamingGroupAndUpdate()); - EXPECT_FALSE(nonSVE_insn.checkStreamingGroupAndUpdate()); - EXPECT_TRUE(PRED_insn.checkStreamingGroupAndUpdate()); - EXPECT_EQ(SVE_insn.getGroup(), InstructionGroups::SVE_DIV_OR_SQRT); - EXPECT_EQ(nonSVE_insn.getGroup(), InstructionGroups::BRANCH); - EXPECT_EQ(PRED_insn.getGroup(), InstructionGroups::PREDICATE); -} - } // namespace aarch64 } // namespace arch } // namespace simeng \ No newline at end of file diff --git a/test/unit/riscv/InstructionTest.cc b/test/unit/riscv/InstructionTest.cc index 43e0daf745..64eff7071c 100644 --- a/test/unit/riscv/InstructionTest.cc +++ b/test/unit/riscv/InstructionTest.cc @@ -179,7 +179,7 @@ TEST_F(RiscVInstructionTest, invalidInsn_1) { EXPECT_EQ(insn.getException(), InstructionException::EncodingUnallocated); EXPECT_EQ(insn.getGeneratedAddresses().size(), 0); // Default Group for instruction that is not decoded - EXPECT_EQ(insn.getGroup(), InstructionGroups::NONE); + EXPECT_EQ(insn.getGroup(), InstructionGroups::INT_SIMPLE_ARTH); EXPECT_EQ(insn.getInstructionAddress(), 0x44); EXPECT_EQ(insn.getInstructionId(), 13); EXPECT_EQ(insn.getKnownOffset(), 0); @@ -243,7 +243,7 @@ TEST_F(RiscVInstructionTest, invalidInsn_2) { EXPECT_EQ(insn.getException(), InstructionException::HypervisorCall); EXPECT_EQ(insn.getGeneratedAddresses().size(), 0); // Default Group for instruction that is not decoded - EXPECT_EQ(insn.getGroup(), InstructionGroups::NONE); + EXPECT_EQ(insn.getGroup(), InstructionGroups::INT_SIMPLE_ARTH); EXPECT_EQ(insn.getInstructionAddress(), 0x43); EXPECT_EQ(insn.getInstructionId(), 15); EXPECT_EQ(insn.getKnownOffset(), 0); From 611d607101ebe59cac8d79c680be4f6dadc7cb37 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Thu, 5 Dec 2024 13:38:09 +0000 Subject: [PATCH 46/48] Reverted docs aarch64 instruction groups image. --- .../assets/instruction_groups_AArch64.png | Bin 145502 -> 51409 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/sphinx/assets/instruction_groups_AArch64.png b/docs/sphinx/assets/instruction_groups_AArch64.png index f877fd7795c68fe8113f1816c44eab082176997e..ad71920824f9ca3dc38451629ee6e782b4161f0e 100644 GIT binary patch literal 51409 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 z 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 literal 145502 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 z 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 N{;YB}N6zH#{{d>~hZz6> From f3088d5e503d5edc96dd5d433f37663b34889e90 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Mon, 16 Dec 2024 12:36:13 +0000 Subject: [PATCH 47/48] Fixed order of vector concat for NEON uminp. --- src/include/simeng/arch/aarch64/helpers/neon.hh | 4 ++-- test/regression/aarch64/instructions/neon.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/simeng/arch/aarch64/helpers/neon.hh b/src/include/simeng/arch/aarch64/helpers/neon.hh index 4ada414951..cc9aa03461 100644 --- a/src/include/simeng/arch/aarch64/helpers/neon.hh +++ b/src/include/simeng/arch/aarch64/helpers/neon.hh @@ -592,8 +592,8 @@ RegisterValue vecUMinP(srcValContainer& sourceValues) { // Concatenate the vectors T temp[2 * I]; - memcpy(temp, m, sizeof(T) * I); - memcpy(temp + (sizeof(T) * I), n, sizeof(T) * I); + memcpy(temp, n, sizeof(T) * I); + memcpy(temp + (sizeof(T) * I), m, sizeof(T) * I); T out[I]; for (int i = 0; i < I; i++) { diff --git a/test/regression/aarch64/instructions/neon.cc b/test/regression/aarch64/instructions/neon.cc index 572ad842d5..96d23590a6 100644 --- a/test/regression/aarch64/instructions/neon.cc +++ b/test/regression/aarch64/instructions/neon.cc @@ -2684,8 +2684,8 @@ TEST_P(InstNeon, uminp) { )"); CHECK_NEON(2, uint8_t, - {0x00, 0x11, 0x22, 0x44, 0xEE, 0xCC, 0xAA, 0x88, 0x00, 0xAA, 0xBB, - 0xDD, 0x01, 0x03, 0x05, 0x07}); + {0x00, 0xAA, 0xBB, 0xDD, 0x01, 0x03, 0x05, 0x07, 0x00, 0x11, 0x22, + 0x44, 0xEE, 0xCC, 0xAA, 0x88}); } TEST_P(InstNeon, umaxp) { // umaxp vd.16b vn.16b vm.16b From 1232bcc49938fb8b7bdb2d0d20ab29f9bf5d3de3 Mon Sep 17 00:00:00 2001 From: Finn Wilkinson Date: Fri, 20 Dec 2024 11:25:55 +0000 Subject: [PATCH 48/48] Post rebase fixes. --- src/lib/arch/aarch64/Instruction_execute.cc | 68 ++-- test/regression/aarch64/instructions/sme.cc | 329 ++++++++++---------- 2 files changed, 209 insertions(+), 188 deletions(-) diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 604c90f8fc..8f4bc38142 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -1410,7 +1410,8 @@ void Instruction::execute() { const uint64_t* pg = sourceValues_[1].getAsVector(); const uint32_t sliceNum = (sourceValues_[2 + rowCount].get() + - static_cast(metadata_.operands[2].sme_index.disp)) % + static_cast( + metadata_.operands[2].sme.slice_offset.imm)) % rowCount; const uint64_t* zaRow = sourceValues_[2 + sliceNum].getAsVector(); @@ -1438,7 +1439,8 @@ void Instruction::execute() { const uint64_t* pg = sourceValues_[1].getAsVector(); const uint32_t sliceNum = (sourceValues_[2 + rowCount].get() + - static_cast(metadata_.operands[2].sme_index.disp)) % + static_cast( + metadata_.operands[2].sme.slice_offset.imm)) % rowCount; const uint16_t* zaRow = sourceValues_[2 + sliceNum].getAsVector(); @@ -1500,7 +1502,8 @@ void Instruction::execute() { const uint64_t* pg = sourceValues_[1].getAsVector(); const uint32_t sliceNum = (sourceValues_[2 + rowCount].get() + - static_cast(metadata_.operands[2].sme_index.disp)) % + static_cast( + metadata_.operands[2].sme.slice_offset.imm)) % rowCount; const uint32_t* zaRow = sourceValues_[2 + sliceNum].getAsVector(); @@ -1528,7 +1531,8 @@ void Instruction::execute() { const uint64_t* pg = sourceValues_[1].getAsVector(); const uint32_t sliceNum = (sourceValues_[2 + rowCount].get() + - static_cast(metadata_.operands[2].sme_index.disp)) % + static_cast( + metadata_.operands[2].sme.slice_offset.imm)) % rowCount; uint8_t out[256] = {0}; @@ -1555,7 +1559,8 @@ void Instruction::execute() { const uint64_t* pg = sourceValues_[1].getAsVector(); const uint32_t sliceNum = (sourceValues_[2 + rowCount].get() + - static_cast(metadata_.operands[2].sme_index.disp)) % + static_cast( + metadata_.operands[2].sme.slice_offset.imm)) % rowCount; uint64_t out[32] = {0}; @@ -1582,7 +1587,8 @@ void Instruction::execute() { const uint64_t* pg = sourceValues_[1].getAsVector(); const uint32_t sliceNum = (sourceValues_[2 + rowCount].get() + - static_cast(metadata_.operands[2].sme_index.disp)) % + static_cast( + metadata_.operands[2].sme.slice_offset.imm)) % rowCount; uint16_t out[128] = {0}; @@ -1642,7 +1648,8 @@ void Instruction::execute() { const uint64_t* pg = sourceValues_[1].getAsVector(); const uint32_t sliceNum = (sourceValues_[2 + rowCount].get() + - static_cast(metadata_.operands[2].sme_index.disp)) % + static_cast( + metadata_.operands[2].sme.slice_offset.imm)) % rowCount; uint32_t out[64] = {0}; @@ -3004,7 +3011,8 @@ void Instruction::execute() { const uint16_t rowCount = VL_bits / 8; const uint32_t sliceNum = (sourceValues_[rowCount].get() + - static_cast(metadata_.operands[0].sme_index.disp)) % + static_cast( + metadata_.operands[0].sme.slice_offset.imm)) % rowCount; const uint8_t* zaRow = sourceValues_[sliceNum].getAsVector(); const uint64_t* pg = @@ -3036,7 +3044,8 @@ void Instruction::execute() { const uint16_t rowCount = VL_bits / 64; const uint32_t sliceNum = (sourceValues_[rowCount].get() + - static_cast(metadata_.operands[0].sme_index.disp)) % + static_cast( + metadata_.operands[0].sme.slice_offset.imm)) % rowCount; const uint64_t* zaRow = sourceValues_[sliceNum].getAsVector(); const uint64_t* pg = @@ -3069,7 +3078,8 @@ void Instruction::execute() { const uint16_t rowCount = VL_bits / 16; const uint32_t sliceNum = (sourceValues_[rowCount].get() + - static_cast(metadata_.operands[0].sme_index.disp)) % + static_cast( + metadata_.operands[0].sme.slice_offset.imm)) % rowCount; const uint16_t* zaRow = sourceValues_[sliceNum].getAsVector(); const uint64_t* pg = @@ -3142,7 +3152,8 @@ void Instruction::execute() { const uint16_t rowCount = VL_bits / 32; const uint32_t sliceNum = (sourceValues_[rowCount].get() + - static_cast(metadata_.operands[0].sme_index.disp)) % + static_cast( + metadata_.operands[0].sme.slice_offset.imm)) % rowCount; const uint32_t* zaRow = sourceValues_[sliceNum].getAsVector(); const uint64_t* pg = @@ -3175,7 +3186,8 @@ void Instruction::execute() { const uint16_t rowCount = VL_bits / 8; const uint32_t sliceNum = (sourceValues_[rowCount].get() + - static_cast(metadata_.operands[0].sme_index.disp)) % + static_cast( + metadata_.operands[0].sme.slice_offset.imm)) % rowCount; const uint64_t* pg = sourceValues_[rowCount + 1].getAsVector(); @@ -3201,7 +3213,8 @@ void Instruction::execute() { const uint16_t rowCount = VL_bits / 64; const uint32_t sliceNum = (sourceValues_[rowCount].get() + - static_cast(metadata_.operands[0].sme_index.disp)) % + static_cast( + metadata_.operands[0].sme.slice_offset.imm)) % rowCount; const uint64_t* pg = sourceValues_[rowCount + 1].getAsVector(); @@ -3228,7 +3241,8 @@ void Instruction::execute() { const uint16_t rowCount = VL_bits / 16; const uint32_t sliceNum = (sourceValues_[rowCount].get() + - static_cast(metadata_.operands[0].sme_index.disp)) % + static_cast( + metadata_.operands[0].sme.slice_offset.imm)) % rowCount; const uint64_t* pg = sourceValues_[rowCount + 1].getAsVector(); @@ -3287,7 +3301,8 @@ void Instruction::execute() { const uint16_t rowCount = VL_bits / 32; const uint32_t sliceNum = (sourceValues_[rowCount].get() + - static_cast(metadata_.operands[0].sme_index.disp)) % + static_cast( + metadata_.operands[0].sme.slice_offset.imm)) % rowCount; const uint64_t* pg = sourceValues_[rowCount + 1].getAsVector(); @@ -3344,7 +3359,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint16_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; const uint8_t* data = memoryData_[0].getAsVector(); uint8_t out[256] = {0}; @@ -3514,7 +3529,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; const uint8_t* data = memoryData_[0].getAsVector(); for (int i = 0; i < partition_num; i++) { @@ -3541,7 +3556,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; const uint64_t* data = memoryData_[0].getAsVector(); for (int i = 0; i < partition_num; i++) { @@ -3568,7 +3583,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; const uint16_t* data = memoryData_[0].getAsVector(); for (int i = 0; i < partition_num; i++) { @@ -4637,7 +4652,8 @@ void Instruction::execute() { const uint16_t rowCount = VL_bits / 8; const uint32_t wn = sourceValues_[rowCount].get(); const uint32_t sliceNum = - wn + static_cast(metadata_.operands[0].sme_index.disp); + wn + + static_cast(metadata_.operands[0].sme.slice_offset.imm); const uint8_t* data = memoryData_[0].getAsVector(); uint8_t out[256] = {0}; @@ -5588,7 +5604,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; const uint8_t* tileSlice = sourceValues_[sliceNum].getAsVector(); @@ -5626,7 +5642,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; const uint16_t* tileSlice = sourceValues_[sliceNum].getAsVector(); @@ -5688,7 +5704,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; const uint32_t* tileSlice = sourceValues_[sliceNum].getAsVector(); @@ -5707,7 +5723,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; std::vector memData; uint16_t index = 0; @@ -5779,7 +5795,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; std::vector memData; uint16_t index = 0; @@ -6468,7 +6484,7 @@ void Instruction::execute() { const uint16_t zaRowCount = VL_bits / 8; const uint32_t wv = sourceValues_[zaRowCount].get(); - const uint32_t imm = metadata_.operands[0].sme_index.disp; + const uint32_t imm = metadata_.operands[0].sme.slice_offset.imm; const uint8_t* zaRow = sourceValues_[(wv + imm) % zaRowCount].getAsVector(); diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index caca903a21..a54c0c981a 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -48,26 +48,26 @@ TEST_P(InstSme, addha) { for (uint32_t i = 0; i < (SVL / 32); i++) { // All rows, all elems - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, uint32_t, fillNeon(index32, (SVL / 8))); - CHECK_MAT_COL(ARM64_REG_ZAS0, i, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS0, i, uint32_t, fillNeon({i}, (SVL / 8))); // All rows, even elements - CHECK_MAT_ROW(ARM64_REG_ZAS1, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS1, i, uint32_t, fillNeon(inter32, (SVL / 8))); if (i % 2 == 0) { // Even rows, all elements - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, uint32_t, fillNeon(index32, (SVL / 8))); // Even rows, even elements - CHECK_MAT_ROW(ARM64_REG_ZAS3, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS3, i, uint32_t, fillNeon(inter32, (SVL / 8))); } else { // Even rows, all elements - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, uint32_t, fillNeon(full32, (SVL / 8))); // Even rows, even elements - CHECK_MAT_ROW(ARM64_REG_ZAS3, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS3, i, uint32_t, fillNeon(full32, (SVL / 8))); } } @@ -111,26 +111,26 @@ TEST_P(InstSme, addha) { for (uint64_t i = 0; i < (SVL / 64); i++) { // All rows, all elems - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, uint64_t, fillNeon(index64, (SVL / 8))); - CHECK_MAT_COL(ARM64_REG_ZAD0, i, uint64_t, + CHECK_MAT_COL(AARCH64_REG_ZAD0, i, uint64_t, fillNeon({i}, (SVL / 8))); // All rows, even elements - CHECK_MAT_ROW(ARM64_REG_ZAD1, i, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD1, i, uint64_t, fillNeon(inter64, (SVL / 8))); if (i % 2 == 0) { // Even rows, all elements - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, uint64_t, fillNeon(index64, (SVL / 8))); // Even rows, even elements - CHECK_MAT_ROW(ARM64_REG_ZAD3, i, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD3, i, uint64_t, fillNeon(inter64, (SVL / 8))); } else { // Even rows, all elements - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, uint64_t, fillNeon(full64, (SVL / 8))); // Even rows, even elements - CHECK_MAT_ROW(ARM64_REG_ZAD3, i, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD3, i, uint64_t, fillNeon(full64, (SVL / 8))); } } @@ -176,26 +176,26 @@ TEST_P(InstSme, addva) { for (uint32_t i = 0; i < (SVL / 32); i++) { // All cols, all elems - CHECK_MAT_COL(ARM64_REG_ZAS0, i, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS0, i, uint32_t, fillNeon(index32, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, uint32_t, fillNeon({i}, (SVL / 8))); // All cols, even elements - CHECK_MAT_COL(ARM64_REG_ZAS1, i, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS1, i, uint32_t, fillNeon(inter32, (SVL / 8))); if (i % 2 == 0) { // Even cols, all elements - CHECK_MAT_COL(ARM64_REG_ZAS2, i, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS2, i, uint32_t, fillNeon(index32, (SVL / 8))); // Even cols, even elements - CHECK_MAT_COL(ARM64_REG_ZAS3, i, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS3, i, uint32_t, fillNeon(inter32, (SVL / 8))); } else { // Even cols, all elements - CHECK_MAT_COL(ARM64_REG_ZAS2, i, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS2, i, uint32_t, fillNeon(full32, (SVL / 8))); // Even cols, even elements - CHECK_MAT_COL(ARM64_REG_ZAS3, i, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS3, i, uint32_t, fillNeon(full32, (SVL / 8))); } } @@ -239,26 +239,26 @@ TEST_P(InstSme, addva) { for (uint64_t i = 0; i < (SVL / 64); i++) { // All cols, all elems - CHECK_MAT_COL(ARM64_REG_ZAD0, i, uint64_t, + CHECK_MAT_COL(AARCH64_REG_ZAD0, i, uint64_t, fillNeon(index64, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, uint64_t, fillNeon({i}, (SVL / 8))); // All cols, even elements - CHECK_MAT_COL(ARM64_REG_ZAD1, i, uint64_t, + CHECK_MAT_COL(AARCH64_REG_ZAD1, i, uint64_t, fillNeon(inter64, (SVL / 8))); if (i % 2 == 0) { // Even cols, all elements - CHECK_MAT_COL(ARM64_REG_ZAD2, i, uint64_t, + CHECK_MAT_COL(AARCH64_REG_ZAD2, i, uint64_t, fillNeon(index64, (SVL / 8))); // Even cols, even elements - CHECK_MAT_COL(ARM64_REG_ZAD3, i, uint64_t, + CHECK_MAT_COL(AARCH64_REG_ZAD3, i, uint64_t, fillNeon(inter64, (SVL / 8))); } else { // Even cols, all elements - CHECK_MAT_COL(ARM64_REG_ZAD2, i, uint64_t, + CHECK_MAT_COL(AARCH64_REG_ZAD2, i, uint64_t, fillNeon(full64, (SVL / 8))); // Even cols, even elements - CHECK_MAT_COL(ARM64_REG_ZAD3, i, uint64_t, + CHECK_MAT_COL(AARCH64_REG_ZAD3, i, uint64_t, fillNeon(full64, (SVL / 8))); } } @@ -646,11 +646,12 @@ TEST_P(InstSme, mova_b_vecToTile) { mova za0h.b[w12, #0], p0/m, z0.b mova za0h.b[w12, #1], p1/m, z1.b )"); - CHECK_MAT_ROW(ARM64_REG_ZAB0, 0, uint8_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAB0, 1, uint8_t, + CHECK_MAT_ROW(AARCH64_REG_ZAB0, 0, uint8_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_ROW(AARCH64_REG_ZAB0, 1, uint8_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 8; i++) { - CHECK_MAT_ROW(ARM64_REG_ZAB0, i, uint8_t, + CHECK_MAT_ROW(AARCH64_REG_ZAB0, i, uint8_t, fillNeon({0}, (SVL / 8))); } @@ -671,11 +672,12 @@ TEST_P(InstSme, mova_b_vecToTile) { mov za0h.b[w12, #0], p0/m, z0.b mov za0h.b[w12, #1], p1/m, z1.b )"); - CHECK_MAT_ROW(ARM64_REG_ZAB0, 0, uint8_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAB0, 1, uint8_t, + CHECK_MAT_ROW(AARCH64_REG_ZAB0, 0, uint8_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_ROW(AARCH64_REG_ZAB0, 1, uint8_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 8; i++) { - CHECK_MAT_ROW(ARM64_REG_ZAB0, i, uint8_t, + CHECK_MAT_ROW(AARCH64_REG_ZAB0, i, uint8_t, fillNeon({0}, (SVL / 8))); } @@ -696,11 +698,12 @@ TEST_P(InstSme, mova_b_vecToTile) { mova za0v.b[w12, #0], p0/m, z0.b mova za0v.b[w12, #1], p1/m, z1.b )"); - CHECK_MAT_COL(ARM64_REG_ZAB0, 0, uint8_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_COL(ARM64_REG_ZAB0, 1, uint8_t, + CHECK_MAT_COL(AARCH64_REG_ZAB0, 0, uint8_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_COL(AARCH64_REG_ZAB0, 1, uint8_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 8; i++) { - CHECK_MAT_COL(ARM64_REG_ZAB0, i, uint8_t, + CHECK_MAT_COL(AARCH64_REG_ZAB0, i, uint8_t, fillNeon({0}, (SVL / 8))); } @@ -721,11 +724,12 @@ TEST_P(InstSme, mova_b_vecToTile) { mov za0v.b[w12, #0], p0/m, z0.b mov za0v.b[w12, #1], p1/m, z1.b )"); - CHECK_MAT_COL(ARM64_REG_ZAB0, 0, uint8_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_COL(ARM64_REG_ZAB0, 1, uint8_t, + CHECK_MAT_COL(AARCH64_REG_ZAB0, 0, uint8_t, + fillNeon({1}, (SVL / 8))); + CHECK_MAT_COL(AARCH64_REG_ZAB0, 1, uint8_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 8; i++) { - CHECK_MAT_COL(ARM64_REG_ZAB0, i, uint8_t, + CHECK_MAT_COL(AARCH64_REG_ZAB0, i, uint8_t, fillNeon({0}, (SVL / 8))); } } @@ -749,12 +753,12 @@ TEST_P(InstSme, mova_h_vecToTile) { mova za0h.h[w12, #0], p0/m, z0.h mova za0h.h[w12, #1], p1/m, z1.h )"); - CHECK_MAT_ROW(ARM64_REG_ZAH0, 0, uint16_t, + CHECK_MAT_ROW(AARCH64_REG_ZAH0, 0, uint16_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAH0, 1, uint16_t, + CHECK_MAT_ROW(AARCH64_REG_ZAH0, 1, uint16_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 16; i++) { - CHECK_MAT_ROW(ARM64_REG_ZAH0, i, uint16_t, + CHECK_MAT_ROW(AARCH64_REG_ZAH0, i, uint16_t, fillNeon({0}, (SVL / 8))); } @@ -775,12 +779,12 @@ TEST_P(InstSme, mova_h_vecToTile) { mov za0h.h[w12, #0], p0/m, z0.h mov za0h.h[w12, #1], p1/m, z1.h )"); - CHECK_MAT_ROW(ARM64_REG_ZAH0, 0, uint16_t, + CHECK_MAT_ROW(AARCH64_REG_ZAH0, 0, uint16_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAH0, 1, uint16_t, + CHECK_MAT_ROW(AARCH64_REG_ZAH0, 1, uint16_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 16; i++) { - CHECK_MAT_ROW(ARM64_REG_ZAH0, i, uint16_t, + CHECK_MAT_ROW(AARCH64_REG_ZAH0, i, uint16_t, fillNeon({0}, (SVL / 8))); } @@ -801,12 +805,12 @@ TEST_P(InstSme, mova_h_vecToTile) { mova za0v.h[w12, #0], p0/m, z0.h mova za0v.h[w12, #1], p1/m, z1.h )"); - CHECK_MAT_COL(ARM64_REG_ZAH0, 0, uint16_t, + CHECK_MAT_COL(AARCH64_REG_ZAH0, 0, uint16_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_COL(ARM64_REG_ZAH0, 1, uint16_t, + CHECK_MAT_COL(AARCH64_REG_ZAH0, 1, uint16_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 16; i++) { - CHECK_MAT_COL(ARM64_REG_ZAH0, i, uint16_t, + CHECK_MAT_COL(AARCH64_REG_ZAH0, i, uint16_t, fillNeon({0}, (SVL / 8))); } @@ -827,12 +831,12 @@ TEST_P(InstSme, mova_h_vecToTile) { mov za0v.h[w12, #0], p0/m, z0.h mov za0v.h[w12, #1], p1/m, z1.h )"); - CHECK_MAT_COL(ARM64_REG_ZAH0, 0, uint16_t, + CHECK_MAT_COL(AARCH64_REG_ZAH0, 0, uint16_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_COL(ARM64_REG_ZAH0, 1, uint16_t, + CHECK_MAT_COL(AARCH64_REG_ZAH0, 1, uint16_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 16; i++) { - CHECK_MAT_COL(ARM64_REG_ZAH0, i, uint16_t, + CHECK_MAT_COL(AARCH64_REG_ZAH0, i, uint16_t, fillNeon({0}, (SVL / 8))); } } @@ -856,12 +860,12 @@ TEST_P(InstSme, mova_s_vecToTile) { mova za0h.s[w12, #0], p0/m, z0.s mova za0h.s[w12, #1], p1/m, z1.s )"); - CHECK_MAT_ROW(ARM64_REG_ZAS0, 0, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, 0, uint32_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS0, 1, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, 1, uint32_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 32; i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, uint32_t, fillNeon({0}, (SVL / 8))); } @@ -882,12 +886,12 @@ TEST_P(InstSme, mova_s_vecToTile) { mov za0h.s[w12, #0], p0/m, z0.s mov za0h.s[w12, #1], p1/m, z1.s )"); - CHECK_MAT_ROW(ARM64_REG_ZAS0, 0, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, 0, uint32_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS0, 1, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, 1, uint32_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 32; i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, uint32_t, fillNeon({0}, (SVL / 8))); } @@ -908,12 +912,12 @@ TEST_P(InstSme, mova_s_vecToTile) { mova za0v.s[w12, #0], p0/m, z0.s mova za0v.s[w12, #1], p1/m, z1.s )"); - CHECK_MAT_COL(ARM64_REG_ZAS0, 0, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS0, 0, uint32_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_COL(ARM64_REG_ZAS0, 1, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS0, 1, uint32_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 32; i++) { - CHECK_MAT_COL(ARM64_REG_ZAS0, i, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS0, i, uint32_t, fillNeon({0}, (SVL / 8))); } @@ -934,12 +938,12 @@ TEST_P(InstSme, mova_s_vecToTile) { mov za0v.s[w12, #0], p0/m, z0.s mov za0v.s[w12, #1], p1/m, z1.s )"); - CHECK_MAT_COL(ARM64_REG_ZAS0, 0, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS0, 0, uint32_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_COL(ARM64_REG_ZAS0, 1, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS0, 1, uint32_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 32; i++) { - CHECK_MAT_COL(ARM64_REG_ZAS0, i, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS0, i, uint32_t, fillNeon({0}, (SVL / 8))); } } @@ -963,12 +967,12 @@ TEST_P(InstSme, mova_d_vecToTile) { mova za0h.d[w12, #0], p0/m, z0.d mova za0h.d[w12, #1], p1/m, z1.d )"); - CHECK_MAT_ROW(ARM64_REG_ZAD0, 0, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, 0, uint64_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD0, 1, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, 1, uint64_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 64; i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, uint64_t, fillNeon({0}, (SVL / 8))); } @@ -989,12 +993,12 @@ TEST_P(InstSme, mova_d_vecToTile) { mov za0h.d[w12, #0], p0/m, z0.d mov za0h.d[w12, #1], p1/m, z1.d )"); - CHECK_MAT_ROW(ARM64_REG_ZAD0, 0, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, 0, uint64_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD0, 1, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, 1, uint64_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 64; i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, uint64_t, fillNeon({0}, (SVL / 8))); } @@ -1015,12 +1019,12 @@ TEST_P(InstSme, mova_d_vecToTile) { mova za0v.d[w12, #0], p0/m, z0.d mova za0v.d[w12, #1], p1/m, z1.d )"); - CHECK_MAT_COL(ARM64_REG_ZAD0, 0, uint64_t, + CHECK_MAT_COL(AARCH64_REG_ZAD0, 0, uint64_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_COL(ARM64_REG_ZAD0, 1, uint64_t, + CHECK_MAT_COL(AARCH64_REG_ZAD0, 1, uint64_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 64; i++) { - CHECK_MAT_COL(ARM64_REG_ZAD0, i, uint64_t, + CHECK_MAT_COL(AARCH64_REG_ZAD0, i, uint64_t, fillNeon({0}, (SVL / 8))); } @@ -1041,12 +1045,12 @@ TEST_P(InstSme, mova_d_vecToTile) { mov za0v.d[w12, #0], p0/m, z0.d mov za0v.d[w12, #1], p1/m, z1.d )"); - CHECK_MAT_COL(ARM64_REG_ZAD0, 0, uint64_t, + CHECK_MAT_COL(AARCH64_REG_ZAD0, 0, uint64_t, fillNeon({1}, (SVL / 8))); - CHECK_MAT_COL(ARM64_REG_ZAD0, 1, uint64_t, + CHECK_MAT_COL(AARCH64_REG_ZAD0, 1, uint64_t, fillNeon({2, 0}, (SVL / 8))); for (uint16_t i = 2; i < SVL / 64; i++) { - CHECK_MAT_COL(ARM64_REG_ZAD0, i, uint64_t, + CHECK_MAT_COL(AARCH64_REG_ZAD0, i, uint64_t, fillNeon({0}, (SVL / 8))); } } @@ -1072,10 +1076,10 @@ TEST_P(InstSme, mova_q_vecToTile) { mova za0h.q[w12, #0], p0/m, z0.q mova za0h.q[w12, #0], p1/m, z1.q )"); - CHECK_MAT_ROW(ARM64_REG_ZAQ0, 0, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAQ0, 0, uint64_t, fillNeon({2, 2, 1, 1}, (SVL / 8))); for (uint16_t i = 1; i < SVL / 128; i++) { - CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAQ0, i, uint64_t, fillNeon({0}, (SVL / 8))); } @@ -1098,10 +1102,10 @@ TEST_P(InstSme, mova_q_vecToTile) { mov za0h.q[w12, #0], p0/m, z0.q mov za0h.q[w12, #0], p1/m, z1.q )"); - CHECK_MAT_ROW(ARM64_REG_ZAQ0, 0, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAQ0, 0, uint64_t, fillNeon({2, 2, 1, 1}, (SVL / 8))); for (uint16_t i = 1; i < SVL / 128; i++) { - CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAQ0, i, uint64_t, fillNeon({0}, (SVL / 8))); } @@ -1132,9 +1136,9 @@ TEST_P(InstSme, mova_q_vecToTile) { offRow[1] = 1; for (uint16_t i = 0; i < SVL / 128; i++) { if (i % 2 == 0) { - CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, onRow); + CHECK_MAT_ROW(AARCH64_REG_ZAQ0, i, uint64_t, onRow); } else { - CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, offRow); + CHECK_MAT_ROW(AARCH64_REG_ZAQ0, i, uint64_t, offRow); } } @@ -1159,9 +1163,9 @@ TEST_P(InstSme, mova_q_vecToTile) { )"); for (uint16_t i = 0; i < SVL / 128; i++) { if (i % 2 == 0) { - CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, onRow); + CHECK_MAT_ROW(AARCH64_REG_ZAQ0, i, uint64_t, onRow); } else { - CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, offRow); + CHECK_MAT_ROW(AARCH64_REG_ZAQ0, i, uint64_t, offRow); } } } @@ -1253,9 +1257,9 @@ TEST_P(InstSme, fmops) { fmops za2.s, p0/m, p2/m, z3.s, z4.s )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, float, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, float, fillNeon({-10.0f}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, float, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, float, fillNeon({-24.0f}, (SVL / 16))); } @@ -1283,9 +1287,9 @@ TEST_P(InstSme, fmops) { fmops za2.d, p0/m, p2/m, z3.d, z4.d )"); for (uint64_t i = 0; i < (SVL / 64); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, double, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, double, fillNeon({-10.0}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, double, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, double, fillNeon({-24.0}, (SVL / 16))); } } @@ -1326,16 +1330,16 @@ TEST_P(InstSme, ld1b) { ld1b {za0h.b[w12, 0]}, p1/z, [x0, x2] )"); CHECK_MAT_ROW( - ARM64_REG_ZAB0, 1, uint8_t, + AARCH64_REG_ZAB0, 1, uint8_t, fillNeon({0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01, 0xDE}, SVL / 8)); CHECK_MAT_ROW( - ARM64_REG_ZAB0, 3, uint8_t, + AARCH64_REG_ZAB0, 3, uint8_t, fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, SVL / 8)); - CHECK_MAT_ROW(ARM64_REG_ZAB0, 15, uint8_t, + CHECK_MAT_ROW(AARCH64_REG_ZAB0, 15, uint8_t, fillNeonCombined( {0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, @@ -1377,16 +1381,16 @@ TEST_P(InstSme, ld1b) { ld1b {za0v.b[w12, 0]}, p1/z, [x0, x2] )"); CHECK_MAT_COL( - ARM64_REG_ZAB0, 1, uint8_t, + AARCH64_REG_ZAB0, 1, uint8_t, fillNeon({0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01, 0xDE}, SVL / 8)); CHECK_MAT_COL( - ARM64_REG_ZAB0, 3, uint8_t, + AARCH64_REG_ZAB0, 3, uint8_t, fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, SVL / 8)); - CHECK_MAT_COL(ARM64_REG_ZAB0, 15, uint8_t, + CHECK_MAT_COL(AARCH64_REG_ZAB0, 15, uint8_t, fillNeonCombined( {0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, @@ -1513,15 +1517,15 @@ TEST_P(InstSme, ld1h) { whilelo p1.h, xzr, x1 ld1h {za1h.h[w12, 0]}, p1/z, [x0, x2, lsl #1] )"); - CHECK_MAT_ROW(ARM64_REG_ZAH0, 1, uint16_t, + CHECK_MAT_ROW(AARCH64_REG_ZAH0, 1, uint16_t, fillNeon({0xBEEF, 0x1234, 0x5678, 0x9876, 0x5432, 0xABCD, 0xEF01, 0xDEAD}, SVL / 8)); - CHECK_MAT_ROW(ARM64_REG_ZAH0, 3, uint16_t, + CHECK_MAT_ROW(AARCH64_REG_ZAH0, 3, uint16_t, fillNeon({0xDEAD, 0xBEEF, 0x1234, 0x5678, 0x9876, 0x5432, 0xABCD, 0xEF01}, SVL / 8)); - CHECK_MAT_ROW(ARM64_REG_ZAH1, 1, uint16_t, + CHECK_MAT_ROW(AARCH64_REG_ZAH1, 1, uint16_t, fillNeonCombined({0xDEAD, 0xBEEF, 0x1234, 0x5678, 0x9876, 0x5432, 0xABCD, 0xEF01}, {0}, SVL / 8)); @@ -1559,15 +1563,15 @@ TEST_P(InstSme, ld1h) { whilelo p1.h, xzr, x1 ld1h {za1v.h[w12, 0]}, p1/z, [x0, x2, lsl #1] )"); - CHECK_MAT_COL(ARM64_REG_ZAH0, 1, uint16_t, + CHECK_MAT_COL(AARCH64_REG_ZAH0, 1, uint16_t, fillNeon({0xBEEF, 0x1234, 0x5678, 0x9876, 0x5432, 0xABCD, 0xEF01, 0xDEAD}, SVL / 8)); - CHECK_MAT_COL(ARM64_REG_ZAH0, 3, uint16_t, + CHECK_MAT_COL(AARCH64_REG_ZAH0, 3, uint16_t, fillNeon({0xDEAD, 0xBEEF, 0x1234, 0x5678, 0x9876, 0x5432, 0xABCD, 0xEF01}, SVL / 8)); - CHECK_MAT_COL(ARM64_REG_ZAH1, 1, uint16_t, + CHECK_MAT_COL(AARCH64_REG_ZAH1, 1, uint16_t, fillNeonCombined({0xDEAD, 0xBEEF, 0x1234, 0x5678, 0x9876, 0x5432, 0xABCD, 0xEF01}, {0}, SVL / 8)); @@ -1602,11 +1606,11 @@ TEST_P(InstSme, ld1q) { zip1 p0.d, p0.d, p0.d ld1q {za15h.q[w12, 0]}, p0/z, [x0] )"); - CHECK_MAT_ROW(ARM64_REG_ZAQ0, 1 % (SVL / 128), uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAQ0, 1 % (SVL / 128), uint64_t, fillNeon({0x98765432ABCDEF01, 0xDEADBEEF12345678, 0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); - CHECK_MAT_ROW(ARM64_REG_ZAQ15, 1 % (SVL / 128), uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAQ15, 1 % (SVL / 128), uint64_t, fillNeon( {0xDEADBEEF12345678, 0x98765432ABCDEF01, 0, 0}, SVL / 8)); @@ -1650,11 +1654,11 @@ TEST_P(InstSme, ld1q) { row1[3 % (SVL / 64)] = 0x98765432ABCDEF01; for (uint16_t i = 0; i < SVL / 128; i++) { if (i % 2 == 0) { - CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, row0); - CHECK_MAT_ROW(ARM64_REG_ZAQ15, i, uint64_t, row1); + CHECK_MAT_ROW(AARCH64_REG_ZAQ0, i, uint64_t, row0); + CHECK_MAT_ROW(AARCH64_REG_ZAQ15, i, uint64_t, row1); } else { - CHECK_MAT_ROW(ARM64_REG_ZAQ0, i, uint64_t, row1); - CHECK_MAT_ROW(ARM64_REG_ZAQ15, i, uint64_t, zeroRow); + CHECK_MAT_ROW(AARCH64_REG_ZAQ0, i, uint64_t, row1); + CHECK_MAT_ROW(AARCH64_REG_ZAQ15, i, uint64_t, zeroRow); } } } @@ -1771,19 +1775,20 @@ TEST_P(InstSme, ldr) { ldr za[w12, 2], [x0, #2, mul vl] )"); CHECK_MAT_ROW( - ARM64_REG_ZAB0, 0, uint8_t, + AARCH64_REG_ZAB0, 0, uint8_t, fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, SVL / 8)); - CHECK_MAT_ROW(ARM64_REG_ZAB0, 1, uint8_t, fillNeon({0}, SVL / 8)); + CHECK_MAT_ROW(AARCH64_REG_ZAB0, 1, uint8_t, fillNeon({0}, SVL / 8)); CHECK_MAT_ROW( - ARM64_REG_ZAB0, 2, uint8_t, + AARCH64_REG_ZAB0, 2, uint8_t, fillNeon({0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x98, 0x76, 0x54, 0x32, 0xAB, 0xCD, 0xEF, 0x01}, SVL / 8)); for (uint16_t i = 3; i < SVL / 8; i++) { - CHECK_MAT_ROW(ARM64_REG_ZAB0, i, uint8_t, fillNeon({0}, SVL / 8)); + CHECK_MAT_ROW(AARCH64_REG_ZAB0, i, uint8_t, + fillNeon({0}, SVL / 8)); } } @@ -1812,9 +1817,9 @@ TEST_P(InstSme, smopa) { smopa za2.s, p0/m, p2/m, z3.b, z4.b )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, int32_t, fillNeon({96}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, int32_t, fillNeon({112}, (SVL / 16))); } @@ -1842,9 +1847,9 @@ TEST_P(InstSme, smopa) { smopa za2.d, p0/m, p2/m, z3.h, z4.h )"); for (uint64_t i = 0; i < (SVL / 64); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, int64_t, fillNeon({96}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, int64_t, fillNeon({112}, (SVL / 16))); } } @@ -1874,9 +1879,9 @@ TEST_P(InstSme, smops) { smops za2.s, p0/m, p2/m, z3.b, z4.b )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, int32_t, fillNeon({-96}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, int32_t, fillNeon({-112}, (SVL / 16))); } @@ -1904,9 +1909,9 @@ TEST_P(InstSme, smops) { smops za2.d, p0/m, p2/m, z3.h, z4.h )"); for (uint64_t i = 0; i < (SVL / 64); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, int64_t, fillNeon({-96}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, int64_t, fillNeon({-112}, (SVL / 16))); } } @@ -2756,13 +2761,13 @@ TEST_P(InstSme, str) { str za[w12, #0], [x2] )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, uint32_t, fillNeon({40}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS1, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS1, i, uint32_t, fillNeon({0}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, uint32_t, fillNeon({20}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS3, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS3, i, uint32_t, fillNeon({0}, (SVL / 8))); } const uint64_t SVL_bytes = SVL / 8; @@ -2802,9 +2807,9 @@ TEST_P(InstSme, sumopa) { sumopa za2.s, p0/m, p2/m, z3.b, z4.b )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, int32_t, fillNeon({-96}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, int32_t, fillNeon({-112}, (SVL / 16))); } @@ -2833,9 +2838,9 @@ TEST_P(InstSme, sumopa) { sumopa za2.s, p0/m, p2/m, z3.b, z4.b )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, int32_t, fillNeon({3060}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, int32_t, fillNeon({7112}, (SVL / 16))); } @@ -2863,9 +2868,9 @@ TEST_P(InstSme, sumopa) { sumopa za2.d, p0/m, p2/m, z3.h, z4.h )"); for (uint64_t i = 0; i < (SVL / 64); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, int64_t, fillNeon({-96}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, int64_t, fillNeon({-112}, (SVL / 16))); } @@ -2894,9 +2899,9 @@ TEST_P(InstSme, sumopa) { sumopa za2.d, p0/m, p2/m, z3.h, z4.h )"); for (uint64_t i = 0; i < (SVL / 64); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, int64_t, fillNeon({786420}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, int64_t, fillNeon({1834952}, (SVL / 16))); } } @@ -2926,9 +2931,9 @@ TEST_P(InstSme, sumops) { sumops za2.s, p0/m, p2/m, z3.b, z4.b )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, int32_t, fillNeon({96}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, int32_t, fillNeon({112}, (SVL / 16))); } @@ -2957,9 +2962,9 @@ TEST_P(InstSme, sumops) { sumops za2.s, p0/m, p2/m, z3.b, z4.b )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, int32_t, fillNeon({-3060}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, int32_t, fillNeon({-7112}, (SVL / 16))); } @@ -2987,9 +2992,9 @@ TEST_P(InstSme, sumops) { sumops za2.d, p0/m, p2/m, z3.h, z4.h )"); for (uint64_t i = 0; i < (SVL / 64); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, int64_t, fillNeon({96}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, int64_t, fillNeon({112}, (SVL / 16))); } @@ -3018,9 +3023,9 @@ TEST_P(InstSme, sumops) { sumops za2.d, p0/m, p2/m, z3.h, z4.h )"); for (uint64_t i = 0; i < (SVL / 64); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, int64_t, fillNeon({-786420}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, int64_t, fillNeon({-1834952}, (SVL / 16))); } } @@ -3050,9 +3055,9 @@ TEST_P(InstSme, umopa) { umopa za2.s, p0/m, p2/m, z3.b, z4.b )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, uint32_t, fillNeon({96}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, uint32_t, fillNeon({112}, (SVL / 16))); } @@ -3080,9 +3085,9 @@ TEST_P(InstSme, umopa) { umopa za2.d, p0/m, p2/m, z3.h, z4.h )"); for (uint64_t i = 0; i < (SVL / 64); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, uint64_t, fillNeon({96}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, uint64_t, fillNeon({112}, (SVL / 16))); } } @@ -3116,9 +3121,9 @@ TEST_P(InstSme, umops) { umops za2.s, p0/m, p2/m, z3.b, z5.b )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, uint32_t, fillNeon({32}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, uint32_t, fillNeon({28}, (SVL / 16))); } @@ -3150,9 +3155,9 @@ TEST_P(InstSme, umops) { umops za2.d, p0/m, p2/m, z3.h, z5.h )"); for (uint64_t i = 0; i < (SVL / 64); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, uint64_t, fillNeon({32}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, uint64_t, fillNeon({28}, (SVL / 16))); } } @@ -3182,9 +3187,9 @@ TEST_P(InstSme, usmopa) { usmopa za2.s, p0/m, p2/m, z3.b, z4.b )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, int32_t, fillNeon({-96}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, int32_t, fillNeon({-112}, (SVL / 16))); } @@ -3213,9 +3218,9 @@ TEST_P(InstSme, usmopa) { usmopa za2.s, p0/m, p2/m, z3.b, z4.b )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, int32_t, fillNeon({2024}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, int32_t, fillNeon({7112}, (SVL / 16))); } @@ -3243,9 +3248,9 @@ TEST_P(InstSme, usmopa) { usmopa za2.d, p0/m, p2/m, z3.h, z4.h )"); for (uint64_t i = 0; i < (SVL / 64); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, int64_t, fillNeon({-96}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, int64_t, fillNeon({-112}, (SVL / 16))); } @@ -3274,9 +3279,9 @@ TEST_P(InstSme, usmopa) { usmopa za2.d, p0/m, p2/m, z3.h, z4.h )"); for (uint64_t i = 0; i < (SVL / 64); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, int64_t, fillNeon({524264}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, int64_t, fillNeon({1834952}, (SVL / 16))); } } @@ -3306,9 +3311,9 @@ TEST_P(InstSme, usmops) { usmops za2.s, p0/m, p2/m, z3.b, z4.b )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, int32_t, fillNeon({96}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, int32_t, fillNeon({112}, (SVL / 16))); } @@ -3337,9 +3342,9 @@ TEST_P(InstSme, usmops) { usmops za2.s, p0/m, p2/m, z3.b, z4.b )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, int32_t, fillNeon({-2024}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, int32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, int32_t, fillNeon({-7112}, (SVL / 16))); } @@ -3367,9 +3372,9 @@ TEST_P(InstSme, usmops) { usmops za2.d, p0/m, p2/m, z3.h, z4.h )"); for (uint64_t i = 0; i < (SVL / 64); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, int64_t, fillNeon({96}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, int64_t, fillNeon({112}, (SVL / 16))); } @@ -3398,9 +3403,9 @@ TEST_P(InstSme, usmops) { usmops za2.d, p0/m, p2/m, z3.h, z4.h )"); for (uint64_t i = 0; i < (SVL / 64); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, int64_t, fillNeon({-524264}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, int64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, int64_t, fillNeon({-1834952}, (SVL / 16))); } }