From 523262b34ba411eae0c20fc93e3c2d394fad4d41 Mon Sep 17 00:00:00 2001 From: Lina Yu <108146828+linay-xsj@users.noreply.github.com> Date: Mon, 28 Aug 2023 16:54:10 -0700 Subject: [PATCH] Put exp lookup table into run_time_lib/AIE2 (#604) --- .../AIE/exp_lut.cpp | 56 ++--- aie_runtime_lib/AIE/exp_lut.h | 61 +++++ aie_runtime_lib/AIE/libexp_lut.a | Bin 0 -> 23188 bytes aie_runtime_lib/AIE2/exp_lut.cpp | 216 ++++++++++++++++++ aie_runtime_lib/AIE2/exp_lut.h | 61 +++++ aie_runtime_lib/AIE2/libexp_lut.a | Bin 0 -> 23188 bytes aie_runtime_lib/CMakeLists.txt | 5 +- .../bf16_exp_lut/bf16_exp_lut.mlir | 2 +- 8 files changed, 356 insertions(+), 45 deletions(-) rename test/unit_tests/aievec_tests/bf16_exp_lut/exp_lut.h => aie_runtime_lib/AIE/exp_lut.cpp (90%) create mode 100644 aie_runtime_lib/AIE/exp_lut.h create mode 100644 aie_runtime_lib/AIE/libexp_lut.a create mode 100644 aie_runtime_lib/AIE2/exp_lut.cpp create mode 100644 aie_runtime_lib/AIE2/exp_lut.h create mode 100644 aie_runtime_lib/AIE2/libexp_lut.a diff --git a/test/unit_tests/aievec_tests/bf16_exp_lut/exp_lut.h b/aie_runtime_lib/AIE/exp_lut.cpp similarity index 90% rename from test/unit_tests/aievec_tests/bf16_exp_lut/exp_lut.h rename to aie_runtime_lib/AIE/exp_lut.cpp index fd4fe0e7a2..e014b8508c 100644 --- a/test/unit_tests/aievec_tests/bf16_exp_lut/exp_lut.h +++ b/aie_runtime_lib/AIE/exp_lut.cpp @@ -1,6 +1,16 @@ -#ifndef __EXP_LUT_H__ -#define __EXP_LUT_H__ -#include "adf.h" +//===--- exp_lut.cpp - exponential loopup tables ---===// +// +// This file is licensed under the Apache License v2.0 with LLVM Exceptions +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// (c) Copyright 2023 Xilinx Inc. +// +// +//===----------------------------------------------------------------------===// +// These are exponential lookup tables for bfloat16 type +//===----------------------------------------------------------------------===// + #include "aie_api/aie.hpp" // The tables _ab and _cd are copies of each other @@ -204,43 +214,3 @@ alignas(aie::vector_decl_align) int16 softmax_flut_cd[512] = { 16422, 16423, 16423, 16424, 16419, 16420, 16421, 16421, 16422, 16423, 16423, 16424, 16425, 16425, 16426, 16427, 16427, 16428, 16429, 16429, 16425, 16425, 16426, 16427, 16427, 16428, 16429, 16429}; - -__attribute__((always_inline)) v16accfloat getExpBf16(v16bfloat16 x) { - bfloat16 __aie_dm_resource_a *ilut_ab = - (bfloat16 __aie_dm_resource_a *)softmax_ilut_ab; - bfloat16 __aie_dm_resource_b *ilut_cd = - (bfloat16 __aie_dm_resource_b *)softmax_ilut_cd; - bfloat16 __aie_dm_resource_a *flut_ab = - (bfloat16 __aie_dm_resource_a *)softmax_flut_ab; - bfloat16 __aie_dm_resource_b *flut_cd = - (bfloat16 __aie_dm_resource_b *)softmax_flut_cd; - - using lut_type = aie::lut<4, bfloat16, bfloat16>; - const int LUT_elems = 256; - const int step_i = 8; - const int step_f = 0; - - lut_type lut_i(LUT_elems, ilut_ab, ilut_cd); - lut_type lut_f(LUT_elems, flut_ab, flut_cd); - aie::parallel_lookup - lookup_i(lut_i, step_i); - aie::parallel_lookup - lookup_f(lut_f, step_f); - - aie::vector I_val_vec, F_val_vec; - aie::accum exp_val; - aie::vector input_bf16 = x; - - // position of output decimal point = 8, making input become 8 bits, and for - // LUT_elems = 256 lookup. aie::vector - // input=aie::to_fixed(input_bf16,8); - aie::vector input0 = v32int16(bfloat16_to_int(input_bf16, 8)); - aie::vector input = aie::filter_even(input0); - - I_val_vec = lookup_i.fetch(input.cast_to()); - F_val_vec = lookup_f.fetch(input.cast_to()); - exp_val = aie::mul(I_val_vec, F_val_vec); - return v16accfloat(exp_val); -} - -#endif //__EXP_LUT_H__ diff --git a/aie_runtime_lib/AIE/exp_lut.h b/aie_runtime_lib/AIE/exp_lut.h new file mode 100644 index 0000000000..4ecc5abce5 --- /dev/null +++ b/aie_runtime_lib/AIE/exp_lut.h @@ -0,0 +1,61 @@ +//===--- exp_lut.h - get exponential values from loopup tables ---===// +// +// This file is licensed under the Apache License v2.0 with LLVM Exceptions +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// (c) Copyright 2023 Xilinx Inc. +// +// +//===----------------------------------------------------------------------===// +// This is the implementation of getting exponential values for a bfloat16 +// vector from exponential lookup tables. +//===----------------------------------------------------------------------===// +#ifndef __EXP_LUT_H__ +#define __EXP_LUT_H__ + +#include "aie_api/aie.hpp" + +alignas(aie::vector_decl_align) extern int16 softmax_ilut_ab[512]; +alignas(aie::vector_decl_align) extern int16 softmax_ilut_cd[512]; +alignas(aie::vector_decl_align) extern int16 softmax_flut_ab[512]; +alignas(aie::vector_decl_align) extern int16 softmax_flut_cd[512]; + +__attribute__((always_inline)) v16accfloat getExpBf16(v16bfloat16 x) { + bfloat16 __aie_dm_resource_a *ilut_ab = + (bfloat16 __aie_dm_resource_a *)softmax_ilut_ab; + bfloat16 __aie_dm_resource_b *ilut_cd = + (bfloat16 __aie_dm_resource_b *)softmax_ilut_cd; + bfloat16 __aie_dm_resource_a *flut_ab = + (bfloat16 __aie_dm_resource_a *)softmax_flut_ab; + bfloat16 __aie_dm_resource_b *flut_cd = + (bfloat16 __aie_dm_resource_b *)softmax_flut_cd; + + using lut_type = aie::lut<4, bfloat16, bfloat16>; + const int LUT_elems = 256; + const int step_i = 8; + const int step_f = 0; + + lut_type lut_i(LUT_elems, ilut_ab, ilut_cd); + lut_type lut_f(LUT_elems, flut_ab, flut_cd); + aie::parallel_lookup + lookup_i(lut_i, step_i); + aie::parallel_lookup + lookup_f(lut_f, step_f); + + aie::vector I_val_vec, F_val_vec; + aie::accum exp_val; + aie::vector input_bf16 = x; + + // position of output decimal point = 8, making input become 8 bits, and for + // LUT_elems = 256 lookup. aie::vector + // input=aie::to_fixed(input_bf16,8); + aie::vector input0 = v32int16(bfloat16_to_int(input_bf16, 8)); + aie::vector input = aie::filter_even(input0); + + I_val_vec = lookup_i.fetch(input.cast_to()); + F_val_vec = lookup_f.fetch(input.cast_to()); + exp_val = aie::mul(I_val_vec, F_val_vec); + return v16accfloat(exp_val); +} +#endif //__EXP_LUT_H__ diff --git a/aie_runtime_lib/AIE/libexp_lut.a b/aie_runtime_lib/AIE/libexp_lut.a new file mode 100644 index 0000000000000000000000000000000000000000..8245a4af636300ad9d19b0db3c3ab6535ccdd99d GIT binary patch literal 23188 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 + const int LUT_elems = 256; + const int step_i = 8; + const int step_f = 0; + + lut_type lut_i(LUT_elems, ilut_ab, ilut_cd); + lut_type lut_f(LUT_elems, flut_ab, flut_cd); + aie::parallel_lookup + lookup_i(lut_i, step_i); + aie::parallel_lookup + lookup_f(lut_f, step_f); + + aie::vector I_val_vec, F_val_vec; + aie::accum exp_val; + aie::vector input_bf16 = x; + + // position of output decimal point = 8, making input become 8 bits, and for + // LUT_elems = 256 lookup. aie::vector + // input=aie::to_fixed(input_bf16,8); + aie::vector input0 = v32int16(bfloat16_to_int(input_bf16, 8)); + aie::vector input = aie::filter_even(input0); + + I_val_vec = lookup_i.fetch(input.cast_to()); + F_val_vec = lookup_f.fetch(input.cast_to()); + exp_val = aie::mul(I_val_vec, F_val_vec); + return v16accfloat(exp_val); +} +#endif //__EXP_LUT_H__ diff --git a/aie_runtime_lib/AIE2/libexp_lut.a b/aie_runtime_lib/AIE2/libexp_lut.a new file mode 100644 index 0000000000000000000000000000000000000000..8245a4af636300ad9d19b0db3c3ab6535ccdd99d GIT binary patch literal 23188 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 xca_udm_dbg.stdout // RUN: FileCheck --input-file=./xca_udm_dbg.stdout %s