perf: DO WHILE/SEEK/DELETE WA hoisting — reduce per-iteration lookups
DO WHILE optimization: - Detect RDD commands in body (SKIP/GO/SEEK/REPLACE/DELETE) - If no USE/SELECT (safe), hoist _dwa/_darea before loop - SKIP/GO/SEEK/DELETE inside loop use cached area variable - Eliminates WA lookup + Current() per iteration SEEK optimization: - Use hoisted area when inside DO WHILE or FOR hoist context - Eliminates WA lookup per SEEK call in tight loops DELETE optimization: - Use hoisted area when available All commands now check g.hoistedDW || g.hoistedFields: - GO TOP/BOTTOM/n → cached area - SKIP n → cached area - SEEK key → cached area + Indexer check - DELETE → cached area - APPEND → cached area (FOR loop) - REPLACE → cached _rdbf + _rfiN (FOR loop) 82/82 stress PASS. 14 packages ALL PASS. CDX SCOPE: 12ms (Harbour 4ms = 3x) NTX SCAN: 24ms (Harbour 5ms = 4.8x) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -43,79 +43,110 @@ func (g *Generator) emitUseCmd(s *ast.UseCmd, locals localMap) {
|
||||
}
|
||||
|
||||
func (g *Generator) emitGoCmd(s *ast.GoCmd) {
|
||||
g.writeln("{")
|
||||
g.indent++
|
||||
g.writeln("wa := t.WA.(*hbrdd.WorkAreaManager)")
|
||||
g.writeln("if _area := wa.Current(); _area != nil {")
|
||||
g.indent++
|
||||
// Use hoisted area if available
|
||||
areaVar := "_area"
|
||||
if g.hoistedDW || g.hoistedFields != nil {
|
||||
areaVar = g.hoistedAreaVar()
|
||||
g.writeln(fmt.Sprintf("if %s != nil {", areaVar))
|
||||
g.indent++
|
||||
} else {
|
||||
g.writeln("{")
|
||||
g.indent++
|
||||
g.writeln("wa := t.WA.(*hbrdd.WorkAreaManager)")
|
||||
g.writeln(fmt.Sprintf("if %s := wa.Current(); %s != nil {", areaVar, areaVar))
|
||||
g.indent++
|
||||
}
|
||||
|
||||
switch s.Direction {
|
||||
case "TOP":
|
||||
g.writeln("_area.GoTop()")
|
||||
g.writeln(fmt.Sprintf("%s.GoTop()", areaVar))
|
||||
case "BOTTOM":
|
||||
g.writeln("_area.GoBottom()")
|
||||
g.writeln(fmt.Sprintf("%s.GoBottom()", areaVar))
|
||||
default:
|
||||
if s.RecNo != nil {
|
||||
// Optimize: literal integers skip stack ops
|
||||
if lit, ok := s.RecNo.(*ast.LiteralExpr); ok && lit.Kind == token.INT {
|
||||
g.writeln(fmt.Sprintf("_area.GoTo(uint32(%s))", lit.Value))
|
||||
g.writeln(fmt.Sprintf("%s.GoTo(uint32(%s))", areaVar, lit.Value))
|
||||
} else {
|
||||
g.emitExpr(s.RecNo)
|
||||
g.writeln("_area.GoTo(uint32(t.Pop2().AsNumInt()))")
|
||||
g.writeln(fmt.Sprintf("%s.GoTo(uint32(t.Pop2().AsNumInt()))", areaVar))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g.indent--
|
||||
g.writeln("}")
|
||||
g.indent--
|
||||
g.writeln("}")
|
||||
if !g.hoistedDW && g.hoistedFields == nil {
|
||||
g.indent--
|
||||
g.writeln("}")
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) emitSkipCmd(s *ast.SkipCmd, locals localMap) {
|
||||
g.writeln("{")
|
||||
g.indent++
|
||||
g.writeln("wa := t.WA.(*hbrdd.WorkAreaManager)")
|
||||
g.writeln("if _area := wa.Current(); _area != nil {")
|
||||
g.indent++
|
||||
areaVar := "_area"
|
||||
if g.hoistedDW || g.hoistedFields != nil {
|
||||
areaVar = g.hoistedAreaVar()
|
||||
g.writeln(fmt.Sprintf("if %s != nil {", areaVar))
|
||||
g.indent++
|
||||
} else {
|
||||
g.writeln("{")
|
||||
g.indent++
|
||||
g.writeln("wa := t.WA.(*hbrdd.WorkAreaManager)")
|
||||
g.writeln(fmt.Sprintf("if %s := wa.Current(); %s != nil {", areaVar, areaVar))
|
||||
g.indent++
|
||||
}
|
||||
|
||||
if s.Count != nil {
|
||||
// Optimize: literal skip count avoids stack ops
|
||||
if lit, ok := s.Count.(*ast.LiteralExpr); ok && lit.Kind == token.INT {
|
||||
g.writeln(fmt.Sprintf("_area.Skip(%s)", lit.Value))
|
||||
g.writeln(fmt.Sprintf("%s.Skip(%s)", areaVar, lit.Value))
|
||||
} else if unary, ok := s.Count.(*ast.UnaryExpr); ok {
|
||||
if lit2, ok2 := unary.X.(*ast.LiteralExpr); ok2 && lit2.Kind == token.INT {
|
||||
g.writeln(fmt.Sprintf("_area.Skip(-%s)", lit2.Value))
|
||||
g.writeln(fmt.Sprintf("%s.Skip(-%s)", areaVar, lit2.Value))
|
||||
} else {
|
||||
g.emitExpr(s.Count)
|
||||
g.writeln("_area.Skip(t.Pop2().AsNumInt())")
|
||||
g.writeln(fmt.Sprintf("%s.Skip(t.Pop2().AsNumInt())", areaVar))
|
||||
}
|
||||
} else {
|
||||
g.emitExpr(s.Count)
|
||||
g.writeln("_area.Skip(t.Pop2().AsNumInt())")
|
||||
g.writeln(fmt.Sprintf("%s.Skip(t.Pop2().AsNumInt())", areaVar))
|
||||
}
|
||||
} else {
|
||||
g.writeln("_area.Skip(1)")
|
||||
g.writeln(fmt.Sprintf("%s.Skip(1)", areaVar))
|
||||
}
|
||||
|
||||
g.indent--
|
||||
g.writeln("}")
|
||||
g.indent--
|
||||
g.writeln("}")
|
||||
if !g.hoistedDW && g.hoistedFields == nil {
|
||||
g.indent--
|
||||
g.writeln("}")
|
||||
}
|
||||
}
|
||||
|
||||
// hoistedAreaVar returns the area variable name for the current hoisting context.
|
||||
func (g *Generator) hoistedAreaVar() string {
|
||||
if g.hoistedFields != nil {
|
||||
return "_rarea"
|
||||
}
|
||||
return "_darea"
|
||||
}
|
||||
|
||||
func (g *Generator) emitSeekCmd(s *ast.SeekCmd, locals localMap) {
|
||||
g.writeln("{")
|
||||
g.indent++
|
||||
g.writeln("wa := t.WA.(*hbrdd.WorkAreaManager)")
|
||||
g.writeln("if area := wa.Current(); area != nil {")
|
||||
g.indent++
|
||||
areaVar := "area"
|
||||
if g.hoistedDW || g.hoistedFields != nil {
|
||||
areaVar = g.hoistedAreaVar()
|
||||
g.writeln(fmt.Sprintf("if %s != nil {", areaVar))
|
||||
g.indent++
|
||||
} else {
|
||||
g.writeln("{")
|
||||
g.indent++
|
||||
g.writeln("wa := t.WA.(*hbrdd.WorkAreaManager)")
|
||||
g.writeln(fmt.Sprintf("if %s := wa.Current(); %s != nil {", areaVar, areaVar))
|
||||
g.indent++
|
||||
}
|
||||
|
||||
g.emitExpr(s.Key)
|
||||
g.writeln("_key := t.Pop2()")
|
||||
g.writeln("if _idx, ok := area.(hbrdd.Indexer); ok {")
|
||||
g.writeln(fmt.Sprintf("if _idx, ok := %s.(hbrdd.Indexer); ok {", areaVar))
|
||||
g.indent++
|
||||
// SoftSeek: from SEEK SOFT keyword OR runtime SET SOFTSEEK
|
||||
if s.SoftSeek {
|
||||
g.writeln("_found, _ := _idx.Seek(_key, true, false)")
|
||||
} else {
|
||||
@@ -127,8 +158,10 @@ func (g *Generator) emitSeekCmd(s *ast.SeekCmd, locals localMap) {
|
||||
|
||||
g.indent--
|
||||
g.writeln("}")
|
||||
g.indent--
|
||||
g.writeln("}")
|
||||
if !g.hoistedDW && g.hoistedFields == nil {
|
||||
g.indent--
|
||||
g.writeln("}")
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) emitReplaceCmd(s *ast.ReplaceCmd, locals localMap) {
|
||||
|
||||
@@ -38,6 +38,7 @@ type Generator struct {
|
||||
staticVars map[string]string // top-level STATIC: upper name → Go var name
|
||||
IsLibrary bool // if true, no main() generated, symbols use unique name
|
||||
hoistedFields []string // field names hoisted outside FOR loop (nil = not hoisting)
|
||||
hoistedDW bool // DO WHILE has hoisted _dwa/_darea
|
||||
Debug bool // if true, emit t.DebugLine() calls
|
||||
}
|
||||
|
||||
@@ -465,8 +466,12 @@ func (g *Generator) emitStmt(stmt ast.Stmt, locals localMap) {
|
||||
g.writeln("if _area := _wa.Current(); _area != nil { _area.Append() } }")
|
||||
}
|
||||
case *ast.DeleteCmd:
|
||||
g.writeln("{ _wa := t.WA.(*hbrdd.WorkAreaManager)")
|
||||
g.writeln("if _area := _wa.Current(); _area != nil { _area.Delete() } }")
|
||||
if g.hoistedDW || g.hoistedFields != nil {
|
||||
g.writeln(fmt.Sprintf("if %s != nil { %s.Delete() }", g.hoistedAreaVar(), g.hoistedAreaVar()))
|
||||
} else {
|
||||
g.writeln("{ _wa := t.WA.(*hbrdd.WorkAreaManager)")
|
||||
g.writeln("if _area := _wa.Current(); _area != nil { _area.Delete() } }")
|
||||
}
|
||||
case *ast.SelectCmd:
|
||||
g.emitExpr(s.Area)
|
||||
g.writeln("{ _wa := t.WA.(*hbrdd.WorkAreaManager); _v := t.Pop2()")
|
||||
@@ -854,6 +859,18 @@ func (g *Generator) emitIf(s *ast.IfStmt, locals localMap) {
|
||||
}
|
||||
|
||||
func (g *Generator) emitDoWhile(s *ast.DoWhileStmt, locals localMap) {
|
||||
// Detect RDD commands in body for WA hoisting
|
||||
hasRDD := hasRDDCommands(s.Body)
|
||||
safeToHoist := hasRDD && !hasWorkareaChange(s.Body)
|
||||
|
||||
if safeToHoist && g.hoistedFields == nil {
|
||||
g.writeln("{")
|
||||
g.indent++
|
||||
g.writeln("_dwa := t.WA.(*hbrdd.WorkAreaManager)")
|
||||
g.writeln("_darea := _dwa.Current()")
|
||||
g.hoistedDW = true
|
||||
}
|
||||
|
||||
g.writeln("for {")
|
||||
g.indent++
|
||||
g.emitExpr(s.Cond)
|
||||
@@ -863,6 +880,43 @@ func (g *Generator) emitDoWhile(s *ast.DoWhileStmt, locals localMap) {
|
||||
}
|
||||
g.indent--
|
||||
g.writeln("}")
|
||||
|
||||
if safeToHoist && g.hoistedDW {
|
||||
g.hoistedDW = false
|
||||
g.indent--
|
||||
g.writeln("}")
|
||||
}
|
||||
}
|
||||
|
||||
// hasRDDCommands checks if any statement is an RDD operation.
|
||||
func hasRDDCommands(stmts []ast.Stmt) bool {
|
||||
for _, s := range stmts {
|
||||
switch s.(type) {
|
||||
case *ast.SkipCmd, *ast.GoCmd, *ast.SeekCmd,
|
||||
*ast.ReplaceCmd, *ast.AppendCmd, *ast.DeleteCmd:
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// hasWorkareaChange checks for USE/SELECT that would invalidate cached area.
|
||||
func hasWorkareaChange(stmts []ast.Stmt) bool {
|
||||
for _, s := range stmts {
|
||||
switch v := s.(type) {
|
||||
case *ast.UseCmd, *ast.SelectCmd:
|
||||
return true
|
||||
case *ast.IfStmt:
|
||||
if hasWorkareaChange(v.Body) || hasWorkareaChange(v.ElseBody) {
|
||||
return true
|
||||
}
|
||||
case *ast.DoWhileStmt:
|
||||
if hasWorkareaChange(v.Body) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// collectReplaceFields scans statements for REPLACE field names.
|
||||
|
||||
Reference in New Issue
Block a user