constant folding 2
This commit is contained in:
parent
cf9f3af3f1
commit
121774005b
File diff suppressed because it is too large
Load Diff
@ -173,7 +173,7 @@ func (cs *CompilerState) AddUpvalue(index uint8, isLocal bool) int {
|
|||||||
return upvalueCount
|
return upvalueCount
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimized constant pool management with deduplication
|
// Enhanced constant pool management with better deduplication
|
||||||
func (cs *CompilerState) AddConstant(value Value) int {
|
func (cs *CompilerState) AddConstant(value Value) int {
|
||||||
// Generate unique key for deduplication
|
// Generate unique key for deduplication
|
||||||
key := cs.valueKey(value)
|
key := cs.valueKey(value)
|
||||||
@ -191,7 +191,7 @@ func (cs *CompilerState) AddConstant(value Value) int {
|
|||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate unique key for value deduplication
|
// Enhanced value key generation for better deduplication
|
||||||
func (cs *CompilerState) valueKey(value Value) string {
|
func (cs *CompilerState) valueKey(value Value) string {
|
||||||
switch value.Type {
|
switch value.Type {
|
||||||
case ValueNil:
|
case ValueNil:
|
||||||
@ -202,15 +202,41 @@ func (cs *CompilerState) valueKey(value Value) string {
|
|||||||
}
|
}
|
||||||
return "bool:false"
|
return "bool:false"
|
||||||
case ValueNumber:
|
case ValueNumber:
|
||||||
return fmt.Sprintf("number:%g", value.Data.(float64))
|
num := value.Data.(float64)
|
||||||
|
// Handle special numeric values
|
||||||
|
if num == 0 {
|
||||||
|
return "number:0"
|
||||||
|
} else if num == 1 {
|
||||||
|
return "number:1"
|
||||||
|
} else if num == -1 {
|
||||||
|
return "number:-1"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("number:%g", num)
|
||||||
case ValueString:
|
case ValueString:
|
||||||
return fmt.Sprintf("string:%s", value.Data.(string))
|
str := value.Data.(string)
|
||||||
|
if str == "" {
|
||||||
|
return "string:empty"
|
||||||
|
}
|
||||||
|
// For very long strings, just use a hash to avoid memory issues
|
||||||
|
if len(str) > 100 {
|
||||||
|
return fmt.Sprintf("string:hash:%d", cs.simpleHash(str))
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("string:%s", str)
|
||||||
default:
|
default:
|
||||||
// For complex types, use memory address as fallback
|
// For complex types, use memory address as fallback
|
||||||
return fmt.Sprintf("%T:%p", value.Data, value.Data)
|
return fmt.Sprintf("%T:%p", value.Data, value.Data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simple hash function for long strings
|
||||||
|
func (cs *CompilerState) simpleHash(s string) uint32 {
|
||||||
|
var hash uint32
|
||||||
|
for _, c := range s {
|
||||||
|
hash = hash*31 + uint32(c)
|
||||||
|
}
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
// Optimized bytecode emission methods
|
// Optimized bytecode emission methods
|
||||||
func (cs *CompilerState) EmitByte(byte uint8) {
|
func (cs *CompilerState) EmitByte(byte uint8) {
|
||||||
cs.Chunk.Code = append(cs.Chunk.Code, byte)
|
cs.Chunk.Code = append(cs.Chunk.Code, byte)
|
||||||
@ -240,7 +266,7 @@ func (cs *CompilerState) PatchJump(offset int) {
|
|||||||
jump := len(cs.Chunk.Code) - offset - 2
|
jump := len(cs.Chunk.Code) - offset - 2
|
||||||
|
|
||||||
if jump > 65535 {
|
if jump > 65535 {
|
||||||
// Jump distance too large - would need to implement long jumps
|
// Jump distance too large - could implement long jumps here
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,7 +378,7 @@ func (cs *CompilerState) EmitStoreLocal(slot int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instruction pattern detection for optimization
|
// Enhanced instruction pattern detection for optimization
|
||||||
func (cs *CompilerState) GetLastInstruction() (Opcode, []uint16) {
|
func (cs *CompilerState) GetLastInstruction() (Opcode, []uint16) {
|
||||||
if len(cs.Chunk.Code) == 0 {
|
if len(cs.Chunk.Code) == 0 {
|
||||||
return OpNoop, nil
|
return OpNoop, nil
|
||||||
@ -367,8 +393,10 @@ func (cs *CompilerState) GetLastInstruction() (Opcode, []uint16) {
|
|||||||
// This is a complete instruction
|
// This is a complete instruction
|
||||||
operands := make([]uint16, operandCount)
|
operands := make([]uint16, operandCount)
|
||||||
for j := 0; j < operandCount; j++ {
|
for j := 0; j < operandCount; j++ {
|
||||||
operands[j] = uint16(cs.Chunk.Code[i+1+j*2]) |
|
if i+1+j*2 < len(cs.Chunk.Code) && i+2+j*2 < len(cs.Chunk.Code) {
|
||||||
(uint16(cs.Chunk.Code[i+2+j*2]) << 8)
|
operands[j] = uint16(cs.Chunk.Code[i+1+j*2]) |
|
||||||
|
(uint16(cs.Chunk.Code[i+2+j*2]) << 8)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return op, operands
|
return op, operands
|
||||||
}
|
}
|
||||||
@ -402,50 +430,6 @@ func (cs *CompilerState) ReplaceLastInstruction(op Opcode, operands ...uint16) b
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constant folding support
|
|
||||||
func (cs *CompilerState) TryConstantFolding(op Opcode, operands ...Value) *Value {
|
|
||||||
if len(operands) < 2 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
left, right := operands[0], operands[1]
|
|
||||||
|
|
||||||
// Only fold numeric operations for now
|
|
||||||
if left.Type != ValueNumber || right.Type != ValueNumber {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
l := left.Data.(float64)
|
|
||||||
r := right.Data.(float64)
|
|
||||||
|
|
||||||
switch op {
|
|
||||||
case OpAdd:
|
|
||||||
return &Value{Type: ValueNumber, Data: l + r}
|
|
||||||
case OpSub:
|
|
||||||
return &Value{Type: ValueNumber, Data: l - r}
|
|
||||||
case OpMul:
|
|
||||||
return &Value{Type: ValueNumber, Data: l * r}
|
|
||||||
case OpDiv:
|
|
||||||
if r != 0 {
|
|
||||||
return &Value{Type: ValueNumber, Data: l / r}
|
|
||||||
}
|
|
||||||
case OpEq:
|
|
||||||
return &Value{Type: ValueBool, Data: l == r}
|
|
||||||
case OpNeq:
|
|
||||||
return &Value{Type: ValueBool, Data: l != r}
|
|
||||||
case OpLt:
|
|
||||||
return &Value{Type: ValueBool, Data: l < r}
|
|
||||||
case OpLte:
|
|
||||||
return &Value{Type: ValueBool, Data: l <= r}
|
|
||||||
case OpGt:
|
|
||||||
return &Value{Type: ValueBool, Data: l > r}
|
|
||||||
case OpGte:
|
|
||||||
return &Value{Type: ValueBool, Data: l >= r}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dead code elimination support
|
// Dead code elimination support
|
||||||
func (cs *CompilerState) MarkUnreachable(start, end int) {
|
func (cs *CompilerState) MarkUnreachable(start, end int) {
|
||||||
if start >= 0 && end <= len(cs.Chunk.Code) {
|
if start >= 0 && end <= len(cs.Chunk.Code) {
|
||||||
@ -461,12 +445,14 @@ type OptimizationStats struct {
|
|||||||
InstructionsOpt int
|
InstructionsOpt int
|
||||||
DeadCodeEliminated int
|
DeadCodeEliminated int
|
||||||
JumpsOptimized int
|
JumpsOptimized int
|
||||||
|
ConstantsDeduped int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *CompilerState) GetOptimizationStats() OptimizationStats {
|
func (cs *CompilerState) GetOptimizationStats() OptimizationStats {
|
||||||
// Count specialized instructions used
|
// Count specialized instructions used
|
||||||
specialized := 0
|
specialized := 0
|
||||||
noops := 0
|
noops := 0
|
||||||
|
constantsDeduped := len(cs.Constants) - len(cs.Chunk.Constants)
|
||||||
|
|
||||||
for i := 0; i < len(cs.Chunk.Code); {
|
for i := 0; i < len(cs.Chunk.Code); {
|
||||||
op, _, next := DecodeInstruction(cs.Chunk.Code, i)
|
op, _, next := DecodeInstruction(cs.Chunk.Code, i)
|
||||||
@ -482,6 +468,7 @@ func (cs *CompilerState) GetOptimizationStats() OptimizationStats {
|
|||||||
return OptimizationStats{
|
return OptimizationStats{
|
||||||
InstructionsOpt: specialized,
|
InstructionsOpt: specialized,
|
||||||
DeadCodeEliminated: noops,
|
DeadCodeEliminated: noops,
|
||||||
|
ConstantsDeduped: constantsDeduped,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,13 +476,31 @@ func (cs *CompilerState) SetLine(line int) {
|
|||||||
cs.CurrentLine = line
|
cs.CurrentLine = line
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debugging support
|
// Enhanced debugging support
|
||||||
func (cs *CompilerState) PrintChunk(name string) {
|
func (cs *CompilerState) PrintChunk(name string) {
|
||||||
fmt.Printf("== %s ==\n", name)
|
fmt.Printf("== %s ==\n", name)
|
||||||
|
fmt.Printf("Constants: %d\n", len(cs.Chunk.Constants))
|
||||||
|
fmt.Printf("Functions: %d\n", len(cs.Chunk.Functions))
|
||||||
|
fmt.Printf("Structs: %d\n", len(cs.Chunk.Structs))
|
||||||
|
fmt.Printf("Code size: %d bytes\n", len(cs.Chunk.Code))
|
||||||
|
|
||||||
|
stats := cs.GetOptimizationStats()
|
||||||
|
fmt.Printf("Optimizations: %d specialized, %d dead eliminated, %d constants deduped\n",
|
||||||
|
stats.InstructionsOpt, stats.DeadCodeEliminated, stats.ConstantsDeduped)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
for offset := 0; offset < len(cs.Chunk.Code); {
|
for offset := 0; offset < len(cs.Chunk.Code); {
|
||||||
offset = cs.disassembleInstruction(offset)
|
offset = cs.disassembleInstruction(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(cs.Chunk.Constants) > 0 {
|
||||||
|
fmt.Println("\nConstants:")
|
||||||
|
for i, constant := range cs.Chunk.Constants {
|
||||||
|
fmt.Printf("%4d: ", i)
|
||||||
|
cs.printValue(constant)
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *CompilerState) disassembleInstruction(offset int) int {
|
func (cs *CompilerState) disassembleInstruction(offset int) int {
|
||||||
@ -528,12 +533,14 @@ func (cs *CompilerState) disassembleInstruction(offset int) int {
|
|||||||
switch op {
|
switch op {
|
||||||
case OpLoadConst:
|
case OpLoadConst:
|
||||||
return cs.constantInstruction(offset)
|
return cs.constantInstruction(offset)
|
||||||
case OpLoadLocal, OpStoreLocal:
|
case OpLoadLocal, OpStoreLocal, OpAddConst, OpSubConst, OpInc, OpDec:
|
||||||
return cs.byteInstruction(offset)
|
return cs.byteInstruction(offset)
|
||||||
case OpJump, OpJumpIfTrue, OpJumpIfFalse:
|
case OpJump, OpJumpIfTrue, OpJumpIfFalse:
|
||||||
return cs.jumpInstruction(offset, 1)
|
return cs.jumpInstruction(offset, 1)
|
||||||
case OpLoopBack:
|
case OpLoopBack:
|
||||||
return cs.jumpInstruction(offset, -1)
|
return cs.jumpInstruction(offset, -1)
|
||||||
|
case OpGetLocalField, OpSetLocalField, OpTestAndJump:
|
||||||
|
return cs.doubleByteInstruction(offset)
|
||||||
default:
|
default:
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
return offset + 1
|
return offset + 1
|
||||||
@ -570,6 +577,18 @@ func (cs *CompilerState) byteInstruction(offset int) int {
|
|||||||
return offset + 3
|
return offset + 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cs *CompilerState) doubleByteInstruction(offset int) int {
|
||||||
|
if offset+4 >= len(cs.Chunk.Code) {
|
||||||
|
fmt.Println(" [incomplete]")
|
||||||
|
return offset + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
arg1 := uint16(cs.Chunk.Code[offset+1]) | (uint16(cs.Chunk.Code[offset+2]) << 8)
|
||||||
|
arg2 := uint16(cs.Chunk.Code[offset+3]) | (uint16(cs.Chunk.Code[offset+4]) << 8)
|
||||||
|
fmt.Printf(" %4d %4d\n", arg1, arg2)
|
||||||
|
return offset + 5
|
||||||
|
}
|
||||||
|
|
||||||
func (cs *CompilerState) jumpInstruction(offset int, sign int) int {
|
func (cs *CompilerState) jumpInstruction(offset int, sign int) int {
|
||||||
if offset+2 >= len(cs.Chunk.Code) {
|
if offset+2 >= len(cs.Chunk.Code) {
|
||||||
fmt.Println(" [incomplete]")
|
fmt.Println(" [incomplete]")
|
||||||
@ -593,9 +612,14 @@ func (cs *CompilerState) printValue(value Value) {
|
|||||||
fmt.Print("false")
|
fmt.Print("false")
|
||||||
}
|
}
|
||||||
case ValueNumber:
|
case ValueNumber:
|
||||||
fmt.Printf("%.2g", value.Data.(float64))
|
fmt.Printf("%.6g", value.Data.(float64))
|
||||||
case ValueString:
|
case ValueString:
|
||||||
fmt.Printf("\"%s\"", value.Data.(string))
|
str := value.Data.(string)
|
||||||
|
if len(str) > 50 {
|
||||||
|
fmt.Printf("\"%s...\"", str[:47])
|
||||||
|
} else {
|
||||||
|
fmt.Printf("\"%s\"", str)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
fmt.Printf("<%s>", cs.valueTypeString(value.Type))
|
fmt.Printf("<%s>", cs.valueTypeString(value.Type))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user