Remove ACLE submodule
This involves moving from the ACLE intrinsic definitions (which aren't available for SVE at this point) to a JSON file. This was derived from ARM's documentation[^1], and then relicensed under `MIT OR Apache-2.0` for use in this repository. [^1]: https://developer.arm.com/architectures/instruction-sets/intrinsics
This commit is contained in:
committed by
Amanieu d'Antras
parent
284b9706d0
commit
0125fa17c8
3
library/stdarch/.gitmodules
vendored
3
library/stdarch/.gitmodules
vendored
@@ -1,3 +0,0 @@
|
|||||||
[submodule "crates/intrinsic-test/acle"]
|
|
||||||
path = crates/intrinsic-test/acle
|
|
||||||
url = https://github.com/ARM-software/acle.git
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
qemu-user \
|
qemu-user \
|
||||||
make \
|
make \
|
||||||
file \
|
file \
|
||||||
clang-13 \
|
clang-15 \
|
||||||
lld
|
lld
|
||||||
|
|
||||||
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
|
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
qemu-user \
|
qemu-user \
|
||||||
make \
|
make \
|
||||||
file \
|
file \
|
||||||
clang-13 \
|
clang-15 \
|
||||||
lld
|
lld
|
||||||
ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \
|
ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \
|
||||||
CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER="qemu-arm -L /usr/arm-linux-gnueabihf" \
|
CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER="qemu-arm -L /usr/arm-linux-gnueabihf" \
|
||||||
|
|||||||
@@ -137,10 +137,10 @@ esac
|
|||||||
|
|
||||||
if [ "${TARGET}" = "aarch64-unknown-linux-gnu" ]; then
|
if [ "${TARGET}" = "aarch64-unknown-linux-gnu" ]; then
|
||||||
export CPPFLAGS="-fuse-ld=lld -I/usr/aarch64-linux-gnu/include/ -I/usr/aarch64-linux-gnu/include/c++/9/aarch64-linux-gnu/"
|
export CPPFLAGS="-fuse-ld=lld -I/usr/aarch64-linux-gnu/include/ -I/usr/aarch64-linux-gnu/include/c++/9/aarch64-linux-gnu/"
|
||||||
RUST_LOG=warn cargo run ${INTRINSIC_TEST} --release --bin intrinsic-test -- crates/intrinsic-test/acle/tools/intrinsic_db/advsimd.csv --runner "${CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER}" --cppcompiler "clang++-13" --skip crates/intrinsic-test/missing_aarch64.txt
|
RUST_LOG=warn cargo run ${INTRINSIC_TEST} --release --bin intrinsic-test -- intrinsics_data/arm_intrinsics.json --runner "${CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER}" --cppcompiler "clang++-15" --skip crates/intrinsic-test/missing_aarch64.txt
|
||||||
elif [ "${TARGET}" = "armv7-unknown-linux-gnueabihf" ]; then
|
elif [ "${TARGET}" = "armv7-unknown-linux-gnueabihf" ]; then
|
||||||
export CPPFLAGS="-fuse-ld=lld -I/usr/arm-linux-gnueabihf/include/ -I/usr/arm-linux-gnueabihf/include/c++/9/arm-linux-gnueabihf/"
|
export CPPFLAGS="-fuse-ld=lld -I/usr/arm-linux-gnueabihf/include/ -I/usr/arm-linux-gnueabihf/include/c++/9/arm-linux-gnueabihf/"
|
||||||
RUST_LOG=warn cargo run ${INTRINSIC_TEST} --release --bin intrinsic-test -- crates/intrinsic-test/acle/tools/intrinsic_db/advsimd.csv --runner "${CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER}" --cppcompiler "clang++-13" --skip crates/intrinsic-test/missing_arm.txt --a32
|
RUST_LOG=warn cargo run ${INTRINSIC_TEST} --release --bin intrinsic-test -- intrinsics_data/arm_intrinsics.json --runner "${CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER}" --cppcompiler "clang++-15" --skip crates/intrinsic-test/missing_arm.txt --a32
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$NORUN" != "1" ] && [ "$NOSTD" != 1 ]; then
|
if [ "$NORUN" != "1" ] && [ "$NOSTD" != 1 ]; then
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "intrinsic-test"
|
name = "intrinsic-test"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Jamie Cunliffe <Jamie.Cunliffe@arm.com>"]
|
authors = ["Jamie Cunliffe <Jamie.Cunliffe@arm.com>",
|
||||||
edition = "2021"
|
"James McGregor <James.McGregor2@arm.com",
|
||||||
|
"Adam Gemmell <Adam.Gemmell@arm.com"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
csv = "1.1"
|
csv = "1.1"
|
||||||
clap = "2.33.3"
|
clap = "2.33.3"
|
||||||
regex = "1.4.2"
|
regex = "1.4.2"
|
||||||
|
|||||||
Submodule library/stdarch/crates/intrinsic-test/acle deleted from 5626f85f46
@@ -23,39 +23,6 @@ vusdotq_lane_s32
|
|||||||
vusdotq_s32
|
vusdotq_s32
|
||||||
vusdot_s32
|
vusdot_s32
|
||||||
|
|
||||||
# Implemented in Clang but missing from CSV
|
|
||||||
vcmla_f64
|
|
||||||
vcmla_lane_f64
|
|
||||||
vcmla_laneq_f64
|
|
||||||
vcmlaq_lane_f64
|
|
||||||
vcmlaq_laneq_f64
|
|
||||||
vcmlaq_rot180_lane_f64
|
|
||||||
vcmlaq_rot180_laneq_f64
|
|
||||||
vcmlaq_rot270_lane_f64
|
|
||||||
vcmlaq_rot270_laneq_f64
|
|
||||||
vcmlaq_rot90_lane_f64
|
|
||||||
vcmlaq_rot90_laneq_f64
|
|
||||||
vcmla_rot180_f64
|
|
||||||
vcmla_rot180_lane_f64
|
|
||||||
vcmla_rot180_laneq_f64
|
|
||||||
vcmla_rot270_f64
|
|
||||||
vcmla_rot270_lane_f64
|
|
||||||
vcmla_rot270_laneq_f64
|
|
||||||
vcmla_rot90_f64
|
|
||||||
vcmla_rot90_lane_f64
|
|
||||||
vcmla_rot90_laneq_f64
|
|
||||||
|
|
||||||
# Implemented in Clang and stdarch but missing from CSV
|
|
||||||
vmov_n_p64
|
|
||||||
vmovq_n_p64
|
|
||||||
vreinterpret_f32_p64
|
|
||||||
vreinterpret_p64_s64
|
|
||||||
vreinterpretq_f32_p128
|
|
||||||
vreinterpretq_f32_p64
|
|
||||||
vreinterpretq_p128_p64
|
|
||||||
vreinterpretq_p64_p128
|
|
||||||
vtst_p16
|
|
||||||
vtstq_p16
|
|
||||||
|
|
||||||
# Missing from both Clang and stdarch
|
# Missing from both Clang and stdarch
|
||||||
vrnd32x_f64
|
vrnd32x_f64
|
||||||
@@ -67,30 +34,17 @@ vrnd64xq_f64
|
|||||||
vrnd64z_f64
|
vrnd64z_f64
|
||||||
vrnd64zq_f64
|
vrnd64zq_f64
|
||||||
|
|
||||||
# QEMU 6.0 doesn't support these instructions
|
|
||||||
vmmlaq_s32
|
|
||||||
vmmlaq_u32
|
|
||||||
vsm3partw1q_u32
|
|
||||||
vsm3partw2q_u32
|
|
||||||
vsm3ss1q_u32
|
|
||||||
vsm3tt1aq_u32
|
|
||||||
vsm3tt1bq_u32
|
|
||||||
vsm3tt2aq_u32
|
|
||||||
vsm3tt2bq_u32
|
|
||||||
vsm4ekeyq_u32
|
|
||||||
vsm4eq_u32
|
|
||||||
vusmmlaq_s32
|
|
||||||
|
|
||||||
# LLVM select error in debug builds
|
# LLVM select error in debug builds
|
||||||
vqshlu_n_s16
|
#vqshlu_n_s16
|
||||||
vqshlu_n_s32
|
#vqshlu_n_s32
|
||||||
vqshlu_n_s64
|
#vqshlu_n_s64
|
||||||
vqshlu_n_s8
|
#vqshlu_n_s8
|
||||||
vqshlub_n_s8
|
#vqshlub_n_s8
|
||||||
vqshlud_n_s64
|
#vqshlud_n_s64
|
||||||
vqshluh_n_s16
|
#vqshluh_n_s16
|
||||||
vqshluq_n_s16
|
#vqshluq_n_s16
|
||||||
vqshluq_n_s32
|
#vqshluq_n_s32
|
||||||
vqshluq_n_s64
|
#vqshluq_n_s64
|
||||||
vqshluq_n_s8
|
#vqshluq_n_s8
|
||||||
vqshlus_n_s32
|
#vqshlus_n_s32
|
||||||
|
|
||||||
|
|||||||
@@ -23,15 +23,6 @@ vusdotq_lane_s32
|
|||||||
vusdotq_s32
|
vusdotq_s32
|
||||||
vusdot_s32
|
vusdot_s32
|
||||||
|
|
||||||
# Implemented in Clang and stdarch but missing from CSV
|
|
||||||
vtst_p16
|
|
||||||
vtstq_p16
|
|
||||||
|
|
||||||
# QEMU 6.0 doesn't support these instructions
|
|
||||||
vmmlaq_s32
|
|
||||||
vmmlaq_u32
|
|
||||||
vusmmlaq_s32
|
|
||||||
|
|
||||||
# Implemented in Clang and stdarch for A64 only even though CSV claims A32 support
|
# Implemented in Clang and stdarch for A64 only even though CSV claims A32 support
|
||||||
__crc32d
|
__crc32d
|
||||||
__crc32cd
|
__crc32cd
|
||||||
@@ -214,110 +205,29 @@ vrndx_f32
|
|||||||
vrndxq_f32
|
vrndxq_f32
|
||||||
|
|
||||||
# LLVM select error in debug builds
|
# LLVM select error in debug builds
|
||||||
vqrshrn_n_s16
|
#vqrshrn_n_s16
|
||||||
vqrshrn_n_s32
|
#vqrshrn_n_s32
|
||||||
vqrshrn_n_s64
|
#vqrshrn_n_s64
|
||||||
vqrshrn_n_u16
|
#vqrshrn_n_u16
|
||||||
vqrshrn_n_u32
|
#vqrshrn_n_u32
|
||||||
vqrshrn_n_u64
|
#vqrshrn_n_u64
|
||||||
vqrshrun_n_s16
|
#vqrshrun_n_s16
|
||||||
vqrshrun_n_s32
|
#vqrshrun_n_s32
|
||||||
vqrshrun_n_s64
|
#vqrshrun_n_s64
|
||||||
vqshrn_n_s16
|
#vqshrn_n_s16
|
||||||
vqshrn_n_s32
|
#vqshrn_n_s32
|
||||||
vqshrn_n_s64
|
#vqshrn_n_s64
|
||||||
vqshrn_n_u16
|
#vqshrn_n_u16
|
||||||
vqshrn_n_u32
|
#vqshrn_n_u32
|
||||||
vqshrn_n_u64
|
#vqshrn_n_u64
|
||||||
vqshrun_n_s16
|
#vqshrun_n_s16
|
||||||
vqshrun_n_s32
|
#vqshrun_n_s32
|
||||||
vqshrun_n_s64
|
#vqshrun_n_s64
|
||||||
vrshrn_n_s16
|
#vrshrn_n_s16
|
||||||
vrshrn_n_s32
|
#vrshrn_n_s32
|
||||||
vrshrn_n_s64
|
#vrshrn_n_s64
|
||||||
vrshrn_n_u16
|
#vrshrn_n_u16
|
||||||
vrshrn_n_u32
|
#vrshrn_n_u32
|
||||||
vrshrn_n_u64
|
#vrshrn_n_u64
|
||||||
vshrq_n_u64
|
#vshrq_n_u64
|
||||||
vshr_n_u64
|
#vshr_n_u64
|
||||||
|
|
||||||
# Failing tests: stdarch has incorrect results compared to Clang
|
|
||||||
vqshlu_n_s16
|
|
||||||
vqshlu_n_s32
|
|
||||||
vqshlu_n_s64
|
|
||||||
vqshlu_n_s8
|
|
||||||
vqshluq_n_s16
|
|
||||||
vqshluq_n_s32
|
|
||||||
vqshluq_n_s64
|
|
||||||
vqshluq_n_s8
|
|
||||||
vsli_n_p16
|
|
||||||
vsli_n_p8
|
|
||||||
vsli_n_s16
|
|
||||||
vsli_n_s32
|
|
||||||
vsli_n_s64
|
|
||||||
vsli_n_s8
|
|
||||||
vsli_n_u16
|
|
||||||
vsli_n_u32
|
|
||||||
vsli_n_u64
|
|
||||||
vsli_n_u8
|
|
||||||
vsliq_n_p16
|
|
||||||
vsliq_n_p8
|
|
||||||
vsliq_n_s16
|
|
||||||
vsliq_n_s32
|
|
||||||
vsliq_n_s64
|
|
||||||
vsliq_n_s8
|
|
||||||
vsliq_n_u16
|
|
||||||
vsliq_n_u32
|
|
||||||
vsliq_n_u64
|
|
||||||
vsliq_n_u8
|
|
||||||
vsri_n_p16
|
|
||||||
vsri_n_p8
|
|
||||||
vsri_n_s16
|
|
||||||
vsri_n_s32
|
|
||||||
vsri_n_s64
|
|
||||||
vsri_n_s8
|
|
||||||
vsri_n_u16
|
|
||||||
vsri_n_u32
|
|
||||||
vsri_n_u64
|
|
||||||
vsri_n_u8
|
|
||||||
vsriq_n_p16
|
|
||||||
vsriq_n_p8
|
|
||||||
vsriq_n_s16
|
|
||||||
vsriq_n_s32
|
|
||||||
vsriq_n_s64
|
|
||||||
vsriq_n_s8
|
|
||||||
vsriq_n_u16
|
|
||||||
vsriq_n_u32
|
|
||||||
vsriq_n_u64
|
|
||||||
vsriq_n_u8
|
|
||||||
|
|
||||||
# These produce a different result on Clang depending on the optimization level.
|
|
||||||
# This is definitely a bug in LLVM.
|
|
||||||
vadd_f32
|
|
||||||
vaddq_f32
|
|
||||||
vcvt_s32_f32
|
|
||||||
vcvt_u32_f32
|
|
||||||
vcvtq_s32_f32
|
|
||||||
vcvtq_u32_f32
|
|
||||||
vfma_f32
|
|
||||||
vfma_n_f32
|
|
||||||
vfmaq_f32
|
|
||||||
vfmaq_n_f32
|
|
||||||
vfms_f32
|
|
||||||
vfmsq_f32
|
|
||||||
vmla_f32
|
|
||||||
vmla_lane_f32
|
|
||||||
vmla_n_f32
|
|
||||||
vmlaq_f32
|
|
||||||
vmlaq_lane_f32
|
|
||||||
vmlaq_n_f32
|
|
||||||
vmls_f32
|
|
||||||
vmls_lane_f32
|
|
||||||
vmls_n_f32
|
|
||||||
vmlsq_f32
|
|
||||||
vmlsq_lane_f32
|
|
||||||
vmlsq_n_f32
|
|
||||||
vmul_lane_f32
|
|
||||||
vmul_n_f32
|
|
||||||
vmulq_lane_f32
|
|
||||||
vmulq_n_f32
|
|
||||||
|
|||||||
@@ -1,363 +0,0 @@
|
|||||||
use itertools::Itertools;
|
|
||||||
use regex::Regex;
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
use crate::argument::{Argument, ArgumentList, Constraint};
|
|
||||||
use crate::intrinsic::Intrinsic;
|
|
||||||
use crate::types::{IntrinsicType, TypeKind};
|
|
||||||
|
|
||||||
pub struct CsvMetadata {
|
|
||||||
notices: String,
|
|
||||||
spdx_lic: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CsvMetadata {
|
|
||||||
fn new<'a>(header: impl Iterator<Item = &'a str>) -> Self {
|
|
||||||
lazy_static! {
|
|
||||||
static ref SPDX_LICENSE_IDENTIFIER: Regex =
|
|
||||||
Regex::new(r#"SPDX-License-Identifier:(.*)"#).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let notices = header.map(|line| format!("{line}\n")).collect::<String>();
|
|
||||||
let spdx_lic = match SPDX_LICENSE_IDENTIFIER
|
|
||||||
.captures_iter(¬ices)
|
|
||||||
.exactly_one()
|
|
||||||
{
|
|
||||||
Ok(caps) => {
|
|
||||||
let cap = caps.get(1).unwrap().as_str().trim();
|
|
||||||
// Ensure that (unlikely) ACLE licence changes don't go unnoticed.
|
|
||||||
assert_eq!(cap, "Apache-2.0");
|
|
||||||
cap.to_string()
|
|
||||||
}
|
|
||||||
Err(caps_iter) => panic!(
|
|
||||||
"Expected exactly one SPDX-License-Identifier, found {}.",
|
|
||||||
caps_iter.count()
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
Self { notices, spdx_lic }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn spdx_license_identifier(&self) -> &str {
|
|
||||||
self.spdx_lic.as_str()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn notices_lines(&self) -> impl Iterator<Item = &str> {
|
|
||||||
self.notices.lines()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_acle_intrinsics(filename: &str) -> (CsvMetadata, Vec<Intrinsic>) {
|
|
||||||
let data = std::fs::read_to_string(filename).expect("Failed to open ACLE intrinsics file");
|
|
||||||
|
|
||||||
let comment_header = data.lines().map_while(|l| l.strip_prefix("<COMMENT>\t"));
|
|
||||||
let meta = CsvMetadata::new(comment_header);
|
|
||||||
|
|
||||||
let data = data
|
|
||||||
.lines()
|
|
||||||
.filter_map(|l| {
|
|
||||||
(!(l.starts_with("<COMMENT>") || l.is_empty() || l.starts_with("<SECTION>")))
|
|
||||||
.then(|| l.replace("<HEADER>\t", ""))
|
|
||||||
})
|
|
||||||
.join("\n");
|
|
||||||
|
|
||||||
let mut csv_reader = csv::ReaderBuilder::new()
|
|
||||||
.delimiter(b'\t')
|
|
||||||
.from_reader(data.as_bytes());
|
|
||||||
|
|
||||||
let mut intrinsics: Vec<Intrinsic> = csv_reader
|
|
||||||
.deserialize()
|
|
||||||
.filter_map(|x: Result<ACLEIntrinsicLine, _>| x.ok().map(|i| i.into()))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// Intrinsics such as vshll_n_s8 exist twice in the ACLE with different constraints.
|
|
||||||
intrinsics.sort_by(|a, b| a.name.cmp(&b.name));
|
|
||||||
let (intrinsics, duplicates) = intrinsics.partition_dedup_by(|a, b| a.name == b.name);
|
|
||||||
for duplicate in duplicates {
|
|
||||||
let name = &duplicate.name;
|
|
||||||
let constraints = duplicate
|
|
||||||
.arguments
|
|
||||||
.args
|
|
||||||
.drain(..)
|
|
||||||
.filter(|a| a.has_constraint());
|
|
||||||
let intrinsic = intrinsics.iter_mut().find(|i| &i.name == name).unwrap();
|
|
||||||
|
|
||||||
for mut constraint in constraints {
|
|
||||||
let real_constraint = intrinsic
|
|
||||||
.arguments
|
|
||||||
.args
|
|
||||||
.iter_mut()
|
|
||||||
.find(|a| a.name == constraint.name)
|
|
||||||
.unwrap();
|
|
||||||
real_constraint
|
|
||||||
.constraints
|
|
||||||
.push(constraint.constraints.pop().unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(meta, intrinsics.to_vec())
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<Intrinsic> for ACLEIntrinsicLine {
|
|
||||||
fn into(self) -> Intrinsic {
|
|
||||||
let signature = self.intrinsic;
|
|
||||||
let (ret_ty, remaining) = signature.split_once(' ').unwrap();
|
|
||||||
|
|
||||||
let results =
|
|
||||||
type_from_c(ret_ty).unwrap_or_else(|_| panic!("Failed to parse return type: {ret_ty}"));
|
|
||||||
|
|
||||||
let (name, args) = remaining.split_once('(').unwrap();
|
|
||||||
let args = args.trim_end_matches(')');
|
|
||||||
|
|
||||||
// Typo in ACLE data
|
|
||||||
let args = args.replace("int16x8q_t", "int16x8_t");
|
|
||||||
|
|
||||||
let arg_prep = self.argument_preparation.as_str();
|
|
||||||
let args = args
|
|
||||||
.split(',')
|
|
||||||
.enumerate()
|
|
||||||
.map(move |(idx, arg)| {
|
|
||||||
let arg = arg.trim();
|
|
||||||
if arg.starts_with("__builtin_constant_p") {
|
|
||||||
handle_constraint(idx, arg, arg_prep)
|
|
||||||
} else {
|
|
||||||
from_c(idx, arg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let arguments = ArgumentList { args };
|
|
||||||
let a64_only = match &*self.supported_architectures {
|
|
||||||
"A64" => true,
|
|
||||||
"v7/A32/A64" | "A32/A64" => false,
|
|
||||||
_ => panic!("Invalid supported architectures"),
|
|
||||||
};
|
|
||||||
|
|
||||||
Intrinsic {
|
|
||||||
name: name.to_string(),
|
|
||||||
arguments,
|
|
||||||
results,
|
|
||||||
a64_only,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_constraint(idx: usize, arg: &str, prep: &str) -> Argument {
|
|
||||||
let prep = prep.replace(' ', "");
|
|
||||||
|
|
||||||
let name = arg
|
|
||||||
.trim_start_matches("__builtin_constant_p")
|
|
||||||
.trim_start_matches(|ref c| c == &' ' || c == &'(')
|
|
||||||
.trim_end_matches(')')
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
let ty = IntrinsicType::Type {
|
|
||||||
constant: true,
|
|
||||||
kind: TypeKind::Int,
|
|
||||||
bit_len: Some(32),
|
|
||||||
simd_len: None,
|
|
||||||
vec_len: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let constraints = prep
|
|
||||||
.split(';')
|
|
||||||
.find_map(|p| handle_range_constraint(&name, p).or_else(|| handle_eq_constraint(&name, p)))
|
|
||||||
.map(|c| vec![c])
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
Argument {
|
|
||||||
pos: idx,
|
|
||||||
name,
|
|
||||||
ty,
|
|
||||||
constraints,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_range_constraint(name: &str, data: &str) -> Option<Constraint> {
|
|
||||||
lazy_static! {
|
|
||||||
static ref RANGE_CONSTRAINT: Regex =
|
|
||||||
Regex::new(r#"([0-9]+)<=([[:alnum:]]+)<=([0-9]+)"#).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let captures = RANGE_CONSTRAINT.captures(data)?;
|
|
||||||
if captures.get(2).map(|c| c.as_str() == name).unwrap_or(false) {
|
|
||||||
match (captures.get(1), captures.get(3)) {
|
|
||||||
(Some(start), Some(end)) => {
|
|
||||||
let start = start.as_str().parse::<i64>().unwrap();
|
|
||||||
let end = end.as_str().parse::<i64>().unwrap() + 1;
|
|
||||||
Some(Constraint::Range(start..end))
|
|
||||||
}
|
|
||||||
_ => panic!("Invalid constraint"),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_eq_constraint(name: &str, data: &str) -> Option<Constraint> {
|
|
||||||
lazy_static! {
|
|
||||||
static ref EQ_CONSTRAINT: Regex = Regex::new(r#"([[:alnum:]]+)==([0-9]+)"#).unwrap();
|
|
||||||
}
|
|
||||||
let captures = EQ_CONSTRAINT.captures(data)?;
|
|
||||||
if captures.get(1).map(|c| c.as_str() == name).unwrap_or(false) {
|
|
||||||
captures
|
|
||||||
.get(2)
|
|
||||||
.map(|c| Constraint::Equal(c.as_str().parse::<i64>().unwrap()))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_c(pos: usize, s: &str) -> Argument {
|
|
||||||
let name_index = s
|
|
||||||
.chars()
|
|
||||||
.rev()
|
|
||||||
.take_while(|c| c != &'*' && c != &' ')
|
|
||||||
.count();
|
|
||||||
|
|
||||||
let name_start = s.len() - name_index;
|
|
||||||
let name = s[name_start..].to_string();
|
|
||||||
let s = s[..name_start].trim();
|
|
||||||
|
|
||||||
Argument {
|
|
||||||
pos,
|
|
||||||
name,
|
|
||||||
ty: type_from_c(s).unwrap_or_else(|_| panic!("Failed to parse type: {s}")),
|
|
||||||
constraints: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn type_from_c(s: &str) -> Result<IntrinsicType, String> {
|
|
||||||
const CONST_STR: &str = "const ";
|
|
||||||
|
|
||||||
if let Some(s) = s.strip_suffix('*') {
|
|
||||||
let (s, constant) = if s.ends_with(CONST_STR) {
|
|
||||||
(&s[..s.len() - (CONST_STR.len() + 1)], true)
|
|
||||||
} else {
|
|
||||||
(s, false)
|
|
||||||
};
|
|
||||||
|
|
||||||
let s = s.trim_end();
|
|
||||||
|
|
||||||
Ok(IntrinsicType::Ptr {
|
|
||||||
constant,
|
|
||||||
child: Box::new(type_from_c(s)?),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// [const ]TYPE[{bitlen}[x{simdlen}[x{vec_len}]]][_t]
|
|
||||||
|
|
||||||
let (mut s, constant) = if let Some(s) = s.strip_prefix(CONST_STR) {
|
|
||||||
(s, true)
|
|
||||||
} else {
|
|
||||||
(s, false)
|
|
||||||
};
|
|
||||||
s = s.strip_suffix("_t").unwrap_or(s);
|
|
||||||
|
|
||||||
let mut parts = s.split('x'); // [[{bitlen}], [{simdlen}], [{vec_len}] ]
|
|
||||||
|
|
||||||
let start = parts.next().ok_or("Impossible to parse type")?;
|
|
||||||
|
|
||||||
if let Some(digit_start) = start.find(|c: char| c.is_ascii_digit()) {
|
|
||||||
let (arg_kind, bit_len) = start.split_at(digit_start);
|
|
||||||
|
|
||||||
let arg_kind = arg_kind.parse::<TypeKind>()?;
|
|
||||||
let bit_len = bit_len.parse::<u32>().map_err(|err| err.to_string())?;
|
|
||||||
|
|
||||||
let simd_len = parts.next().map(|part| part.parse::<u32>().ok()).flatten();
|
|
||||||
let vec_len = parts.next().map(|part| part.parse::<u32>().ok()).flatten();
|
|
||||||
|
|
||||||
Ok(IntrinsicType::Type {
|
|
||||||
constant,
|
|
||||||
kind: arg_kind,
|
|
||||||
bit_len: Some(bit_len),
|
|
||||||
simd_len,
|
|
||||||
vec_len,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Ok(IntrinsicType::Type {
|
|
||||||
constant,
|
|
||||||
kind: start.parse::<TypeKind>()?,
|
|
||||||
bit_len: None,
|
|
||||||
simd_len: None,
|
|
||||||
vec_len: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, PartialEq, Clone)]
|
|
||||||
struct ACLEIntrinsicLine {
|
|
||||||
#[serde(rename = "Intrinsic")]
|
|
||||||
intrinsic: String,
|
|
||||||
#[serde(rename = "Argument preparation")]
|
|
||||||
argument_preparation: String,
|
|
||||||
#[serde(rename = "AArch64 Instruction")]
|
|
||||||
aarch64_instruction: String,
|
|
||||||
#[serde(rename = "Result")]
|
|
||||||
result: String,
|
|
||||||
#[serde(rename = "Supported architectures")]
|
|
||||||
supported_architectures: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
use crate::argument::Argument;
|
|
||||||
use crate::types::{IntrinsicType, TypeKind};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parse_simd() {
|
|
||||||
let expected = Argument {
|
|
||||||
pos: 0,
|
|
||||||
name: "a".into(),
|
|
||||||
ty: IntrinsicType::Type {
|
|
||||||
constant: false,
|
|
||||||
kind: TypeKind::Int,
|
|
||||||
bit_len: Some(32),
|
|
||||||
simd_len: Some(4),
|
|
||||||
vec_len: None,
|
|
||||||
},
|
|
||||||
constraints: vec![],
|
|
||||||
};
|
|
||||||
let actual = from_c(0, "int32x4_t a");
|
|
||||||
assert_eq!(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parse_simd_with_vec() {
|
|
||||||
let expected = Argument {
|
|
||||||
pos: 0,
|
|
||||||
name: "a".into(),
|
|
||||||
ty: IntrinsicType::Type {
|
|
||||||
constant: false,
|
|
||||||
kind: TypeKind::Int,
|
|
||||||
bit_len: Some(32),
|
|
||||||
simd_len: Some(4),
|
|
||||||
vec_len: Some(2),
|
|
||||||
},
|
|
||||||
constraints: vec![],
|
|
||||||
};
|
|
||||||
let actual = from_c(0, "int32x4x2_t a");
|
|
||||||
assert_eq!(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ptr() {
|
|
||||||
let expected = Argument {
|
|
||||||
pos: 0,
|
|
||||||
name: "ptr".into(),
|
|
||||||
ty: crate::types::IntrinsicType::Ptr {
|
|
||||||
constant: true,
|
|
||||||
child: Box::new(IntrinsicType::Type {
|
|
||||||
constant: false,
|
|
||||||
kind: TypeKind::Int,
|
|
||||||
bit_len: Some(8),
|
|
||||||
simd_len: None,
|
|
||||||
vec_len: None,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
constraints: vec![],
|
|
||||||
};
|
|
||||||
let actual = from_c(0, "int8_t const *ptr");
|
|
||||||
assert_eq!(expected, actual);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use crate::json_parser::ArgPrep;
|
||||||
use crate::types::{IntrinsicType, TypeKind};
|
use crate::types::{IntrinsicType, TypeKind};
|
||||||
use crate::Language;
|
use crate::Language;
|
||||||
|
|
||||||
@@ -22,6 +23,26 @@ pub enum Constraint {
|
|||||||
Range(Range<i64>),
|
Range(Range<i64>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<ArgPrep> for Constraint {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(prep: ArgPrep) -> Result<Self, Self::Error> {
|
||||||
|
let parsed_ints = match prep {
|
||||||
|
ArgPrep::Immediate { min, max } => Ok((min, max)),
|
||||||
|
_ => Err(()),
|
||||||
|
};
|
||||||
|
if let Ok((min, max)) = parsed_ints {
|
||||||
|
if min == max {
|
||||||
|
Ok(Constraint::Equal(min))
|
||||||
|
} else {
|
||||||
|
Ok(Constraint::Range(min..max + 1))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Constraint {
|
impl Constraint {
|
||||||
pub fn to_range(&self) -> Range<i64> {
|
pub fn to_range(&self) -> Range<i64> {
|
||||||
match self {
|
match self {
|
||||||
@@ -47,6 +68,30 @@ impl Argument {
|
|||||||
pub fn has_constraint(&self) -> bool {
|
pub fn has_constraint(&self) -> bool {
|
||||||
!self.constraints.is_empty()
|
!self.constraints.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn type_and_name_from_c(arg: &str) -> (&str, &str) {
|
||||||
|
let split_index = arg
|
||||||
|
.rfind([' ', '*'])
|
||||||
|
.expect("Couldn't split type and argname");
|
||||||
|
|
||||||
|
(arg[..split_index + 1].trim_end(), &arg[split_index + 1..])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_c(pos: usize, arg: &str, arg_prep: Option<ArgPrep>) -> Argument {
|
||||||
|
let (ty, var_name) = Self::type_and_name_from_c(arg);
|
||||||
|
|
||||||
|
let ty = IntrinsicType::from_c(ty)
|
||||||
|
.unwrap_or_else(|_| panic!("Failed to parse argument '{arg}'"));
|
||||||
|
|
||||||
|
let constraint = arg_prep.and_then(|a| a.try_into().ok());
|
||||||
|
|
||||||
|
Argument {
|
||||||
|
pos,
|
||||||
|
name: String::from(var_name),
|
||||||
|
ty,
|
||||||
|
constraints: constraint.map_or(vec![], |r| vec![r]),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
|||||||
98
library/stdarch/crates/intrinsic-test/src/json_parser.rs
Normal file
98
library/stdarch/crates/intrinsic-test/src/json_parser.rs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::argument::{Argument, ArgumentList};
|
||||||
|
use crate::intrinsic::Intrinsic;
|
||||||
|
use crate::types::IntrinsicType;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
struct ReturnType {
|
||||||
|
value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(untagged, deny_unknown_fields)]
|
||||||
|
pub enum ArgPrep {
|
||||||
|
Register {
|
||||||
|
#[serde(rename = "register")]
|
||||||
|
reg: String,
|
||||||
|
},
|
||||||
|
Immediate {
|
||||||
|
#[serde(rename = "minimum")]
|
||||||
|
min: i64,
|
||||||
|
#[serde(rename = "maximum")]
|
||||||
|
max: i64,
|
||||||
|
},
|
||||||
|
Nothing {},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
struct JsonIntrinsic {
|
||||||
|
#[serde(rename = "SIMD_ISA")]
|
||||||
|
simd_isa: String,
|
||||||
|
name: String,
|
||||||
|
arguments: Vec<String>,
|
||||||
|
return_type: ReturnType,
|
||||||
|
#[serde(rename = "Arguments_Preparation")]
|
||||||
|
args_prep: Option<HashMap<String, ArgPrep>>,
|
||||||
|
#[serde(rename = "Architectures")]
|
||||||
|
architectures: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_neon_intrinsics(filename: &str) -> Result<Vec<Intrinsic>, Box<dyn std::error::Error>> {
|
||||||
|
let file = std::fs::File::open(filename)?;
|
||||||
|
let reader = std::io::BufReader::new(file);
|
||||||
|
let json: Vec<JsonIntrinsic> = serde_json::from_reader(reader).expect("Couldn't parse JSON");
|
||||||
|
|
||||||
|
let parsed = json
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|intr| {
|
||||||
|
if intr.simd_isa == "Neon" {
|
||||||
|
Some(json_to_intrinsic(intr).expect("Couldn't parse JSON"))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Ok(parsed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json_to_intrinsic(mut intr: JsonIntrinsic) -> Result<Intrinsic, Box<dyn std::error::Error>> {
|
||||||
|
let name = intr.name.replace(['[', ']'], "");
|
||||||
|
|
||||||
|
let results = IntrinsicType::from_c(&intr.return_type.value)?;
|
||||||
|
|
||||||
|
let mut args_prep = intr.args_prep.as_mut();
|
||||||
|
let args = intr
|
||||||
|
.arguments
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, arg)| {
|
||||||
|
let arg_name = Argument::type_and_name_from_c(&arg).1;
|
||||||
|
let arg_prep = args_prep.as_mut().and_then(|a| a.remove(arg_name));
|
||||||
|
let mut arg = Argument::from_c(i, &arg, arg_prep);
|
||||||
|
// The JSON doesn't list immediates as const
|
||||||
|
if let IntrinsicType::Type {
|
||||||
|
ref mut constant, ..
|
||||||
|
} = arg.ty
|
||||||
|
{
|
||||||
|
if arg.name.starts_with("imm") {
|
||||||
|
*constant = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arg
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let arguments = ArgumentList { args };
|
||||||
|
|
||||||
|
Ok(Intrinsic {
|
||||||
|
name,
|
||||||
|
arguments,
|
||||||
|
results,
|
||||||
|
a64_only: intr.architectures == vec!["A64".to_string()],
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
#![feature(slice_partition_dedup)]
|
#![feature(slice_partition_dedup)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@@ -14,12 +12,12 @@ use itertools::Itertools;
|
|||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use types::TypeKind;
|
use types::TypeKind;
|
||||||
|
|
||||||
use crate::acle_csv_parser::{get_acle_intrinsics, CsvMetadata};
|
|
||||||
use crate::argument::Argument;
|
use crate::argument::Argument;
|
||||||
|
use crate::json_parser::get_neon_intrinsics;
|
||||||
|
|
||||||
mod acle_csv_parser;
|
|
||||||
mod argument;
|
mod argument;
|
||||||
mod intrinsic;
|
mod intrinsic;
|
||||||
|
mod json_parser;
|
||||||
mod types;
|
mod types;
|
||||||
mod values;
|
mod values;
|
||||||
|
|
||||||
@@ -191,7 +189,8 @@ fn compile_c(c_filename: &str, intrinsic: &Intrinsic, compiler: &str, a32: bool)
|
|||||||
let output = Command::new("sh")
|
let output = Command::new("sh")
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(format!(
|
.arg(format!(
|
||||||
"{cpp} {cppflags} {arch_flags} -Wno-narrowing -O2 -target {target} -o c_programs/{intrinsic} {filename}",
|
// -ffp-contract=off emulates Rust's approach of not fusing separate mul-add operations
|
||||||
|
"{cpp} {cppflags} {arch_flags} -ffp-contract=off -Wno-narrowing -O2 -target {target} -o c_programs/{intrinsic} {filename}",
|
||||||
target = if a32 { "armv7-unknown-linux-gnueabihf" } else { "aarch64-unknown-linux-gnu" },
|
target = if a32 { "armv7-unknown-linux-gnueabihf" } else { "aarch64-unknown-linux-gnu" },
|
||||||
arch_flags = if a32 { "-march=armv8.6-a+crypto+crc+dotprod" } else { "-march=armv8.6-a+crypto+sha3+crc+dotprod" },
|
arch_flags = if a32 { "-march=armv8.6-a+crypto+crc+dotprod" } else { "-march=armv8.6-a+crypto+sha3+crc+dotprod" },
|
||||||
filename = c_filename,
|
filename = c_filename,
|
||||||
@@ -218,20 +217,14 @@ fn compile_c(c_filename: &str, intrinsic: &Intrinsic, compiler: &str, a32: bool)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_notices(csv_metadata: &CsvMetadata, line_prefix: &str) -> String {
|
fn build_notices(line_prefix: &str) -> String {
|
||||||
let mut notices = format!(
|
format!(
|
||||||
"\
|
"\
|
||||||
{line_prefix}This is a transient test file, not intended for distribution. Some aspects of the
|
{line_prefix}This is a transient test file, not intended for distribution. Some aspects of the
|
||||||
{line_prefix}test are derived from a CSV specification, published with the following notices:
|
{line_prefix}test are derived from a JSON specification, published under the same license as the
|
||||||
{line_prefix}
|
{line_prefix}`intrinsic-test` crate.\n
|
||||||
"
|
"
|
||||||
);
|
)
|
||||||
let lines = csv_metadata
|
|
||||||
.notices_lines()
|
|
||||||
.map(|line| format!("{line_prefix} {line}\n"));
|
|
||||||
notices.extend(lines);
|
|
||||||
notices.push_str("\n");
|
|
||||||
notices
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_c(notices: &str, intrinsics: &Vec<Intrinsic>, compiler: &str, a32: bool) -> bool {
|
fn build_c(notices: &str, intrinsics: &Vec<Intrinsic>, compiler: &str, a32: bool) -> bool {
|
||||||
@@ -250,13 +243,7 @@ fn build_c(notices: &str, intrinsics: &Vec<Intrinsic>, compiler: &str, a32: bool
|
|||||||
.is_none()
|
.is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_rust(
|
fn build_rust(notices: &str, intrinsics: &[Intrinsic], toolchain: &str, a32: bool) -> bool {
|
||||||
notices: &str,
|
|
||||||
spdx_lic: &str,
|
|
||||||
intrinsics: &Vec<Intrinsic>,
|
|
||||||
toolchain: &str,
|
|
||||||
a32: bool,
|
|
||||||
) -> bool {
|
|
||||||
intrinsics.iter().for_each(|i| {
|
intrinsics.iter().for_each(|i| {
|
||||||
let rust_dir = format!(r#"rust_programs/{}"#, i.name);
|
let rust_dir = format!(r#"rust_programs/{}"#, i.name);
|
||||||
let _ = std::fs::create_dir_all(&rust_dir);
|
let _ = std::fs::create_dir_all(&rust_dir);
|
||||||
@@ -275,7 +262,7 @@ fn build_rust(
|
|||||||
name = "intrinsic-test-programs"
|
name = "intrinsic-test-programs"
|
||||||
version = "{version}"
|
version = "{version}"
|
||||||
authors = ["{authors}"]
|
authors = ["{authors}"]
|
||||||
license = "{spdx_lic}"
|
license = "{license}"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
[workspace]
|
[workspace]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@@ -283,6 +270,7 @@ core_arch = {{ path = "../crates/core_arch" }}
|
|||||||
{binaries}"#,
|
{binaries}"#,
|
||||||
version = env!("CARGO_PKG_VERSION"),
|
version = env!("CARGO_PKG_VERSION"),
|
||||||
authors = env!("CARGO_PKG_AUTHORS"),
|
authors = env!("CARGO_PKG_AUTHORS"),
|
||||||
|
license = env!("CARGO_PKG_LICENSE"),
|
||||||
binaries = intrinsics
|
binaries = intrinsics
|
||||||
.iter()
|
.iter()
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
@@ -394,8 +382,9 @@ fn main() {
|
|||||||
Default::default()
|
Default::default()
|
||||||
};
|
};
|
||||||
let a32 = matches.is_present("A32");
|
let a32 = matches.is_present("A32");
|
||||||
|
let mut intrinsics = get_neon_intrinsics(filename).expect("Error parsing input file");
|
||||||
|
|
||||||
let (csv_metadata, intrinsics) = get_acle_intrinsics(filename);
|
intrinsics.sort_by(|a, b| a.name.cmp(&b.name));
|
||||||
|
|
||||||
let mut intrinsics = intrinsics
|
let mut intrinsics = intrinsics
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -418,14 +407,13 @@ fn main() {
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
intrinsics.dedup();
|
intrinsics.dedup();
|
||||||
|
|
||||||
let notices = build_notices(&csv_metadata, "// ");
|
let notices = build_notices("// ");
|
||||||
let spdx_lic = csv_metadata.spdx_license_identifier();
|
|
||||||
|
|
||||||
if !build_c(¬ices, &intrinsics, cpp_compiler, a32) {
|
if !build_c(¬ices, &intrinsics, cpp_compiler, a32) {
|
||||||
std::process::exit(2);
|
std::process::exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !build_rust(¬ices, spdx_lic, &intrinsics, &toolchain, a32) {
|
if !build_rust(¬ices, &intrinsics, &toolchain, a32) {
|
||||||
std::process::exit(3);
|
std::process::exit(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,11 +110,11 @@ impl IntrinsicType {
|
|||||||
/// pointers, i.e. a pointer to a u16 would be 16 rather than the size
|
/// pointers, i.e. a pointer to a u16 would be 16 rather than the size
|
||||||
/// of a pointer.
|
/// of a pointer.
|
||||||
pub fn inner_size(&self) -> u32 {
|
pub fn inner_size(&self) -> u32 {
|
||||||
match *self {
|
match self {
|
||||||
IntrinsicType::Ptr { ref child, .. } => child.inner_size(),
|
IntrinsicType::Ptr { child, .. } => child.inner_size(),
|
||||||
IntrinsicType::Type {
|
IntrinsicType::Type {
|
||||||
bit_len: Some(bl), ..
|
bit_len: Some(bl), ..
|
||||||
} => bl,
|
} => *bl,
|
||||||
_ => unreachable!(""),
|
_ => unreachable!(""),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -433,4 +433,67 @@ impl IntrinsicType {
|
|||||||
_ => todo!("get_lane_function IntrinsicType: {:#?}", self),
|
_ => todo!("get_lane_function IntrinsicType: {:#?}", self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_c(s: &str) -> Result<IntrinsicType, String> {
|
||||||
|
const CONST_STR: &str = "const";
|
||||||
|
if let Some(s) = s.strip_suffix('*') {
|
||||||
|
let (s, constant) = match s.trim().strip_suffix(CONST_STR) {
|
||||||
|
Some(stripped) => (stripped, true),
|
||||||
|
None => (s, false),
|
||||||
|
};
|
||||||
|
let s = s.trim_end();
|
||||||
|
Ok(IntrinsicType::Ptr {
|
||||||
|
constant,
|
||||||
|
child: Box::new(IntrinsicType::from_c(s)?),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// [const ]TYPE[{bitlen}[x{simdlen}[x{vec_len}]]][_t]
|
||||||
|
let (mut s, constant) = match s.strip_prefix(CONST_STR) {
|
||||||
|
Some(stripped) => (stripped.trim(), true),
|
||||||
|
None => (s, false),
|
||||||
|
};
|
||||||
|
s = s.strip_suffix("_t").unwrap_or(s);
|
||||||
|
let mut parts = s.split('x'); // [[{bitlen}], [{simdlen}], [{vec_len}] ]
|
||||||
|
let start = parts.next().ok_or("Impossible to parse type")?;
|
||||||
|
if let Some(digit_start) = start.find(|c: char| c.is_ascii_digit()) {
|
||||||
|
let (arg_kind, bit_len) = start.split_at(digit_start);
|
||||||
|
let arg_kind = arg_kind.parse::<TypeKind>()?;
|
||||||
|
let bit_len = bit_len.parse::<u32>().map_err(|err| err.to_string())?;
|
||||||
|
let simd_len = match parts.next() {
|
||||||
|
Some(part) => Some(
|
||||||
|
part.parse::<u32>()
|
||||||
|
.map_err(|_| "Couldn't parse simd_len: {part}")?,
|
||||||
|
),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
let vec_len = match parts.next() {
|
||||||
|
Some(part) => Some(
|
||||||
|
part.parse::<u32>()
|
||||||
|
.map_err(|_| "Couldn't parse vec_len: {part}")?,
|
||||||
|
),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
Ok(IntrinsicType::Type {
|
||||||
|
constant,
|
||||||
|
kind: arg_kind,
|
||||||
|
bit_len: Some(bit_len),
|
||||||
|
simd_len,
|
||||||
|
vec_len,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let kind = start.parse::<TypeKind>()?;
|
||||||
|
let bit_len = match kind {
|
||||||
|
TypeKind::Int => Some(32),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
Ok(IntrinsicType::Type {
|
||||||
|
constant,
|
||||||
|
kind: start.parse::<TypeKind>()?,
|
||||||
|
bit_len,
|
||||||
|
simd_len: None,
|
||||||
|
vec_len: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
87470
library/stdarch/intrinsics_data/arm_intrinsics.json
Normal file
87470
library/stdarch/intrinsics_data/arm_intrinsics.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user