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, code, with less chance of branch misprediction. In the JS backend,
that does nothing. 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 ## Reflection via codegen
Having built-in JSON support is nice, but V also allows you to create efficient 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: pub:
expr Expr expr Expr
pos token.Position pos token.Position
is_likely bool // false for _unlikely_
} }
pub struct TypeOf { 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) ltype := c.expr(it.expr)
if !c.check_types(ltype, table.bool_type) { if !c.check_types(ltype, table.bool_type) {
ltype_sym := c.table.get_type_symbol(ltype) 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 return table.bool_type
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,8 @@
// _likely_(expr) should be compilable, and it should return the expr // _likely_(expr) should be compilable, and it should return the expr
fn test_likely_type() { fn test_likely_type() {
assert typeof(_likely_(false)) == 'bool' assert typeof(_likely_(false)) == 'bool'
assert _likely_(false) == false
assert _likely_(true) == true
} }
fn test_likely() { fn test_likely() {
@ -22,3 +23,10 @@ fn test_likely_returns_the_value_of_its_bool_argument(){
assert true 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_select
key_sizeof key_sizeof
key_likely key_likely
key_unlikely
key_offsetof key_offsetof
key_struct key_struct
key_switch key_switch
@ -220,6 +221,7 @@ fn build_token_str() []string {
s[Kind.key_module] = 'module' s[Kind.key_module] = 'module'
s[Kind.key_sizeof] = 'sizeof' s[Kind.key_sizeof] = 'sizeof'
s[Kind.key_likely] = '_likely_' s[Kind.key_likely] = '_likely_'
s[Kind.key_unlikely] = '_unlikely_'
s[Kind.key_go] = 'go' s[Kind.key_go] = 'go'
s[Kind.key_goto] = 'goto' s[Kind.key_goto] = 'goto'
s[Kind.key_const] = 'const' s[Kind.key_const] = 'const'