From b45e793c5118d675900b77eda3241eddecbfa67f Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Thu, 23 Apr 2020 13:22:37 -0700 Subject: [PATCH] printf functionality in the API files. --- gapil/README.md | 5 +++++ gapil/bapi/bapi.proto | 10 +++++++++- gapil/bapi/decode.go | 14 ++++++++++++++ gapil/bapi/encode.go | 16 ++++++++++++++++ gapil/resolver/internal.go | 15 +++++++++++++++ gapil/semantic/interface_test.go | 2 ++ gapil/semantic/internal.go | 9 +++++++++ gapil/semantic/printer/printer.go | 4 ++++ gapil/semantic/visit.go | 4 ++++ gapil/template/types.go | 1 + gapis/api/templates/api_spy.cpp.tmpl | 15 ++++++++++++++- gapis/api/templates/mutate.go.tmpl | 15 +++++++++++++++ gapis/api/test/BUILD.bazel | 1 + 13 files changed, 109 insertions(+), 2 deletions(-) diff --git a/gapil/README.md b/gapil/README.md index dc9f0b001..9fd91419f 100644 --- a/gapil/README.md +++ b/gapil/README.md @@ -226,6 +226,11 @@ simple, and may fail with a compilation error if a single insertion point cannot be found. In these cases you should explicitly add a `fence` statement to the command. +##### print(fmt, ...) + +`print` can be used for debugging and will issue printf like logging calls to +print messages and values to the log. + ## Annotations An annotation is a custom attribute that can be placed on named types and diff --git a/gapil/bapi/bapi.proto b/gapil/bapi/bapi.proto index 4747ae4aa..7659c263e 100644 --- a/gapil/bapi/bapi.proto +++ b/gapil/bapi/bapi.proto @@ -84,6 +84,7 @@ message Instances { repeated Parameter parameter = 57; repeated Pointer pointer = 58; repeated PointerRange pointer_range = 59; + repeated Print print = 128; repeated Pseudonym pseudonym = 60; repeated Read read = 61; repeated Reference reference = 62; @@ -686,6 +687,7 @@ message Node { uint64 parameter = 57; // Parameter ID uint64 pointer = 58; // Pointer ID uint64 pointer_range = 59; // PointerRange ID + uint64 print = 81; // Print ID uint64 pseudonym = 60; // Pseudonym ID uint64 read = 61; // Read ID uint64 reference = 62; // Reference ID @@ -728,6 +730,11 @@ message Parameter { Type type = 6; } +message Print { + uint64 ast = 1; // ASTParameter ID + repeated uint64 arguments = 2; // Argument IDs +} + message Pointer { Node owner = 1; uint64 name = 2; // String ID @@ -843,6 +850,7 @@ message Statement { uint64 map_clear = 14; // MapClear ID uint64 map_iteration = 15; // MapIteration ID uint64 map_remove = 16; // MapRemove ID + uint64 print = 22; // Print ID uint64 read = 17; // Read ID uint64 return = 18; // Return ID uint64 slice_assign = 19; // SliceAssign ID @@ -1231,4 +1239,4 @@ message CSTToken { uint64 source = 1; // CSTSource ID uint64 start = 2; uint64 end = 3; -} \ No newline at end of file +} diff --git a/gapil/bapi/decode.go b/gapil/bapi/decode.go index 81105a525..06b6b72ba 100644 --- a/gapil/bapi/decode.go +++ b/gapil/bapi/decode.go @@ -83,6 +83,7 @@ type decoderInstances struct { Parameter []*semantic.Parameter Pointer []*semantic.Pointer PointerRange []*semantic.PointerRange + Print []*semantic.Print Pseudonym []*semantic.Pseudonym Read []*semantic.Read Reference []*semantic.Reference @@ -1002,6 +1003,15 @@ func (d *decoder) pointerRange(ptrRangeID uint64) (out *semantic.PointerRange) { return } +func (d *decoder) print(printID uint64) (out *semantic.Print) { + d.build(d.content.Instances.Print, &d.inst.Print, printID, &out, + func(p *Print, s *semantic.Print) { + s.AST = d.astCall(p.Ast) + foreach(p.Arguments, d.expr, &s.Arguments) + }) + return +} + func (d *decoder) pseudonym(pseudID uint64) (out *semantic.Pseudonym) { d.build(d.content.Instances.Pseudonym, &d.inst.Pseudonym, pseudID, &out, func(p *Pseudonym, s *semantic.Pseudonym) { @@ -1155,6 +1165,8 @@ func (d *decoder) stat(statID uint64) semantic.Statement { return d.mapRemove(p.MapRemove) case *Statement_MapClear: return d.mapClear(p.MapClear) + case *Statement_Print: + return d.print(p.Print) case *Statement_Read: return d.read(p.Read) case *Statement_Return: @@ -1294,6 +1306,8 @@ func (d *decoder) node(p *Node) semantic.Node { return d.pointer(p.Pointer) case *Node_Pseudonym: return d.pseudonym(p.Pseudonym) + case *Node_Print: + return d.print(p.Print) case *Node_Read: return d.read(p.Read) case *Node_Reference: diff --git a/gapil/bapi/encode.go b/gapil/bapi/encode.go index 6dfdcf875..40c088fc9 100644 --- a/gapil/bapi/encode.go +++ b/gapil/bapi/encode.go @@ -89,6 +89,7 @@ type encoderInstances struct { Parameter map[*semantic.Parameter]uint64 Pointer map[*semantic.Pointer]uint64 PointerRange map[*semantic.PointerRange]uint64 + Print map[*semantic.Print]uint64 Pseudonym map[*semantic.Pseudonym]uint64 Read map[*semantic.Read]uint64 Reference map[*semantic.Reference]uint64 @@ -339,6 +340,8 @@ func (e *encoder) node(n semantic.Node) *Node { return &Node{Ty: &Node_PointerRange{PointerRange: e.pointerRange(n)}} case *semantic.Pseudonym: return &Node{Ty: &Node_Pseudonym{Pseudonym: e.pseudonym(n)}} + case *semantic.Print: + return &Node{Ty: &Node_Print{Print: e.print(n)}} case *semantic.Read: return &Node{Ty: &Node_Read{Read: e.read(n)}} case *semantic.Reference: @@ -1236,6 +1239,17 @@ func (e *encoder) pointerRange(n *semantic.PointerRange) (outID uint64) { return } +func (e *encoder) print(n *semantic.Print) (outID uint64) { + e.build(&e.instances.Print, e.maps.Print, n, &outID, func() *Print { + p := &Print{ + Ast: e.astCall(n.AST), + } + foreach(n.Arguments, e.expr, &p.Arguments) + return p + }) + return +} + func (e *encoder) pseudonym(n *semantic.Pseudonym) (outID uint64) { e.build(&e.instances.Pseudonym, e.maps.Pseudonym, n, &outID, func() *Pseudonym { n.SortMembers() @@ -1391,6 +1405,8 @@ func (e *encoder) stat(n semantic.Statement) (outID uint64) { p.Ty = &Statement_MapRemove{e.mapRemove(n)} case *semantic.MapClear: p.Ty = &Statement_MapClear{e.mapClear(n)} + case *semantic.Print: + p.Ty = &Statement_Print{e.print(n)} case *semantic.Read: p.Ty = &Statement_Read{e.read(n)} case *semantic.Return: diff --git a/gapil/resolver/internal.go b/gapil/resolver/internal.go index b57edd033..4062383eb 100644 --- a/gapil/resolver/internal.go +++ b/gapil/resolver/internal.go @@ -33,6 +33,7 @@ func init() { internals["write"] = func(rv *resolver, in *ast.Call, g *ast.Generic) semantic.Node { return write(rv, in, g) } internals["copy"] = func(rv *resolver, in *ast.Call, g *ast.Generic) semantic.Node { return copy_(rv, in, g) } internals["len"] = func(rv *resolver, in *ast.Call, g *ast.Generic) semantic.Node { return length(rv, in, g) } + internals["print"] = func(rv *resolver, in *ast.Call, g *ast.Generic) semantic.Node { return print(rv, in, g) } } func internalCall(rv *resolver, in *ast.Call) semantic.Node { @@ -229,3 +230,17 @@ func length(rv *resolver, in *ast.Call, g *ast.Generic) semantic.Expression { rv.mappings.Add(in, out) return out } + +func print(rv *resolver, in *ast.Call, g *ast.Generic) semantic.Statement { + out := &semantic.Print{AST: in} + + for i, a := range in.Arguments { + arg := expression(rv, a) + if isVoid(arg.ExpressionType()) { + rv.errorf(a, "argument %d to print is void", i) + return semantic.Invalid{} + } + out.Arguments = append(out.Arguments, arg) + } + return out +} diff --git a/gapil/semantic/interface_test.go b/gapil/semantic/interface_test.go index b2c81dbe4..88e756e76 100644 --- a/gapil/semantic/interface_test.go +++ b/gapil/semantic/interface_test.go @@ -70,6 +70,7 @@ var ( &semantic.Parameter{}, &semantic.Pointer{}, &semantic.PointerRange{}, + &semantic.Print{}, &semantic.Pseudonym{}, &semantic.Read{}, &semantic.Reference{}, @@ -171,6 +172,7 @@ var ( &semantic.MapIteration{}, &semantic.MapRemove{}, &semantic.MapClear{}, + &semantic.Print{}, &semantic.Read{}, &semantic.Return{}, &semantic.SliceAssign{}, diff --git a/gapil/semantic/internal.go b/gapil/semantic/internal.go index 8f23d7468..7507874c2 100644 --- a/gapil/semantic/internal.go +++ b/gapil/semantic/internal.go @@ -133,3 +133,12 @@ type Copy struct { func (*Copy) isNode() {} func (*Copy) isStatement() {} + +// Print represents a call to print. +type Print struct { + AST *ast.Call // the underlying syntax node this was built from + Arguments []Expression // The parameters to print +} + +func (*Print) isNode() {} +func (*Print) isStatement() {} diff --git a/gapil/semantic/printer/printer.go b/gapil/semantic/printer/printer.go index 67a0492ba..7ae1a7979 100644 --- a/gapil/semantic/printer/printer.go +++ b/gapil/semantic/printer/printer.go @@ -376,6 +376,10 @@ func (p *Printer) statement(n interface{}) bool { p.WriteString(", ") p.WriteExpression(n.Src) p.WriteRune(')') + case *semantic.Print: + p.WriteString("print(") + p.list(n.Arguments, p.WriteExpression) + p.WriteRune(')') case *semantic.Switch: p.WriteString("switch ") p.WriteExpression(n.Value) diff --git a/gapil/semantic/visit.go b/gapil/semantic/visit.go index 50ff36abd..6fdf171e0 100644 --- a/gapil/semantic/visit.go +++ b/gapil/semantic/visit.go @@ -330,6 +330,10 @@ func Replace(node Node, visitor func(Node) Node) { n.Type = visitor(n.Type).(*Slice) n.Size = visitor(n.Size).(Expression) case Null: + case *Print: + for i, a := range n.Arguments { + n.Arguments[i] = visitor(a).(Expression) + } case *PointerRange: n.Pointer = visitor(n.Pointer).(Expression) n.Range = visitor(n.Range).(*BinaryOp) diff --git a/gapil/template/types.go b/gapil/template/types.go index d5f2a922f..47f7592a8 100644 --- a/gapil/template/types.go +++ b/gapil/template/types.go @@ -96,6 +96,7 @@ var ( semantic.Parameter{}, semantic.PointerRange{}, semantic.Pointer{}, + semantic.Print{}, semantic.Pseudonym{}, semantic.Read{}, semantic.Reference{}, diff --git a/gapis/api/templates/api_spy.cpp.tmpl b/gapis/api/templates/api_spy.cpp.tmpl index 323923a0a..0033516a7 100644 --- a/gapis/api/templates/api_spy.cpp.tmpl +++ b/gapis/api/templates/api_spy.cpp.tmpl @@ -341,6 +341,7 @@ {{else if IsAssign $}}{{Template "Assign" $}} {{else if IsSliceAssign $}}{{Template "SliceAssign" $}} {{else if IsCall $}}{{Template "CallSub" $}} + {{else if IsPrint $}}{{Template "Print" $}} {{else }}{{Template "C++.Statement.Default" $}} {{end}} {{end}} @@ -468,4 +469,16 @@ {{else}} {{Template "C++.Statement.Default" $}} {{end}} -{{end}} \ No newline at end of file +{{end}} + + +{{/* +------------------------------------------------------------------------------- + Emits the logic to execute a print statement +------------------------------------------------------------------------------- +*/}} +{{define "Print"}} + {{AssertType $ "Print"}} + + GAPID_DEBUG({{Macro "C++.ReadListAsCallArgument" $.Arguments}}); +{{end}} diff --git a/gapis/api/templates/mutate.go.tmpl b/gapis/api/templates/mutate.go.tmpl index 54a0a3460..57346cc3e 100644 --- a/gapis/api/templates/mutate.go.tmpl +++ b/gapis/api/templates/mutate.go.tmpl @@ -27,6 +27,7 @@ "strings" "github.com/google/gapid/core/event/task" + "github.com/google/gapid/core/log" "github.com/google/gapid/core/math/u64" "github.com/google/gapid/gapis/api" "github.com/google/gapid/gapis/messages" @@ -47,6 +48,7 @@ _ = stringtable.Msg{} _ = ϟmem.Decoder{} _ = u64.Min + _ = log.Verbose ) type callable interface { @@ -356,6 +358,7 @@ {{else if IsFence $}}{{Template "Fence" $}} {{else if IsBranch $}}{{Template "Branch" $}} {{else if IsSwitch $}}{{Template "Switch" $}} + {{else if IsPrint $}}{{Template "Print" $}} {{else}}{{Error "unsupported statement %T: %v" $ $}} {{end}} {{end}} @@ -715,3 +718,15 @@ _ = {{Template "Go.Read" $.Value}} {{end}} {{end}} + +{{/* +------------------------------------------------------------------------------- + Emits the logic to execute a print statement +------------------------------------------------------------------------------- +*/}} +{{define "Print"}} + {{AssertType $ "Print"}} + + {{$args := ForEach $.Arguments "Go.Read" | JoinWith ", "}} + log.I(ϟctx, {{$args}}) +{{end}} diff --git a/gapis/api/test/BUILD.bazel b/gapis/api/test/BUILD.bazel index 102113e66..0e3980a92 100644 --- a/gapis/api/test/BUILD.bazel +++ b/gapis/api/test/BUILD.bazel @@ -54,6 +54,7 @@ go_library( "//core/data/compare:go_default_library", "//core/data/protoconv:go_default_library", # keep "//core/event/task:go_default_library", # keep + "//core/log:go_default_library", # keep "//core/math/interval:go_default_library", "//core/memory/arena:go_default_library", # keep "//gapil/constset:go_default_library", # keep