v: add full compiler support for _likely_(x)
parent
6663e94780
commit
c7d4360931
16
doc/docs.md
16
doc/docs.md
|
@ -1684,6 +1684,22 @@ vm := vmod.decode( @VMOD_FILE ) or { panic(err) }
|
|||
eprintln('$vm.name $vm.version\n $vm.description')
|
||||
```
|
||||
|
||||
## Performance tuning
|
||||
|
||||
The generated C code is usually fast enough. Although rarely, there
|
||||
are some situations though, where you want to give additional hints
|
||||
to the C compiler, so that it can further optimize some blocks of code.
|
||||
NB: these are *rarely* needed, and should not be used, unless you
|
||||
profile your code, and see that there are significant benefits for them.
|
||||
|
||||
[inline] - you can tag functions with [inline], and the C compiler will
|
||||
try to inline them, which in some cases, may be beneficial for peformance.
|
||||
|
||||
`if _likely_(bool expression) {` this hints the C compiler, that the passed
|
||||
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.
|
||||
|
||||
## Reflection via codegen
|
||||
|
||||
Having built-in JSON support is nice, but V also allows you to create efficient
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
module builtin
|
||||
|
||||
// See cheaders.v: _likely_ is actually a macro, to hint the C compiler
|
||||
// that the passed boolean expression is very likely to be true, so it
|
||||
// can generate assembly code, with less chance of branch misprediction.
|
||||
fn C._likely_(bool) bool
|
||||
|
||||
// <string.h>
|
||||
fn C.memcpy(byteptr, byteptr, int) voidptr
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ pub type Expr = AnonFn | ArrayInit | AsCast | AssignExpr | Assoc | BoolLiteral |
|
|||
CastExpr | CharLiteral | ComptimeCall | ConcatExpr | EnumVal | FloatLiteral | Ident | IfExpr |
|
||||
IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | MapInit | MatchExpr | None | OrExpr |
|
||||
ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectorExpr | SizeOf | StringInterLiteral |
|
||||
StringLiteral | StructInit | Type | TypeOf
|
||||
StringLiteral | StructInit | Type | TypeOf | Likely
|
||||
|
||||
pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompIf | ConstDecl |
|
||||
DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt |
|
||||
|
@ -755,6 +755,12 @@ pub:
|
|||
type_name string
|
||||
}
|
||||
|
||||
pub struct Likely {
|
||||
pub:
|
||||
expr Expr
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub struct TypeOf {
|
||||
pub:
|
||||
expr Expr
|
||||
|
@ -888,6 +894,9 @@ pub fn (expr Expr) position() token.Position {
|
|||
StructInit {
|
||||
return it.pos
|
||||
}
|
||||
Likely {
|
||||
return it.pos
|
||||
}
|
||||
// ast.TypeOf { }
|
||||
else {
|
||||
return token.Position{}
|
||||
|
|
|
@ -163,6 +163,9 @@ pub fn (x Expr) str() string {
|
|||
TypeOf {
|
||||
return 'typeof(${it.expr.str()})'
|
||||
}
|
||||
Likely {
|
||||
return '_likely_(${it.expr.str()})'
|
||||
}
|
||||
else {
|
||||
return '[unhandled expr type ${typeof(x)}]'
|
||||
}
|
||||
|
|
|
@ -1772,7 +1772,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||
c.error('checker: too many expr levels: $c.expr_level ', node.position())
|
||||
return table.void_type
|
||||
}
|
||||
|
||||
|
||||
match mut node {
|
||||
ast.AnonFn {
|
||||
keep_fn := c.cur_fn
|
||||
|
@ -1944,6 +1944,14 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||
it.expr_type = c.expr(it.expr)
|
||||
return table.string_type
|
||||
}
|
||||
ast.Likely {
|
||||
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)
|
||||
}
|
||||
return table.bool_type
|
||||
}
|
||||
else {
|
||||
tnode := typeof(node)
|
||||
if tnode != 'unknown v.ast.Expr' {
|
||||
|
|
|
@ -734,6 +734,11 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
|
|||
f.expr(it.expr)
|
||||
f.write(')')
|
||||
}
|
||||
ast.Likely {
|
||||
f.write('_likely_(')
|
||||
f.expr(it.expr)
|
||||
f.write(')')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1586,6 +1586,11 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||
ast.TypeOf {
|
||||
g.typeof_expr(it)
|
||||
}
|
||||
ast.Likely {
|
||||
g.write('_likely_(')
|
||||
g.expr(it.expr)
|
||||
g.write(')')
|
||||
}
|
||||
else {
|
||||
// #printf("node=%d\n", node.typ);
|
||||
println(term.red('cgen.expr(): bad node ' + typeof(node)))
|
||||
|
|
|
@ -627,6 +627,11 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
// skip: JS has no types
|
||||
// TODO maybe?
|
||||
}
|
||||
ast.Likely {
|
||||
g.write('(')
|
||||
g.expr(it.expr)
|
||||
g.write(')')
|
||||
}
|
||||
ast.TypeOf {
|
||||
g.gen_typeof_expr(it)
|
||||
// TODO: Should this print the V type or the JS type?
|
||||
|
|
|
@ -103,6 +103,17 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
|
|||
expr: expr
|
||||
}
|
||||
}
|
||||
.key_likely {
|
||||
p.next()
|
||||
p.check(.lpar)
|
||||
lpos := p.tok.position()
|
||||
expr := p.expr(0)
|
||||
p.check(.rpar)
|
||||
node = ast.Likely{
|
||||
expr: expr
|
||||
pos: lpos
|
||||
}
|
||||
}
|
||||
.lcbr {
|
||||
// Map `{"age": 20}` or `{ x | foo:bar, a:10 }`
|
||||
p.next()
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// _likely_(expr) should be compilable, and it should return the expr
|
||||
|
||||
fn test_likely_type(){
|
||||
assert typeof(_likely_(false)) == 'bool'
|
||||
}
|
||||
|
||||
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(){
|
||||
i := 123
|
||||
if _likely_(i<2) {
|
||||
assert false
|
||||
} else {
|
||||
assert true
|
||||
}
|
||||
}
|
|
@ -112,6 +112,7 @@ pub enum Kind {
|
|||
key_return
|
||||
key_select
|
||||
key_sizeof
|
||||
key_likely
|
||||
key_offsetof
|
||||
key_struct
|
||||
key_switch
|
||||
|
@ -218,6 +219,7 @@ fn build_token_str() []string {
|
|||
s[Kind.key_return] = 'return'
|
||||
s[Kind.key_module] = 'module'
|
||||
s[Kind.key_sizeof] = 'sizeof'
|
||||
s[Kind.key_likely] = '_likely_'
|
||||
s[Kind.key_go] = 'go'
|
||||
s[Kind.key_goto] = 'goto'
|
||||
s[Kind.key_const] = 'const'
|
||||
|
|
Loading…
Reference in New Issue