diff --git a/clang/include/clang/Basic/BuiltinsRISCVVector.def b/clang/include/clang/Basic/BuiltinsRISCVVector.def --- a/clang/include/clang/Basic/BuiltinsRISCVVector.def +++ b/clang/include/clang/Basic/BuiltinsRISCVVector.def @@ -16,6 +16,7 @@ #endif #include "clang/Basic/riscv_vector_builtins.inc" +#include "clang/Basic/riscv_sifive_vcix_builtins.inc" #undef BUILTIN #undef TARGET_BUILTIN diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt --- a/clang/include/clang/Basic/CMakeLists.txt +++ b/clang/include/clang/Basic/CMakeLists.txt @@ -93,3 +93,12 @@ clang_tablegen(riscv_vector_builtin_sema.inc -gen-riscv-vector-builtin-sema SOURCE riscv_vector.td TARGET ClangRISCVVectorBuiltinSema) +clang_tablegen(riscv_sifive_vcix_builtins.inc -gen-riscv-sifive-vcix-builtins + SOURCE riscv_sifive_vcix.td + TARGET ClangRISCVSiFiveVCIXBuiltins) +clang_tablegen(riscv_sifive_vcix_builtin_cg.inc -gen-riscv-sifive-vcix-builtin-codegen + SOURCE riscv_sifive_vcix.td + TARGET ClangRISCVSiFiveVCIXBuiltinCG) +clang_tablegen(riscv_sifive_vcix_builtin_sema.inc -gen-riscv-sifive-vcix-builtin-sema + SOURCE riscv_sifive_vcix.td + TARGET ClangRISCVSiFiveVCIXBuiltinSema) diff --git a/clang/include/clang/Basic/riscv_sifive_vcix.td b/clang/include/clang/Basic/riscv_sifive_vcix.td new file mode 100644 --- /dev/null +++ b/clang/include/clang/Basic/riscv_sifive_vcix.td @@ -0,0 +1,107 @@ +//==--- riscv_sifive_vcix.td - RISC-V SiFive VCIX function list -----------===// +// +// Part of the LLVM Project, 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the builtins for RISC-V SiFive VCIX. See: +// +// https://sifive.cdn.prismic.io/sifive/c3829e36-8552-41f0-a841-79945784241b_vcix-spec-software.pdf +// +//===----------------------------------------------------------------------===// + +include "riscv_vector_common.td" + +//===----------------------------------------------------------------------===// +// Instruction definitions +//===----------------------------------------------------------------------===// + +class VCIXSuffix { + list suffix = !cond(!eq(range, "c"): ["8mf8", "8mf4", "8mf2", "8m1", "8m2", "8m4", "8m8"], + !eq(range, "s"): ["16mf4", "16mf2", "16m1", "16m2", "16m4", "16m8"], + !eq(range, "i"): ["32mf2", "32m1", "32m2", "32m4", "32m8"], + !eq(range, "l"): ["64m1", "64m2", "64m4", "64m8"]); +} + +class VCIXBuiltinSet intrinsic_types> + : RVVBuiltin { + let Name = name; + let OverloadedName = name; + let IRName = IR_name; + let HasMasked = false; + let IntrinsicTypes = intrinsic_types; +} + +multiclass VCIXBuiltinSet intrinsic_types> { + if !find(prototype, "0") then { + def : VCIXBuiltinSet; + } + def : VCIXBuiltinSet; +} + +multiclass RVVVCIXBuiltinSet range, string prototype, + list intrinsic_types, bit EncodeVtype, + bit UseGPR> { + defvar suffix = !if(EncodeVtype, "", "Uv"); + foreach r = range in { + let RequiredFeatures = !if(!and(UseGPR, !eq(r, "l")), + ["Xsfvcp", "RV64"], ["Xsfvcp"]) in { + // If EncodeVtype is true, then these intrinsic don't have any vector + // types in the output and inputs, but we still need to add vetvli for + // them. So we encode different VTYPE into the intrinsic names, and + // then will know which vsetvli is correct. + if EncodeVtype then { + foreach s = VCIXSuffix.suffix in { + defvar name = NAME # "_u" # s; + defvar IR_name = NAME # "_e" # s; + // Since we already encode the Vtype into the name, so just set + // Log2LMUL to zero. Otherwise the RISCVVEmitter will expand + // lots of redundant intrinsic but have same names. + let Log2LMUL = [0] in + def : VCIXBuiltinSet; + } + } else { + defm : VCIXBuiltinSet; + } + } + } +} + +let SupportOverloading = false in { + defm sf_vc_x_se : RVVVCIXBuiltinSet<["c", "s", "i", "l"], "0KzKzKzUe", [0, 3], /*EncodeVtype*/1, /*UseGPR*/1>; + defm sf_vc_i_se : RVVVCIXBuiltinSet<["c", "s", "i", "l"], "0KzKzKzKz", [2, 3], /*EncodeVtype*/1, /*UseGPR*/0>; + defm sf_vc_xv : RVVVCIXBuiltinSet<["csi", "l"], "0KzKzUvUe", [0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/1>; + defm sf_vc_iv : RVVVCIXBuiltinSet<["csi", "l"], "0KzKzUvKz", [0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_vv : RVVVCIXBuiltinSet<["csi", "l"], "0KzKzUvUv", [0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_fv : RVVVCIXBuiltinSet<["si", "l"], "0KzKzUvFe", [0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_xvv : RVVVCIXBuiltinSet<["csi", "l"], "0KzUvUvUe", [0, 1, 3], /*EncodeVtype*/0, /*UseGPR*/1>; + defm sf_vc_ivv : RVVVCIXBuiltinSet<["csi", "l"], "0KzUvUvKz", [0, 1, 3], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_vvv : RVVVCIXBuiltinSet<["csi", "l"], "0KzUvUvUv", [0, 1, 3], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_fvv : RVVVCIXBuiltinSet<["si", "l"], "0KzUvUvFe", [0, 1, 3], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_v_x : RVVVCIXBuiltinSet<["csi", "l"], "UvKzKzUe", [-1, 1, 2], /*EncodeVtype*/0, /*UseGPR*/1>; + defm sf_vc_v_i : RVVVCIXBuiltinSet<["csi", "l"], "UvKzKzKz", [-1, 1, 2], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_v_xv : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvUe", [-1, 0, 2], /*EncodeVtype*/0, /*UseGPR*/1>; + defm sf_vc_v_iv : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvKz", [-1, 0, 2], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_v_vv : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvUv", [-1, 0, 2], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_v_fv : RVVVCIXBuiltinSet<["si", "l"], "UvKzUvFe", [-1, 0, 2], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_v_xvv : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvUvUe", [-1, 0, 3], /*EncodeVtype*/0, /*UseGPR*/1>; + defm sf_vc_v_ivv : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvUvKz", [-1, 0, 3], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_v_vvv : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvUvUv", [-1, 0, 3], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_v_fvv : RVVVCIXBuiltinSet<["si", "l"], "UvKzUvUvFe", [-1, 0, 3], /*EncodeVtype*/0, /*UseGPR*/0>; + let Log2LMUL = [-3, -2, -1, 0, 1, 2] in { + defm sf_vc_xvw : RVVVCIXBuiltinSet<["csi"], "0KzUwUvUe", [0, 1, 2, 3], /*EncodeVtype*/0, /*UseGPR*/1>; + defm sf_vc_ivw : RVVVCIXBuiltinSet<["csi"], "0KzUwUvKz", [0, 1, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_vvw : RVVVCIXBuiltinSet<["csi"], "0KzUwUvUv", [0, 1, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_fvw : RVVVCIXBuiltinSet<["si"], "0KzUwUvFe", [0, 1, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_v_xvw : RVVVCIXBuiltinSet<["csi"], "UwKzUwUvUe", [-1, 0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/1>; + defm sf_vc_v_ivw : RVVVCIXBuiltinSet<["csi"], "UwKzUwUvKz", [-1, 0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_v_vvw : RVVVCIXBuiltinSet<["csi"], "UwKzUwUvUv", [-1, 0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; + defm sf_vc_v_fvw : RVVVCIXBuiltinSet<["si"], "UwKzUwUvFe", [-1, 0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; + } +} diff --git a/clang/include/clang/Basic/riscv_vector.td b/clang/include/clang/Basic/riscv_vector.td --- a/clang/include/clang/Basic/riscv_vector.td +++ b/clang/include/clang/Basic/riscv_vector.td @@ -12,233 +12,7 @@ // //===----------------------------------------------------------------------===// -//===----------------------------------------------------------------------===// -// Instruction definitions -//===----------------------------------------------------------------------===// -// Each record of the class RVVBuiltin defines a collection of builtins (i.e. -// "def vadd : RVVBuiltin" will be used to define things like "vadd_vv_i32m1", -// "vadd_vv_i32m2", etc). -// -// The elements of this collection are defined by an instantiation process the -// range of which is specified by the cross product of the LMUL attribute and -// every element in the attribute TypeRange. By default builtins have LMUL = [1, -// 2, 4, 8, 1/2, 1/4, 1/8] so the process is repeated 7 times. In tablegen we -// use the Log2LMUL [0, 1, 2, 3, -1, -2, -3] to represent the LMUL. -// -// LMUL represents the fact that the types of values used by that builtin are -// values generated by instructions that are executed under that LMUL. However, -// this does not mean the builtin is necessarily lowered into an instruction -// that executes under the specified LMUL. An example where this happens are -// loads and stores of masks. A mask like `vbool8_t` can be generated, for -// instance, by comparing two `__rvv_int8m1_t` (this is LMUL=1) or comparing two -// `__rvv_int16m2_t` (this is LMUL=2). The actual load or store, however, will -// be performed under LMUL=1 because mask registers are not grouped. -// -// TypeRange is a non-empty sequence of basic types: -// -// c: int8_t (i8) -// s: int16_t (i16) -// i: int32_t (i32) -// l: int64_t (i64) -// x: float16_t (half) -// f: float32_t (float) -// d: float64_t (double) -// -// This way, given an LMUL, a record with a TypeRange "sil" will cause the -// definition of 3 builtins. Each type "t" in the TypeRange (in this example -// they are int16_t, int32_t, int64_t) is used as a parameter that drives the -// definition of that particular builtin (for the given LMUL). -// -// During the instantiation, types can be transformed or modified using type -// transformers. Given a type "t" the following primitive type transformers can -// be applied to it to yield another type. -// -// e: type of "t" as is (identity) -// v: computes a vector type whose element type is "t" for the current LMUL -// w: computes a vector type identical to what 'v' computes except for the -// element type which is twice as wide as the element type of 'v' -// q: computes a vector type identical to what 'v' computes except for the -// element type which is four times as wide as the element type of 'v' -// o: computes a vector type identical to what 'v' computes except for the -// element type which is eight times as wide as the element type of 'v' -// m: computes a vector type identical to what 'v' computes except for the -// element type which is bool -// 0: void type, ignores "t" -// z: size_t, ignores "t" -// t: ptrdiff_t, ignores "t" -// u: unsigned long, ignores "t" -// l: long, ignores "t" -// -// So for instance if t is "i", i.e. int, then "e" will yield int again. "v" -// will yield an RVV vector type (assume LMUL=1), so __rvv_int32m1_t. -// Accordingly "w" would yield __rvv_int64m2_t. -// -// A type transformer can be prefixed by other non-primitive type transformers. -// -// P: constructs a pointer to the current type -// C: adds const to the type -// K: requires the integer type to be a constant expression -// U: given an integer type or vector type, computes its unsigned variant -// I: given a vector type, compute the vector type with integer type -// elements of the same width -// F: given a vector type, compute the vector type with floating-point type -// elements of the same width -// S: given a vector type, computes its equivalent one for LMUL=1. This is a -// no-op if the vector was already LMUL=1 -// (Log2EEW:Value): Log2EEW value could be 3/4/5/6 (8/16/32/64), given a -// vector type (SEW and LMUL) and EEW (8/16/32/64), computes its -// equivalent integer vector type with EEW and corresponding ELMUL (elmul = -// (eew/sew) * lmul). For example, vector type is __rvv_float16m4 -// (SEW=16, LMUL=4) and Log2EEW is 3 (EEW=8), and then equivalent vector -// type is __rvv_uint8m2_t (elmul=(8/16)*4 = 2). Ignore to define a new -// builtins if its equivalent type has illegal lmul. -// (FixedSEW:Value): Given a vector type (SEW and LMUL), and computes another -// vector type which only changed SEW as given value. Ignore to define a new -// builtin if its equivalent type has illegal lmul or the SEW does not changed. -// (SFixedLog2LMUL:Value): Smaller Fixed Log2LMUL. Given a vector type (SEW -// and LMUL), and computes another vector type which only changed LMUL as -// given value. The new LMUL should be smaller than the old one. Ignore to -// define a new builtin if its equivalent type has illegal lmul. -// (LFixedLog2LMUL:Value): Larger Fixed Log2LMUL. Given a vector type (SEW -// and LMUL), and computes another vector type which only changed LMUL as -// given value. The new LMUL should be larger than the old one. Ignore to -// define a new builtin if its equivalent type has illegal lmul. -// -// Following with the example above, if t is "i", then "Ue" will yield unsigned -// int and "Fv" will yield __rvv_float32m1_t (again assuming LMUL=1), Fw would -// yield __rvv_float64m2_t, etc. -// -// Each builtin is then defined by applying each type in TypeRange against the -// sequence of type transformers described in Suffix and Prototype. -// -// The name of the builtin is defined by the Name attribute (which defaults to -// the name of the class) appended (separated with an underscore) the Suffix -// attribute. For instance with Name="foo", Suffix = "v" and TypeRange = "il", -// the builtin generated will be __builtin_rvv_foo_i32m1 and -// __builtin_rvv_foo_i64m1 (under LMUL=1). If Suffix contains more than one -// type transformer (say "vv") each of the types is separated with an -// underscore as in "__builtin_rvv_foo_i32m1_i32m1". -// -// The C/C++ prototype of the builtin is defined by the Prototype attribute. -// Prototype is a non-empty sequence of type transformers, the first of which -// is the return type of the builtin and the rest are the parameters of the -// builtin, in order. For instance if Prototype is "wvv" and TypeRange is "si" -// a first builtin will have type -// __rvv_int32m2_t (__rvv_int16m1_t, __rvv_int16m1_t) and the second builtin -// will have type __rvv_int64m2_t (__rvv_int32m1_t, __rvv_int32m1_t) (again -// under LMUL=1). -// -// There are a number of attributes that are used to constraint the number and -// shape of the builtins generated. Refer to the comments below for them. - -class PolicyScheme{ - int Value = val; -} -def NonePolicy : PolicyScheme<0>; -def HasPassthruOperand : PolicyScheme<1>; -def HasPolicyOperand : PolicyScheme<2>; - -class RVVBuiltin { - // Base name that will be prepended in __builtin_rvv_ and appended the - // computed Suffix. - string Name = NAME; - - // If not empty, each instantiated builtin will have this appended after an - // underscore (_). It is instantiated like Prototype. - string Suffix = suffix; - - // If empty, default OverloadedName is sub string of `Name` which end of first - // '_'. For example, the default overloaded name is `vadd` for Name `vadd_vv`. - // It's used for describe some special naming cases. - string OverloadedName = ""; - - // If not empty, each OverloadedName will have this appended after an - // underscore (_). It is instantiated like Prototype. - string OverloadedSuffix = overloaded_suffix; - - // The different variants of the builtin, parameterised with a type. - string TypeRange = type_range; - - // We use each type described in TypeRange and LMUL with prototype to - // instantiate a specific element of the set of builtins being defined. - // Prototype attribute defines the C/C++ prototype of the builtin. It is a - // non-empty sequence of type transformers, the first of which is the return - // type of the builtin and the rest are the parameters of the builtin, in - // order. For instance if Prototype is "wvv", TypeRange is "si" and LMUL=1, a - // first builtin will have type - // __rvv_int32m2_t (__rvv_int16m1_t, __rvv_int16m1_t), and the second builtin - // will have type __rvv_int64m2_t (__rvv_int32m1_t, __rvv_int32m1_t). - string Prototype = prototype; - - // This builtin has a masked form. - bit HasMasked = true; - - // If HasMasked, this flag states that this builtin has a maskedoff operand. It - // is always the first operand in builtin and IR intrinsic. - bit HasMaskedOffOperand = true; - - // This builtin has a granted vector length parameter. - bit HasVL = true; - - // The policy scheme for masked intrinsic IR. - // It could be NonePolicy or HasPolicyOperand. - // HasPolicyOperand: Has a policy operand. 0 is tail and mask undisturbed, 1 is - // tail agnostic, 2 is mask undisturbed, and 3 is tail and mask agnostic. The - // policy operand is located at the last position. - PolicyScheme MaskedPolicyScheme = HasPolicyOperand; - - // The policy scheme for unmasked intrinsic IR. - // It could be NonePolicy, HasPassthruOperand or HasPolicyOperand. - // HasPassthruOperand: Has a passthru operand to decide tail policy. If it is - // poison, tail policy is tail agnostic, otherwise policy is tail undisturbed. - // HasPolicyOperand: Has a policy operand. 1 is tail agnostic and 0 is tail - // undisturbed. - PolicyScheme UnMaskedPolicyScheme = NonePolicy; - - // This builtin support tail agnostic and undisturbed policy. - bit HasTailPolicy = true; - // This builtin support mask agnostic and undisturbed policy. - bit HasMaskPolicy = true; - - // This builtin prototype with TA or TAMA policy could not support overloading - // API. Other policy intrinsic functions would support overloading API with - // suffix `_tu`, `tumu`, `tuma`, `tamu` and `tama`. - bit SupportOverloading = true; - - // This builtin is valid for the given Log2LMULs. - list Log2LMUL = [0, 1, 2, 3, -1, -2, -3]; - - // Manual code in clang codegen riscv_vector_builtin_cg.inc - code ManualCodegen = [{}]; - - // When emit the automatic clang codegen, it describes what types we have to use - // to obtain the specific LLVM intrinsic. -1 means the return type, otherwise, - // k >= 0 meaning the k-th operand (counting from zero) of the codegen'd - // parameter of the unmasked version. k can't be the mask operand's position. - list IntrinsicTypes = []; - - // If these names are not empty, this is the ID of the LLVM intrinsic - // we want to lower to. - string IRName = NAME; - - // If HasMasked, this is the ID of the LLVM intrinsic we want to lower to. - string MaskedIRName = NAME #"_mask"; - - // Use clang_builtin_alias to save the number of builtins. - bit HasBuiltinAlias = true; - - // Features required to enable for this builtin. - list RequiredFeatures = []; - - // Number of fields for Load/Store Segment instructions. - int NF = 1; -} - -// This is the code emitted in the header. -class RVVHeader { - code HeaderCode; -} +include "riscv_vector_common.td" //===----------------------------------------------------------------------===// // Basic classes with automatic codegen. @@ -2374,91 +2148,3 @@ } } } - -class VCIXSuffix { - list suffix = !cond(!eq(range, "c"): ["8mf8", "8mf4", "8mf2", "8m1", "8m2", "8m4", "8m8"], - !eq(range, "s"): ["16mf4", "16mf2", "16m1", "16m2", "16m4", "16m8"], - !eq(range, "i"): ["32mf2", "32m1", "32m2", "32m4", "32m8"], - !eq(range, "l"): ["64m1", "64m2", "64m4", "64m8"]); -} - -class VCIXBuiltinSet intrinsic_types> - : RVVBuiltin { - let Name = name; - let OverloadedName = name; - let IRName = IR_name; - let HasMasked = false; - let IntrinsicTypes = intrinsic_types; -} - -multiclass VCIXBuiltinSet intrinsic_types> { - if !find(prototype, "0") then { - def : VCIXBuiltinSet; - } - def : VCIXBuiltinSet; -} - -multiclass RVVVCIXBuiltinSet range, string prototype, - list intrinsic_types, bit EncodeVtype, - bit UseGPR> { - defvar suffix = !if(EncodeVtype, "", "Uv"); - foreach r = range in { - let RequiredFeatures = !if(!and(UseGPR, !eq(r, "l")), - ["Xsfvcp", "RV64"], ["Xsfvcp"]) in { - // If EncodeVtype is true, then these intrinsic don't have any vector - // types in the output and inputs, but we still need to add vetvli for - // them. So we encode different VTYPE into the intrinsic names, and - // then will know which vsetvli is correct. - if EncodeVtype then { - foreach s = VCIXSuffix.suffix in { - defvar name = NAME # "_u" # s; - defvar IR_name = NAME # "_e" # s; - // Since we already encode the Vtype into the name, so just set - // Log2LMUL to zero. Otherwise the RISCVVEmitter will expand - // lots of redundant intrinsic but have same names. - let Log2LMUL = [0] in - def : VCIXBuiltinSet; - } - } else { - defm : VCIXBuiltinSet; - } - } - } -} - -let SupportOverloading = false in { - defm sf_vc_x_se : RVVVCIXBuiltinSet<["c", "s", "i", "l"], "0KzKzKzUe", [0, 3], /*EncodeVtype*/1, /*UseGPR*/1>; - defm sf_vc_i_se : RVVVCIXBuiltinSet<["c", "s", "i", "l"], "0KzKzKzKz", [2, 3], /*EncodeVtype*/1, /*UseGPR*/0>; - defm sf_vc_xv : RVVVCIXBuiltinSet<["csi", "l"], "0KzKzUvUe", [0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/1>; - defm sf_vc_iv : RVVVCIXBuiltinSet<["csi", "l"], "0KzKzUvKz", [0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_vv : RVVVCIXBuiltinSet<["csi", "l"], "0KzKzUvUv", [0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_fv : RVVVCIXBuiltinSet<["si", "l"], "0KzKzUvFe", [0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_xvv : RVVVCIXBuiltinSet<["csi", "l"], "0KzUvUvUe", [0, 1, 3], /*EncodeVtype*/0, /*UseGPR*/1>; - defm sf_vc_ivv : RVVVCIXBuiltinSet<["csi", "l"], "0KzUvUvKz", [0, 1, 3], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_vvv : RVVVCIXBuiltinSet<["csi", "l"], "0KzUvUvUv", [0, 1, 3], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_fvv : RVVVCIXBuiltinSet<["si", "l"], "0KzUvUvFe", [0, 1, 3], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_v_x : RVVVCIXBuiltinSet<["csi", "l"], "UvKzKzUe", [-1, 1, 2], /*EncodeVtype*/0, /*UseGPR*/1>; - defm sf_vc_v_i : RVVVCIXBuiltinSet<["csi", "l"], "UvKzKzKz", [-1, 1, 2], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_v_xv : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvUe", [-1, 0, 2], /*EncodeVtype*/0, /*UseGPR*/1>; - defm sf_vc_v_iv : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvKz", [-1, 0, 2], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_v_vv : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvUv", [-1, 0, 2], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_v_fv : RVVVCIXBuiltinSet<["si", "l"], "UvKzUvFe", [-1, 0, 2], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_v_xvv : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvUvUe", [-1, 0, 3], /*EncodeVtype*/0, /*UseGPR*/1>; - defm sf_vc_v_ivv : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvUvKz", [-1, 0, 3], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_v_vvv : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvUvUv", [-1, 0, 3], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_v_fvv : RVVVCIXBuiltinSet<["si", "l"], "UvKzUvUvFe", [-1, 0, 3], /*EncodeVtype*/0, /*UseGPR*/0>; - let Log2LMUL = [-3, -2, -1, 0, 1, 2] in { - defm sf_vc_xvw : RVVVCIXBuiltinSet<["csi"], "0KzUwUvUe", [0, 1, 2, 3], /*EncodeVtype*/0, /*UseGPR*/1>; - defm sf_vc_ivw : RVVVCIXBuiltinSet<["csi"], "0KzUwUvKz", [0, 1, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_vvw : RVVVCIXBuiltinSet<["csi"], "0KzUwUvUv", [0, 1, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_fvw : RVVVCIXBuiltinSet<["si"], "0KzUwUvFe", [0, 1, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_v_xvw : RVVVCIXBuiltinSet<["csi"], "UwKzUwUvUe", [-1, 0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/1>; - defm sf_vc_v_ivw : RVVVCIXBuiltinSet<["csi"], "UwKzUwUvKz", [-1, 0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_v_vvw : RVVVCIXBuiltinSet<["csi"], "UwKzUwUvUv", [-1, 0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; - defm sf_vc_v_fvw : RVVVCIXBuiltinSet<["si"], "UwKzUwUvFe", [-1, 0, 2, 3], /*EncodeVtype*/0, /*UseGPR*/0>; - } -} diff --git a/clang/include/clang/Basic/riscv_vector_common.td b/clang/include/clang/Basic/riscv_vector_common.td new file mode 100644 --- /dev/null +++ b/clang/include/clang/Basic/riscv_vector_common.td @@ -0,0 +1,239 @@ +//==------ riscv_vector_common.td - RISC-V V-ext builtin class ------------===// +// +// Part of the LLVM Project, 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines RVV builtin base class for RISC-V V-extension. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Instruction definitions +//===----------------------------------------------------------------------===// +// Each record of the class RVVBuiltin defines a collection of builtins (i.e. +// "def vadd : RVVBuiltin" will be used to define things like "vadd_vv_i32m1", +// "vadd_vv_i32m2", etc). +// +// The elements of this collection are defined by an instantiation process the +// range of which is specified by the cross product of the LMUL attribute and +// every element in the attribute TypeRange. By default builtins have LMUL = [1, +// 2, 4, 8, 1/2, 1/4, 1/8] so the process is repeated 7 times. In tablegen we +// use the Log2LMUL [0, 1, 2, 3, -1, -2, -3] to represent the LMUL. +// +// LMUL represents the fact that the types of values used by that builtin are +// values generated by instructions that are executed under that LMUL. However, +// this does not mean the builtin is necessarily lowered into an instruction +// that executes under the specified LMUL. An example where this happens are +// loads and stores of masks. A mask like `vbool8_t` can be generated, for +// instance, by comparing two `__rvv_int8m1_t` (this is LMUL=1) or comparing two +// `__rvv_int16m2_t` (this is LMUL=2). The actual load or store, however, will +// be performed under LMUL=1 because mask registers are not grouped. +// +// TypeRange is a non-empty sequence of basic types: +// +// c: int8_t (i8) +// s: int16_t (i16) +// i: int32_t (i32) +// l: int64_t (i64) +// x: float16_t (half) +// f: float32_t (float) +// d: float64_t (double) +// +// This way, given an LMUL, a record with a TypeRange "sil" will cause the +// definition of 3 builtins. Each type "t" in the TypeRange (in this example +// they are int16_t, int32_t, int64_t) is used as a parameter that drives the +// definition of that particular builtin (for the given LMUL). +// +// During the instantiation, types can be transformed or modified using type +// transformers. Given a type "t" the following primitive type transformers can +// be applied to it to yield another type. +// +// e: type of "t" as is (identity) +// v: computes a vector type whose element type is "t" for the current LMUL +// w: computes a vector type identical to what 'v' computes except for the +// element type which is twice as wide as the element type of 'v' +// q: computes a vector type identical to what 'v' computes except for the +// element type which is four times as wide as the element type of 'v' +// o: computes a vector type identical to what 'v' computes except for the +// element type which is eight times as wide as the element type of 'v' +// m: computes a vector type identical to what 'v' computes except for the +// element type which is bool +// 0: void type, ignores "t" +// z: size_t, ignores "t" +// t: ptrdiff_t, ignores "t" +// u: unsigned long, ignores "t" +// l: long, ignores "t" +// +// So for instance if t is "i", i.e. int, then "e" will yield int again. "v" +// will yield an RVV vector type (assume LMUL=1), so __rvv_int32m1_t. +// Accordingly "w" would yield __rvv_int64m2_t. +// +// A type transformer can be prefixed by other non-primitive type transformers. +// +// P: constructs a pointer to the current type +// C: adds const to the type +// K: requires the integer type to be a constant expression +// U: given an integer type or vector type, computes its unsigned variant +// I: given a vector type, compute the vector type with integer type +// elements of the same width +// F: given a vector type, compute the vector type with floating-point type +// elements of the same width +// S: given a vector type, computes its equivalent one for LMUL=1. This is a +// no-op if the vector was already LMUL=1 +// (Log2EEW:Value): Log2EEW value could be 3/4/5/6 (8/16/32/64), given a +// vector type (SEW and LMUL) and EEW (8/16/32/64), computes its +// equivalent integer vector type with EEW and corresponding ELMUL (elmul = +// (eew/sew) * lmul). For example, vector type is __rvv_float16m4 +// (SEW=16, LMUL=4) and Log2EEW is 3 (EEW=8), and then equivalent vector +// type is __rvv_uint8m2_t (elmul=(8/16)*4 = 2). Ignore to define a new +// builtins if its equivalent type has illegal lmul. +// (FixedSEW:Value): Given a vector type (SEW and LMUL), and computes another +// vector type which only changed SEW as given value. Ignore to define a new +// builtin if its equivalent type has illegal lmul or the SEW does not changed. +// (SFixedLog2LMUL:Value): Smaller Fixed Log2LMUL. Given a vector type (SEW +// and LMUL), and computes another vector type which only changed LMUL as +// given value. The new LMUL should be smaller than the old one. Ignore to +// define a new builtin if its equivalent type has illegal lmul. +// (LFixedLog2LMUL:Value): Larger Fixed Log2LMUL. Given a vector type (SEW +// and LMUL), and computes another vector type which only changed LMUL as +// given value. The new LMUL should be larger than the old one. Ignore to +// define a new builtin if its equivalent type has illegal lmul. +// +// Following with the example above, if t is "i", then "Ue" will yield unsigned +// int and "Fv" will yield __rvv_float32m1_t (again assuming LMUL=1), Fw would +// yield __rvv_float64m2_t, etc. +// +// Each builtin is then defined by applying each type in TypeRange against the +// sequence of type transformers described in Suffix and Prototype. +// +// The name of the builtin is defined by the Name attribute (which defaults to +// the name of the class) appended (separated with an underscore) the Suffix +// attribute. For instance with Name="foo", Suffix = "v" and TypeRange = "il", +// the builtin generated will be __builtin_rvv_foo_i32m1 and +// __builtin_rvv_foo_i64m1 (under LMUL=1). If Suffix contains more than one +// type transformer (say "vv") each of the types is separated with an +// underscore as in "__builtin_rvv_foo_i32m1_i32m1". +// +// The C/C++ prototype of the builtin is defined by the Prototype attribute. +// Prototype is a non-empty sequence of type transformers, the first of which +// is the return type of the builtin and the rest are the parameters of the +// builtin, in order. For instance if Prototype is "wvv" and TypeRange is "si" +// a first builtin will have type +// __rvv_int32m2_t (__rvv_int16m1_t, __rvv_int16m1_t) and the second builtin +// will have type __rvv_int64m2_t (__rvv_int32m1_t, __rvv_int32m1_t) (again +// under LMUL=1). +// +// There are a number of attributes that are used to constraint the number and +// shape of the builtins generated. Refer to the comments below for them. + +class PolicyScheme{ + int Value = val; +} +def NonePolicy : PolicyScheme<0>; +def HasPassthruOperand : PolicyScheme<1>; +def HasPolicyOperand : PolicyScheme<2>; + +class RVVBuiltin { + // Base name that will be prepended in __builtin_rvv_ and appended the + // computed Suffix. + string Name = NAME; + + // If not empty, each instantiated builtin will have this appended after an + // underscore (_). It is instantiated like Prototype. + string Suffix = suffix; + + // If empty, default OverloadedName is sub string of `Name` which end of first + // '_'. For example, the default overloaded name is `vadd` for Name `vadd_vv`. + // It's used for describe some special naming cases. + string OverloadedName = ""; + + // If not empty, each OverloadedName will have this appended after an + // underscore (_). It is instantiated like Prototype. + string OverloadedSuffix = overloaded_suffix; + + // The different variants of the builtin, parameterised with a type. + string TypeRange = type_range; + + // We use each type described in TypeRange and LMUL with prototype to + // instantiate a specific element of the set of builtins being defined. + // Prototype attribute defines the C/C++ prototype of the builtin. It is a + // non-empty sequence of type transformers, the first of which is the return + // type of the builtin and the rest are the parameters of the builtin, in + // order. For instance if Prototype is "wvv", TypeRange is "si" and LMUL=1, a + // first builtin will have type + // __rvv_int32m2_t (__rvv_int16m1_t, __rvv_int16m1_t), and the second builtin + // will have type __rvv_int64m2_t (__rvv_int32m1_t, __rvv_int32m1_t). + string Prototype = prototype; + + // This builtin has a masked form. + bit HasMasked = true; + + // If HasMasked, this flag states that this builtin has a maskedoff operand. It + // is always the first operand in builtin and IR intrinsic. + bit HasMaskedOffOperand = true; + + // This builtin has a granted vector length parameter. + bit HasVL = true; + + // The policy scheme for masked intrinsic IR. + // It could be NonePolicy or HasPolicyOperand. + // HasPolicyOperand: Has a policy operand. 0 is tail and mask undisturbed, 1 is + // tail agnostic, 2 is mask undisturbed, and 3 is tail and mask agnostic. The + // policy operand is located at the last position. + PolicyScheme MaskedPolicyScheme = HasPolicyOperand; + + // The policy scheme for unmasked intrinsic IR. + // It could be NonePolicy, HasPassthruOperand or HasPolicyOperand. + // HasPassthruOperand: Has a passthru operand to decide tail policy. If it is + // poison, tail policy is tail agnostic, otherwise policy is tail undisturbed. + // HasPolicyOperand: Has a policy operand. 1 is tail agnostic and 0 is tail + // undisturbed. + PolicyScheme UnMaskedPolicyScheme = NonePolicy; + + // This builtin support tail agnostic and undisturbed policy. + bit HasTailPolicy = true; + // This builtin support mask agnostic and undisturbed policy. + bit HasMaskPolicy = true; + + // This builtin prototype with TA or TAMA policy could not support overloading + // API. Other policy intrinsic functions would support overloading API with + // suffix `_tu`, `tumu`, `tuma`, `tamu` and `tama`. + bit SupportOverloading = true; + + // This builtin is valid for the given Log2LMULs. + list Log2LMUL = [0, 1, 2, 3, -1, -2, -3]; + + // Manual code in clang codegen riscv_vector_builtin_cg.inc + code ManualCodegen = [{}]; + + // When emit the automatic clang codegen, it describes what types we have to use + // to obtain the specific LLVM intrinsic. -1 means the return type, otherwise, + // k >= 0 meaning the k-th operand (counting from zero) of the codegen'd + // parameter of the unmasked version. k can't be the mask operand's position. + list IntrinsicTypes = []; + + // If these names are not empty, this is the ID of the LLVM intrinsic + // we want to lower to. + string IRName = NAME; + + // If HasMasked, this is the ID of the LLVM intrinsic we want to lower to. + string MaskedIRName = NAME #"_mask"; + + // Use clang_builtin_alias to save the number of builtins. + bit HasBuiltinAlias = true; + + // Features required to enable for this builtin. + list RequiredFeatures = []; + + // Number of fields for Load/Store Segment instructions. + int NF = 1; +} + +// This is the code emitted in the header. +class RVVHeader { + code HeaderCode; +} diff --git a/clang/include/clang/Sema/RISCVIntrinsicManager.h b/clang/include/clang/Sema/RISCVIntrinsicManager.h --- a/clang/include/clang/Sema/RISCVIntrinsicManager.h +++ b/clang/include/clang/Sema/RISCVIntrinsicManager.h @@ -22,6 +22,8 @@ namespace sema { class RISCVIntrinsicManager { public: + enum class IntrinsicKind : uint8_t { RVV, SIFIVE_VCIX }; + virtual ~RISCVIntrinsicManager() = default; // Create RISC-V intrinsic and insert into symbol table and return true if diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1621,6 +1621,9 @@ /// Indicate RISC-V vector builtin functions enabled or not. bool DeclareRISCVVBuiltins = false; + /// Indicate RISC-V Sifive vcix builtin functions enabled or not. + bool DeclareRISCVVCIXBuiltins = false; + private: std::unique_ptr RVIntrinsicManager; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19966,6 +19966,8 @@ // Vector builtins are handled from here. #include "clang/Basic/riscv_vector_builtin_cg.inc" + // SiFive VCIX builtins are handled from here. +#include "clang/Basic/riscv_sifive_vcix_builtin_cg.inc" } assert(ID != Intrinsic::not_intrinsic); diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -98,6 +98,10 @@ htmxlintrin.h ) +set(sifive_files + sifive_vector.h + ) + set(systemz_files s390intrin.h vecintrin.h @@ -244,6 +248,7 @@ ${opencl_files} ${ppc_files} ${ppc_htm_files} + ${sifive_files} ${systemz_files} ${ve_files} ${x86_files} diff --git a/clang/lib/Headers/sifive_vector.h b/clang/lib/Headers/sifive_vector.h new file mode 100644 --- /dev/null +++ b/clang/lib/Headers/sifive_vector.h @@ -0,0 +1,16 @@ +//===----- sifive_vector.h - SiFive Vector definitions --------------------===// +// +// Part of the LLVM Project, 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _SIFIVE_VECTOR_H_ +#define _SIFIVE_VECTOR_H_ + +#include "riscv_vector.h" + +#pragma clang riscv intrinsic sifive_vcix + +#endif //_SIFIVE_VECTOR_H_ diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -4023,6 +4023,7 @@ } // Handle '#pragma clang riscv intrinsic vector'. +// '#pragma clang riscv intrinsic sifive_vcix'. void PragmaRISCVHandler::HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) { @@ -4038,9 +4039,11 @@ PP.Lex(Tok); II = Tok.getIdentifierInfo(); - if (!II || !II->isStr("vector")) { + StringRef IntrinsicClass = II->getName(); + if (!II || !(II->isStr("vector") || II->isStr("sifive_vcix"))) { PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument) - << PP.getSpelling(Tok) << "riscv" << /*Expected=*/true << "'vector'"; + << PP.getSpelling(Tok) << "riscv" << /*Expected=*/true + << "'vector' or 'sifive_vcix'"; return; } @@ -4051,5 +4054,8 @@ return; } - Actions.DeclareRISCVVBuiltins = true; + if (IntrinsicClass == "vector") + Actions.DeclareRISCVVBuiltins = true; + else if (IntrinsicClass == "sifive_vcix") + Actions.DeclareRISCVVCIXBuiltins = true; } diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -932,7 +932,7 @@ } } - if (DeclareRISCVVBuiltins) { + if (DeclareRISCVVBuiltins || DeclareRISCVVCIXBuiltins) { if (!RVIntrinsicManager) RVIntrinsicManager = CreateRISCVIntrinsicManager(*this); diff --git a/clang/lib/Sema/SemaRISCVVectorLookup.cpp b/clang/lib/Sema/SemaRISCVVectorLookup.cpp --- a/clang/lib/Sema/SemaRISCVVectorLookup.cpp +++ b/clang/lib/Sema/SemaRISCVVectorLookup.cpp @@ -28,6 +28,8 @@ using namespace clang; using namespace clang::RISCV; +using IntrinsicKind = sema::RISCVIntrinsicManager::IntrinsicKind; + namespace { // Function definition of a RVV intrinsic. @@ -58,16 +60,35 @@ #undef DECL_SIGNATURE_TABLE }; +static const PrototypeDescriptor RVSiFiveVCIXSignatureTable[] = { +#define DECL_SIGNATURE_TABLE +#include "clang/Basic/riscv_sifive_vcix_builtin_sema.inc" +#undef DECL_SIGNATURE_TABLE +}; + static const RVVIntrinsicRecord RVVIntrinsicRecords[] = { #define DECL_INTRINSIC_RECORDS #include "clang/Basic/riscv_vector_builtin_sema.inc" #undef DECL_INTRINSIC_RECORDS }; +static const RVVIntrinsicRecord RVSiFiveVCIXIntrinsicRecords[] = { +#define DECL_INTRINSIC_RECORDS +#include "clang/Basic/riscv_sifive_vcix_builtin_sema.inc" +#undef DECL_INTRINSIC_RECORDS +}; + // Get subsequence of signature table. -static ArrayRef ProtoSeq2ArrayRef(uint16_t Index, - uint8_t Length) { - return ArrayRef(&RVVSignatureTable[Index], Length); +static ArrayRef +ProtoSeq2ArrayRef(IntrinsicKind K, uint16_t Index, uint8_t Length) { + switch (K) { + default: + llvm_unreachable("Unsupported intrinsic kind."); + case IntrinsicKind::RVV: + return ArrayRef(&RVVSignatureTable[Index], Length); + case IntrinsicKind::SIFIVE_VCIX: + return ArrayRef(&RVSiFiveVCIXSignatureTable[Index], Length); + } } static QualType RVVType2Qual(ASTContext &Context, const RVVType *Type) { @@ -172,123 +193,132 @@ bool HasRV64 = TI.hasFeature("64bit"); bool HasFullMultiply = TI.hasFeature("v"); - // Construction of RVVIntrinsicRecords need to sync with createRVVIntrinsics - // in RISCVVEmitter.cpp. - for (auto &Record : RVVIntrinsicRecords) { - // Create Intrinsics for each type and LMUL. - BasicType BaseType = BasicType::Unknown; - ArrayRef BasicProtoSeq = - ProtoSeq2ArrayRef(Record.PrototypeIndex, Record.PrototypeLength); - ArrayRef SuffixProto = - ProtoSeq2ArrayRef(Record.SuffixIndex, Record.SuffixLength); - ArrayRef OverloadedSuffixProto = ProtoSeq2ArrayRef( - Record.OverloadedSuffixIndex, Record.OverloadedSuffixSize); - - PolicyScheme UnMaskedPolicyScheme = - static_cast(Record.UnMaskedPolicyScheme); - PolicyScheme MaskedPolicyScheme = - static_cast(Record.MaskedPolicyScheme); - - const Policy DefaultPolicy; - - llvm::SmallVector ProtoSeq = - RVVIntrinsic::computeBuiltinTypes(BasicProtoSeq, /*IsMasked=*/false, - /*HasMaskedOffOperand=*/false, - Record.HasVL, Record.NF, - UnMaskedPolicyScheme, DefaultPolicy); - - llvm::SmallVector ProtoMaskSeq = - RVVIntrinsic::computeBuiltinTypes( - BasicProtoSeq, /*IsMasked=*/true, Record.HasMaskedOffOperand, - Record.HasVL, Record.NF, MaskedPolicyScheme, DefaultPolicy); - - bool UnMaskedHasPolicy = UnMaskedPolicyScheme != PolicyScheme::SchemeNone; - bool MaskedHasPolicy = MaskedPolicyScheme != PolicyScheme::SchemeNone; - SmallVector SupportedUnMaskedPolicies = - RVVIntrinsic::getSupportedUnMaskedPolicies(); - SmallVector SupportedMaskedPolicies = - RVVIntrinsic::getSupportedMaskedPolicies(Record.HasTailPolicy, - Record.HasMaskPolicy); - - for (unsigned int TypeRangeMaskShift = 0; - TypeRangeMaskShift <= static_cast(BasicType::MaxOffset); - ++TypeRangeMaskShift) { - unsigned int BaseTypeI = 1 << TypeRangeMaskShift; - BaseType = static_cast(BaseTypeI); - - if ((BaseTypeI & Record.TypeRangeMask) != BaseTypeI) - continue; - - // Check requirement. - if (((Record.RequiredExtensions & RVV_REQ_RV64) == RVV_REQ_RV64) && - !HasRV64) - continue; - - if ((BaseType == BasicType::Int64) && - ((Record.RequiredExtensions & RVV_REQ_FullMultiply) == - RVV_REQ_FullMultiply) && - !HasFullMultiply) - continue; - - // Expanded with different LMUL. - for (int Log2LMUL = -3; Log2LMUL <= 3; Log2LMUL++) { - if (!(Record.Log2LMULMask & (1 << (Log2LMUL + 3)))) + auto ConstructRVVIntrinsics = [&](ArrayRef Recs, + IntrinsicKind K) { + // Construction of RVVIntrinsicRecords need to sync with createRVVIntrinsics + // in RISCVVEmitter.cpp. + for (auto &Record : Recs) { + // Create Intrinsics for each type and LMUL. + BasicType BaseType = BasicType::Unknown; + ArrayRef BasicProtoSeq = + ProtoSeq2ArrayRef(K, Record.PrototypeIndex, Record.PrototypeLength); + ArrayRef SuffixProto = + ProtoSeq2ArrayRef(K, Record.SuffixIndex, Record.SuffixLength); + ArrayRef OverloadedSuffixProto = ProtoSeq2ArrayRef( + K, Record.OverloadedSuffixIndex, Record.OverloadedSuffixSize); + + PolicyScheme UnMaskedPolicyScheme = + static_cast(Record.UnMaskedPolicyScheme); + PolicyScheme MaskedPolicyScheme = + static_cast(Record.MaskedPolicyScheme); + + const Policy DefaultPolicy; + + llvm::SmallVector ProtoSeq = + RVVIntrinsic::computeBuiltinTypes(BasicProtoSeq, /*IsMasked=*/false, + /*HasMaskedOffOperand=*/false, + Record.HasVL, Record.NF, + UnMaskedPolicyScheme, DefaultPolicy); + + llvm::SmallVector ProtoMaskSeq = + RVVIntrinsic::computeBuiltinTypes( + BasicProtoSeq, /*IsMasked=*/true, Record.HasMaskedOffOperand, + Record.HasVL, Record.NF, MaskedPolicyScheme, DefaultPolicy); + + bool UnMaskedHasPolicy = UnMaskedPolicyScheme != PolicyScheme::SchemeNone; + bool MaskedHasPolicy = MaskedPolicyScheme != PolicyScheme::SchemeNone; + SmallVector SupportedUnMaskedPolicies = + RVVIntrinsic::getSupportedUnMaskedPolicies(); + SmallVector SupportedMaskedPolicies = + RVVIntrinsic::getSupportedMaskedPolicies(Record.HasTailPolicy, + Record.HasMaskPolicy); + + for (unsigned int TypeRangeMaskShift = 0; + TypeRangeMaskShift <= static_cast(BasicType::MaxOffset); + ++TypeRangeMaskShift) { + unsigned int BaseTypeI = 1 << TypeRangeMaskShift; + BaseType = static_cast(BaseTypeI); + + if ((BaseTypeI & Record.TypeRangeMask) != BaseTypeI) continue; - std::optional Types = - TypeCache.computeTypes(BaseType, Log2LMUL, Record.NF, ProtoSeq); - - // Ignored to create new intrinsic if there are any illegal types. - if (!Types.has_value()) + // Check requirement. + if (((Record.RequiredExtensions & RVV_REQ_RV64) == RVV_REQ_RV64) && + !HasRV64) continue; - std::string SuffixStr = RVVIntrinsic::getSuffixStr( - TypeCache, BaseType, Log2LMUL, SuffixProto); - std::string OverloadedSuffixStr = RVVIntrinsic::getSuffixStr( - TypeCache, BaseType, Log2LMUL, OverloadedSuffixProto); - - // Create non-masked intrinsic. - InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, false, *Types, - UnMaskedHasPolicy, DefaultPolicy); + if ((BaseType == BasicType::Int64) && + ((Record.RequiredExtensions & RVV_REQ_FullMultiply) == + RVV_REQ_FullMultiply) && + !HasFullMultiply) + continue; - // Create non-masked policy intrinsic. - if (Record.UnMaskedPolicyScheme != PolicyScheme::SchemeNone) { - for (auto P : SupportedUnMaskedPolicies) { + // Expanded with different LMUL. + for (int Log2LMUL = -3; Log2LMUL <= 3; Log2LMUL++) { + if (!(Record.Log2LMULMask & (1 << (Log2LMUL + 3)))) + continue; + + std::optional Types = + TypeCache.computeTypes(BaseType, Log2LMUL, Record.NF, ProtoSeq); + + // Ignored to create new intrinsic if there are any illegal types. + if (!Types.has_value()) + continue; + + std::string SuffixStr = RVVIntrinsic::getSuffixStr( + TypeCache, BaseType, Log2LMUL, SuffixProto); + std::string OverloadedSuffixStr = RVVIntrinsic::getSuffixStr( + TypeCache, BaseType, Log2LMUL, OverloadedSuffixProto); + + // Create non-masked intrinsic. + InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, false, *Types, + UnMaskedHasPolicy, DefaultPolicy); + + // Create non-masked policy intrinsic. + if (Record.UnMaskedPolicyScheme != PolicyScheme::SchemeNone) { + for (auto P : SupportedUnMaskedPolicies) { + llvm::SmallVector PolicyPrototype = + RVVIntrinsic::computeBuiltinTypes( + BasicProtoSeq, /*IsMasked=*/false, + /*HasMaskedOffOperand=*/false, Record.HasVL, Record.NF, + UnMaskedPolicyScheme, P); + std::optional PolicyTypes = TypeCache.computeTypes( + BaseType, Log2LMUL, Record.NF, PolicyPrototype); + InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, + /*IsMask=*/false, *PolicyTypes, UnMaskedHasPolicy, + P); + } + } + if (!Record.HasMasked) + continue; + // Create masked intrinsic. + std::optional MaskTypes = + TypeCache.computeTypes(BaseType, Log2LMUL, Record.NF, ProtoMaskSeq); + InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, true, + *MaskTypes, MaskedHasPolicy, DefaultPolicy); + if (Record.MaskedPolicyScheme == PolicyScheme::SchemeNone) + continue; + // Create masked policy intrinsic. + for (auto P : SupportedMaskedPolicies) { llvm::SmallVector PolicyPrototype = RVVIntrinsic::computeBuiltinTypes( - BasicProtoSeq, /*IsMasked=*/false, - /*HasMaskedOffOperand=*/false, Record.HasVL, Record.NF, - UnMaskedPolicyScheme, P); + BasicProtoSeq, /*IsMasked=*/true, Record.HasMaskedOffOperand, + Record.HasVL, Record.NF, MaskedPolicyScheme, P); std::optional PolicyTypes = TypeCache.computeTypes( BaseType, Log2LMUL, Record.NF, PolicyPrototype); InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, - /*IsMask=*/false, *PolicyTypes, UnMaskedHasPolicy, - P); + /*IsMask=*/true, *PolicyTypes, MaskedHasPolicy, P); } - } - if (!Record.HasMasked) - continue; - // Create masked intrinsic. - std::optional MaskTypes = - TypeCache.computeTypes(BaseType, Log2LMUL, Record.NF, ProtoMaskSeq); - InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, true, - *MaskTypes, MaskedHasPolicy, DefaultPolicy); - if (Record.MaskedPolicyScheme == PolicyScheme::SchemeNone) - continue; - // Create masked policy intrinsic. - for (auto P : SupportedMaskedPolicies) { - llvm::SmallVector PolicyPrototype = - RVVIntrinsic::computeBuiltinTypes( - BasicProtoSeq, /*IsMasked=*/true, Record.HasMaskedOffOperand, - Record.HasVL, Record.NF, MaskedPolicyScheme, P); - std::optional PolicyTypes = TypeCache.computeTypes( - BaseType, Log2LMUL, Record.NF, PolicyPrototype); - InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, - /*IsMask=*/true, *PolicyTypes, MaskedHasPolicy, P); - } - } // End for different LMUL - } // End for different TypeRange - } + } // End for different LMUL + } // End for different TypeRange + } + }; + if (S.DeclareRISCVVBuiltins) + ConstructRVVIntrinsics(RVVIntrinsicRecords, + IntrinsicKind::RVV); + if (S.DeclareRISCVVCIXBuiltins) + ConstructRVVIntrinsics(RVSiFiveVCIXIntrinsicRecords, + IntrinsicKind::SIFIVE_VCIX); } // Compute name and signatures for intrinsic with practical types. diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-x-rv64.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-x-rv64.c --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-x-rv64.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-x-rv64.c @@ -1,7 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +xsfvcp -disable-O0-optnone -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck --check-prefix=CHECK-RV64 %s -#include +#include #define p27_26 (0b11) #define p24_20 (0b11111) diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-x.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-x.c --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-x.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-x.c @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -triple riscv32 -target-feature +v -target-feature +xsfvcp -disable-O0-optnone -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck --check-prefix=CHECK-RV32 %s // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +xsfvcp -disable-O0-optnone -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck --check-prefix=CHECK-RV64 %s -#include +#include #define p27_26 (0b11) #define p24_20 (0b11111) diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xv-rv64.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xv-rv64.c --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xv-rv64.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xv-rv64.c @@ -2,7 +2,7 @@ // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +xsfvcp -disable-O0-optnone -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck --check-prefix=CHECK-RV64 %s -#include +#include #define p27_26 (0b11) #define p11_7 (0b11111) diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xv.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xv.c --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xv.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xv.c @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -triple riscv32 -target-feature +v -target-feature +zfh -target-feature +xsfvcp -disable-O0-optnone -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck --check-prefix=CHECK-RV32 %s // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh -target-feature +xsfvcp -disable-O0-optnone -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck --check-prefix=CHECK-RV64 %s -#include +#include #define p27_26 (0b11) #define p26 (0b1) diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xvv-rv64.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xvv-rv64.c --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xvv-rv64.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xvv-rv64.c @@ -2,7 +2,7 @@ // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh -target-feature +xsfvcp -disable-O0-optnone -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck --check-prefix=CHECK-RV64 %s -#include +#include #define p27_26 (0b11) diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xvv.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xvv.c --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xvv.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xvv.c @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -triple riscv32 -target-feature +v -target-feature +zfh -target-feature +xsfvcp -disable-O0-optnone -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck --check-prefix=CHECK-RV32 %s // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh -target-feature +xsfvcp -disable-O0-optnone -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck --check-prefix=CHECK-RV64 %s -#include +#include #define p27_26 (0b11) #define p26 (0b1) diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xvw.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xvw.c --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xvw.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/xsfvcp-xvw.c @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -triple riscv32 -target-feature +v -target-feature +zfh -target-feature +xsfvcp -disable-O0-optnone -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck --check-prefix=CHECK-RV32 %s // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh -target-feature +xsfvcp -disable-O0-optnone -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck --check-prefix=CHECK-RV64 %s -#include +#include #define p27_26 (0b11) #define p26 (0b1) diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/xsfvcp-index-out-of-range.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/xsfvcp-index-out-of-range.c --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/xsfvcp-index-out-of-range.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/xsfvcp-index-out-of-range.c @@ -5,7 +5,7 @@ // RUN: -target-feature +xsfvcp \ // RUN: -fsyntax-only -verify %s -#include +#include #define p27_26 (0b11) #define p26 (0b1) diff --git a/clang/test/Sema/riscv-bad-intrinsic-pragma.c b/clang/test/Sema/riscv-bad-intrinsic-pragma.c --- a/clang/test/Sema/riscv-bad-intrinsic-pragma.c +++ b/clang/test/Sema/riscv-bad-intrinsic-pragma.c @@ -2,7 +2,7 @@ // RUN: 2>&1 | FileCheck %s #pragma clang riscv intrinsic vvvv -// CHECK: warning: unexpected argument 'vvvv' to '#pragma riscv'; expected 'vector' [-Wignored-pragmas] +// CHECK: warning: unexpected argument 'vvvv' to '#pragma riscv'; expected 'vector' or 'sifive_vcix' [-Wignored-pragmas] #pragma clang riscv what + 3241 // CHECK: warning: unexpected argument 'what' to '#pragma riscv'; expected 'intrinsic' [-Wignored-pragmas] diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp --- a/clang/utils/TableGen/TableGen.cpp +++ b/clang/utils/TableGen/TableGen.cpp @@ -91,6 +91,9 @@ GenRISCVVectorBuiltins, GenRISCVVectorBuiltinCG, GenRISCVVectorBuiltinSema, + GenRISCVSiFiveVCIXBuiltins, + GenRISCVSiFiveVCIXBuiltinCG, + GenRISCVSiFiveVCIXBuiltinSema, GenAttrDocs, GenDiagDocs, GenOptDocs, @@ -251,6 +254,12 @@ "Generate riscv_vector_builtin_cg.inc for clang"), clEnumValN(GenRISCVVectorBuiltinSema, "gen-riscv-vector-builtin-sema", "Generate riscv_vector_builtin_sema.inc for clang"), + clEnumValN(GenRISCVSiFiveVCIXBuiltins, "gen-riscv-sifive-vcix-builtins", + "Generate riscv_sifive_vcix_builtins.inc for clang"), + clEnumValN(GenRISCVSiFiveVCIXBuiltinCG, "gen-riscv-sifive-vcix-builtin-codegen", + "Generate riscv_sifive_vcix_builtin_cg.inc for clang"), + clEnumValN(GenRISCVSiFiveVCIXBuiltinSema, "gen-riscv-sifive-vcix-builtin-sema", + "Generate riscv_sifive_vcix_builtin_sema.inc for clang"), clEnumValN(GenAttrDocs, "gen-attr-docs", "Generate attribute documentation"), clEnumValN(GenDiagDocs, "gen-diag-docs", @@ -472,6 +481,15 @@ case GenRISCVVectorBuiltinSema: EmitRVVBuiltinSema(Records, OS); break; + case GenRISCVSiFiveVCIXBuiltins: + EmitRVVBuiltins(Records, OS); + break; + case GenRISCVSiFiveVCIXBuiltinCG: + EmitRVVBuiltinCG(Records, OS); + break; + case GenRISCVSiFiveVCIXBuiltinSema: + EmitRVVBuiltinSema(Records, OS); + break; case GenAttrDocs: EmitClangAttrDocs(Records, OS); break; diff --git a/llvm/docs/CommandGuide/tblgen.rst b/llvm/docs/CommandGuide/tblgen.rst --- a/llvm/docs/CommandGuide/tblgen.rst +++ b/llvm/docs/CommandGuide/tblgen.rst @@ -348,6 +348,14 @@ Generate ``riscv_vector_builtin_cg.inc`` for Clang. +.. option:: -gen-riscv-sifive-vcix-builtins + + Generate ``riscv_sifive_vcix_builtins.inc`` for Clang. + +.. option:: -gen-riscv-sifive-vcix-builtin-codegen + + Generate ``riscv_sifive_vcix_builtin_cg.inc`` for Clang. + .. option:: -gen-attr-docs Generate attribute documentation.