1/**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16// Test call from asembly
17
18#include <iostream>
19#include <cstdint>
20#include <cmath>
21#include <cassert>
22
23#include <gtest/gtest.h>
24
25class AsmCaller : public ::testing::Test {
26};
27
28#define EMITED_ONE_PARAM_INST_LIST(DEF)                               \
29    DEF(mov, [](auto param) { return param; })                        \
30    DEF(neg, [](auto param) { return -param; })                       \
31    DEF(abs, [](auto param) { return (param > 0) ? param : -param; }) \
32    DEF(not, [](auto param) { return -param - 1L; })
33
34#define EMITED_TWO_PARAM_INST_LIST(DEF)                                \
35    DEF(add, [](auto param1, auto param2) { return param1 + param2; }) \
36    DEF(sub, [](auto param1, auto param2) { return param1 - param2; }) \
37    DEF(mul, [](auto param1, auto param2) { return param1 * param2; }) \
38    DEF(and, [](auto param1, auto param2) { return param1 & param2; }) \
39    DEF(or, [](auto param1, auto param2) { return param1 | param2; })  \
40    DEF(xor, [](auto param1, auto param2) {                            \
41        return param1 ^ param2;                                        \
42    })
43
44#define C_EXTERN_ONE_PARAM(opc, param)                       \
45    extern "C" std::uint8_t test_##opc##_8(std::uint8_t);    \
46    extern "C" std::uint16_t test_##opc##_16(std::uint16_t); \
47    extern "C" std::uint32_t test_##opc##_32(std::uint32_t); \
48    extern "C" std::uint64_t test_##opc##_64(std::uint64_t);
49
50EMITED_ONE_PARAM_INST_LIST(C_EXTERN_ONE_PARAM)
51
52#define C_EXTERN_TWO_PARAM(opc, param)                                      \
53    extern "C" std::uint8_t test_##opc##_8(std::uint8_t, std::uint8_t);     \
54    extern "C" std::uint16_t test_##opc##_16(std::uint16_t, std::uint16_t); \
55    extern "C" std::uint32_t test_##opc##_32(std::uint32_t, std::uint32_t); \
56    extern "C" std::uint64_t test_##opc##_64(std::uint64_t, std::uint64_t);
57
58EMITED_TWO_PARAM_INST_LIST(C_EXTERN_TWO_PARAM)
59
60TEST_F(AsmCaller, call_math)
61{
62    std::int8_t ui8 = 1;
63    std::int8_t ui8_2 = -12;
64    std::int16_t ui16 = 6518;
65    std::int16_t ui16_2 = 6;
66    std::int32_t ui32 = 3;
67    std::int32_t ui32_2 = 0xecf27abf;
68    std::int64_t ui64 = 2423590325;
69    std::int64_t ui64_2 = 8;
70
71#ifdef STDOUT_PRINT
72#define CALL_ONE_PARAM_OUTPUT(opc, param)                                                   \
73    std::cerr << "------------ OUTPUT FOR " << #opc << "------------\n";                    \
74    std::cerr << "ui8 result:" << std::hex << static_cast<uint64_t>(test_##opc##_8(ui8))    \
75              << "  input:" << static_cast<uint64_t>(ui8) << "\n";                          \
76    std::cerr << "ui16 result:" << std::hex << static_cast<uint64_t>(test_##opc##_16(ui16)) \
77              << "  input:" << static_cast<uint64_t>(ui16) << "\n";                         \
78    std::cerr << "ui32 result:" << std::hex << static_cast<uint64_t>(test_##opc##_32(ui32)) \
79              << "  input:" << static_cast<uint64_t>(ui32) << "\n";                         \
80    std::cerr << "ui64 result:" << std::hex << static_cast<uint64_t>(test_##opc##_64(ui64)) \
81              << "  input:" << static_cast<uint64_t>(ui64) << "\n";
82#else
83#define CALL_ONE_PARAM_OUTPUT(opc, param)                                 \
84    EXPECT_EQ(test_##opc##_8(ui8), static_cast<uint8_t>(param(ui8)));     \
85    EXPECT_EQ(test_##opc##_16(ui16), static_cast<uint16_t>(param(ui16))); \
86    EXPECT_EQ(test_##opc##_32(ui32), static_cast<uint32_t>(param(ui32))); \
87    EXPECT_EQ(test_##opc##_64(ui64), static_cast<uint64_t>(param(ui64)));
88#endif
89
90    EMITED_ONE_PARAM_INST_LIST(CALL_ONE_PARAM_OUTPUT)
91
92#ifdef STDOUT_PRINT
93#define CALL_TWO_PARAM_OUTPUT(opc, param)                                                                            \
94    std::cerr << "------------ OUTPUT FOR " << #opc << "------------\n";                                             \
95    std::cerr << "ui8 result:" << std::hex << static_cast<uint64_t>(test_##opc##_8(ui8, ui8_2))                      \
96              << "  input_1:" << static_cast<uint64_t>(ui8) << "  input_2:" << static_cast<uint64_t>(ui8_2) << "\n"; \
97    std::cerr << "ui16 result:" << std::hex << static_cast<uint64_t>(test_##opc##_16(ui16, ui16_2))                  \
98              << "  input:" << static_cast<uint64_t>(ui16) << "  input_2:" << static_cast<uint64_t>(ui16_2) << "\n"; \
99    std::cerr << "ui32 result:" << std::hex << static_cast<uint64_t>(test_##opc##_32(ui32, ui32_2))                  \
100              << "  input:" << static_cast<uint64_t>(ui32) << "  input_2:" << static_cast<uint64_t>(ui32_2) << "\n"; \
101    std::cerr << "ui64 result:" << std::hex << static_cast<uint64_t>(test_##opc##_64(ui64, ui64_2))                  \
102              << "  input:" << static_cast<uint64_t>(ui64) << "  input_2:" << static_cast<uint64_t>(ui64_2) << "\n";
103#else
104#define CALL_TWO_PARAM_OUTPUT(opc, param)                                                 \
105    EXPECT_EQ(test_##opc##_8(ui8, ui8_2), static_cast<uint8_t>(param(ui8, ui8_2)));       \
106    EXPECT_EQ(test_##opc##_16(ui16, ui16_2), static_cast<uint16_t>(param(ui16, ui16_2))); \
107    EXPECT_EQ(test_##opc##_32(ui32, ui32_2), static_cast<uint32_t>(param(ui32, ui32_2))); \
108    EXPECT_EQ(test_##opc##_64(ui64, ui64_2), static_cast<uint64_t>(param(ui64, ui64_2)));
109#endif
110    EMITED_TWO_PARAM_INST_LIST(CALL_TWO_PARAM_OUTPUT)
111}
112