v: add compiler support for _unlikely_(x) too

pull/5311/head
Delyan Angelov 2020-06-09 18:08:31 +03:00
parent c7d4360931
commit 4fc41c4bc4
9 changed files with 42 additions and 13 deletions

View File

@ -1700,6 +1700,9 @@ boolean expression is very likely to be true, so it can generate assembly
code, with less chance of branch misprediction. In the JS backend,
that does nothing.
`if _unlikely_(bool expression) {` similar to `_likely_(x)`, but it hints that
the boolean expression is highly improbable. In the JS backend, that does nothing.
## Reflection via codegen
Having built-in JSON support is nice, but V also allows you to create efficient

View File

@ -759,6 +759,7 @@ pub struct Likely {
pub:
expr Expr
pos token.Position
is_likely bool // false for _unlikely_
}
pub struct TypeOf {

View File

@ -1948,7 +1948,8 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
ltype := c.expr(it.expr)
if !c.check_types(ltype, table.bool_type) {
ltype_sym := c.table.get_type_symbol(ltype)
c.error('`_likely_()` expects a boolean expression, instead it got `${ltype_sym.name}`', it.pos)
lname := if it.is_likely { '_likely_' } else { '_unlikely_' }
c.error('`${lname}()` expects a boolean expression, instead it got `${ltype_sym.name}`', it.pos)
}
return table.bool_type
}

View File

@ -735,7 +735,12 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
f.write(')')
}
ast.Likely {
f.write('_likely_(')
if it.is_likely {
f.write('_likely_')
} else {
f.write('_unlikely_')
}
f.write('(')
f.expr(it.expr)
f.write(')')
}

View File

@ -1587,7 +1587,12 @@ fn (mut g Gen) expr(node ast.Expr) {
g.typeof_expr(it)
}
ast.Likely {
g.write('_likely_(')
if it.is_likely {
g.write('_likely_')
} else {
g.write('_unlikely_')
}
g.write('(')
g.expr(it.expr)
g.write(')')
}

View File

@ -255,8 +255,10 @@ void _vcleanup();
#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) || defined(__TINYC__)
#define _likely_(x) __builtin_expect(x, 1)
#define _unlikely_(x) __builtin_expect((x), 0)
#else
#define _likely_(x) (x)
#define _unlikely_(x) (x)
#endif
#if defined(TARGET_ORDER_IS_LITTLE)

View File

@ -103,7 +103,8 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
expr: expr
}
}
.key_likely {
.key_likely, .key_unlikely {
is_likely := p.tok.kind == .key_likely
p.next()
p.check(.lpar)
lpos := p.tok.position()
@ -112,6 +113,7 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
node = ast.Likely{
expr: expr
pos: lpos
is_likely: is_likely
}
}
.lcbr {

View File

@ -1,24 +1,32 @@
// _likely_(expr) should be compilable, and it should return the expr
fn test_likely_type(){
fn test_likely_type() {
assert typeof(_likely_(false)) == 'bool'
}
fn test_likely(){
if _likely_(2<10) {
assert _likely_(false) == false
assert _likely_(true) == true
}
fn test_likely() {
if _likely_(2 < 10) {
assert true
eprintln('ok, happens every time')
} else {
eprintln('happens *infrequently*')
assert false
}
}
}
fn test_likely_returns_the_value_of_its_bool_argument(){
fn test_likely_returns_the_value_of_its_bool_argument() {
i := 123
if _likely_(i<2) {
if _likely_(i < 2) {
assert false
} else {
assert true
}
}
// _unlikely_ is the same as _likely_ from the V point of view:
fn test_unlikely_type() {
assert typeof(_unlikely_(false)) == 'bool'
assert _unlikely_(false) == false
assert _unlikely_(true) == true
}

View File

@ -113,6 +113,7 @@ pub enum Kind {
key_select
key_sizeof
key_likely
key_unlikely
key_offsetof
key_struct
key_switch
@ -220,6 +221,7 @@ fn build_token_str() []string {
s[Kind.key_module] = 'module'
s[Kind.key_sizeof] = 'sizeof'
s[Kind.key_likely] = '_likely_'
s[Kind.key_unlikely] = '_unlikely_'
s[Kind.key_go] = 'go'
s[Kind.key_goto] = 'goto'
s[Kind.key_const] = 'const'