方法与运算符分类 - 2021.2 Chinese

Vitis 高层次综合用户指南 (UG1399)

Document ID
UG1399
Release Date
2021-12-15
Version
2021.2 Chinese

ap_[u]int 类型不支持从 wide ap_[u]int(>64 位)隐式转换为内置 C/C++ 整数类型。例如,由于在 if 语句中从 ap_int[65]bool 的隐式强制转换返回 0,因此以下代码示例返回 s1。

bool nonzero(ap_uint<65> data) {
   return data; // This leads to implicit truncation to 64b int
 }

int main() {
  if (nonzero((ap_uint<65>)1 << 64)) {
     return 0;
  }
  printf(FAIL\n);
  return 1;
}

要将较宽的 ap_[u]int 类型转换为内置整数,请使用 ap_[u]int 类型包含的显式转换函数:

  • to_int()
  • to_long()
  • to_bool()

一般情况下,支持针对 ap_[u]int 类型使用运算符重载来执行在原生 C/C++ 整数数据类型上执行的任意有效操作。

除这些重载运算符外,还包含部分特定于类的运算符和方法以简化位级运算。

二进制算术运算符

标准二进制整数算术运算符通过重载可提供任意精度算法。这些运算符采用:

  • 2 个 ap_[u]int 操作数,或者
  • 1 个 ap_[u]int 类型和 1 个 C/C++ 基本整数数据类型

例如:

  • char
  • short
  • int

在基于目标变量(或表达式)宽度应用符号位扩展、0 值填充或截断前,生成的值的宽度和符号有无取决于操作数的宽度和符号类型。对应每个运算符提供返回值的详细描述。

当表达式混用 ap_[u]int 与 C/C++ 基本整数类型时,C++ 类型假定采用如下宽度:

  • char(8 位)
  • short(16 位)
  • int(32 位)
  • long(32 位)
  • long long(64 位)

加法

ap_(u)int::RType ap_(u)int::operator + (ap_(u)int op)

返回以下值之和:

  • 2 个 ap_[u]int,或
  • 1 个 ap_[u]int 和 1 个 C/C++ 整数类型

和值的宽度为:

  • 比 2 个操作数的宽度多 1 位,或者
  • 2 位(仅当较宽的操作数无符号而较窄的操作数有符号时)

如果任一操作数或两个操作数均为有符号类型,则所得的和作为有符号来处理。

减法

ap_(u)int::RType ap_(u)int::operator - (ap_(u)int op)

返回 2 个整数之差。

差值的宽度为:

  • 比 2 个操作数的宽度多 1 位,或者
  • 2 位(仅当较宽的操作数无符号而较窄的操作数有符号时)

在赋值前已基于目标变量的宽度执行了符号位扩展、0 值填充或截断的情况下,可满足此条件。

差值作为有符号来处理,与操作数符号类型无关。

乘法

ap_(u)int::RType ap_(u)int::operator * (ap_(u)int op)

返回 2 个整数值的积。

积的宽度是操作数的宽度之和。

如果任一操作数类型为有符号,则积作为有符号类型来处理。

除法

ap_(u)int::RType ap_(u)int::operator / (ap_(u)int op)

返回 2 个整数值的商。

商的宽度为被除数的宽度(前提是除数为无符号类型)。否则,其宽度为被除数宽度加 1。

如果任一操作数类型为有符号,则商作为有符号类型来处理。

模数

ap_(u)int::RType ap_(u)int::operator % (ap_(u)int op)

返回 2 个整数值的整数除法的模数或余数。

模数的宽度为操作数宽度的最小值(前提是 2 个操作数符号类型相同)。

如果除数类型为无符号,而被除数类型为有符号,则宽度为除数宽度加 1。

商的符号类型与被除数相同。

重要: Vitis HLS 对模数 (%) 运算符进行综合会导致对生成的 RTL 中已适当参数化的赛灵思 LogiCORE 被除数核进行例化。

以下是算术运算符的示例:

ap_uint<71> Rslt;

ap_uint<42> Val1 = 5;
ap_int<23> Val2 = -8;

Rslt = Val1 + Val2; // Yields: -3 (43 bits) sign-extended to 71 bits
Rslt = Val1 - Val2; // Yields: +3 sign extended to 71 bits
Rslt = Val1 * Val2; // Yields: -40 (65 bits) sign extended to 71 bits
Rslt = 50 / Val2; // Yields: -6 (33 bits) sign extended to 71 bits
Rslt = 50 % Val2; // Yields: +2 (23 bits) sign extended to 71 bits

按位逻辑运算符

按位逻辑运算符返回的值的宽度全部为 2 个操作数的最大宽度。仅当 2 个操作数均为无符号时,才将其作为无符号来处理。否则,将其作为有符号类型来处理。

根据表达式(而不是目标变量)的符号类型,可能发生符号位扩展(或 0 值填充)。

按位 OR

ap_(u)int::RType ap_(u)int::operator | (ap_(u)int op)

返回 2 个操作数的按位 OR

按位 AND

ap_(u)int::RType ap_(u)int::operator & (ap_(u)int op)

返回 2 个操作数的按位 AND

按位 XOR

ap_(u)int::RType ap_(u)int::operator ^ (ap_(u)int op)

返回 2 个操作数的按位 XOR

一元运算符

加法

ap_(u)int ap_(u)int::operator + ()

返回 ap_[u]int 操作数的自我复制。

减法

ap_(u)int::RType ap_(u)int::operator - ()

运行以下操作:

  • 操作数的负值,位宽相同(前提是其类型为有符号);或者
  • 如果操作数无符号,则位宽为其位宽加 1。

返回值类型始终为有符号。

按位反转

ap_(u)int::RType ap_(u)int::operator ~ ()

返回操作数的按位 NOT,位宽相同,符号类型相同。

逻辑反转

bool ap_(u)int::operator ! ()

仅当操作数不等于零 (0) 时,返回布尔值 false

如果操作数等于零 (0),则返回布尔值 true

三元运算符

对标准 C 语言 int 类型使用三元运算符时,必须从一种类型显式强制转换为另一种类型,以确保 2 个结果的类型相同。例如:

// Integer type is cast to ap_int type
ap_int<32> testc3(int a, ap_int<32> b, ap_int<32> c, bool d) {
 return d?ap_int<32>(a):b;
}
// ap_int type is cast to an integer type
ap_int<32> testc4(int a, ap_int<32> b, ap_int<32> c, bool d) {
 return d?a+1:(int)b;
}
// Integer type is cast to ap_int type
ap_int<32> testc5(int a, ap_int<32> b, ap_int<32> c, bool d) {
 return d?ap_int<33>(a):b+1;
}

移位运算符

每个移位运算符都带有 2 个版本:

  • 1 个版本对应于无符号的右侧 (RHS) 操作数
  • 另 1 个版本对应于有符号的右侧 (RHS) 操作数

对有符号的 RHS 版本提供负值将导致移位操作方向反转。即按 RHS 操作数的绝对值发生反方向移位。

移位运算符返回的值的宽度与左侧 (LHS) 操作数相同。就像 C/C++ 一样,如果右移的 LHS 操作数为有符号类型,那么符号位将复制到最高有效位的位置,并保留 LHS 操作数的符号。

无符号的整数右移

ap_(u)int ap_(u)int::operator >> (ap_uint<int_W2> op)

整数右移

ap_(u)int ap_(u)int::operator >> (ap_int<int_W2> op)

无符号的整数左移

ap_(u)int ap_(u)int::operator << (ap_uint<int_W2> op)

整数左移

ap_(u)int ap_(u)int::operator << (ap_int<int_W2> op)
警告:
将左移运算符结果赋值到更宽的目标变量时,可能丢失部分或全部信息。赛灵思建议您将移位表达式显式强制转换为目标类型以避免发生意外行为。

以下是移位运算示例:

ap_uint<13> Rslt;

ap_uint<7> Val1 = 0x41;

Rslt = Val1 << 6;  // Yields: 0x0040, i.e. msb of Val1 is lost
Rslt = ap_uint<13>(Val1) << 6;  // Yields: 0x1040, no info lost

ap_int<7> Val2 = -63;
Rslt = Val2 >> 4;  //Yields: 0x1ffc, sign is maintained and extended

复合赋值运算符

Vitis HLS 支持复合赋值运算符:

  • *=
  • /=
  • %=
  • +=
  • -=
  • <<=
  • >>=
  • &=
  • ^=
  • |=

RHS 表达式首先进行求值,然后作为 RHS 操作数提供给基本运算符,其结果重新赋值给 LHS 变量。表达式大小、符号类型和可能的符号位扩展或截断规则适用方式与上述相关运算所述规则相同。

ap_uint<10> Val1 = 630;
ap_int<3> Val2 = -3;
ap_uint<5> Val3 = 27;

Val1 += Val2 - Val3; // Yields: 600 and is equivalent to:

// Val1 = ap_uint<10>(ap_int<11>(Val1) +
// ap_int<11>((ap_int<6>(Val2) -
// ap_int<6>(Val3))));

递增运算符和递减运算符

递增运算符和递减运算符均已提供。返回值的宽度全都与操作数相同,仅当 2 个操作数类型均为无符号时,返回值类型为无符号,否则为有符号。

递增前

ap_(u)int& ap_(u)int::operator ++ ()

返回操作数的递增值。

将递增值赋值给操作数。

递增后

const ap_(u)int ap_(u)int::operator ++ (int)

返回的值即为将递增值赋值给操作数变量之前的操作数。

递减前

ap_(u)int& ap_(u)int::operator -- ()

返回操作数的递减值并将递减值赋值给操作数。

递减后

const ap_(u)int ap_(u)int::operator -- (int)

返回的值即为将递减值赋值给操作数变量之前的操作数。

关系运算符

Vitis HLS 支持所有关系运算符。根据比较结果,这些运算符会返回布尔值。您可将 ap_[u]int 类型的变量与含有以下运算符的 C/C++ 基本整数类型进行比较。

等于

bool ap_(u)int::operator == (ap_(u)int op)

不等于

bool ap_(u)int::operator != (ap_(u)int op)

小于

bool ap_(u)int::operator < (ap_(u)int op)

大于

bool ap_(u)int::operator > (ap_(u)int op)

小于或等于

bool ap_(u)int::operator <= (ap_(u)int op)

大于或等于

bool ap_(u)int::operator >= (ap_(u)int op)