mirror of
https://github.com/odin-lang/Odin.git
synced 2026-07-10 18:09:32 +00:00
Merge pull request #6873 from bennyyip/regex/inject
core:text/regex: improve compiler performance
This commit is contained in:
@@ -43,9 +43,16 @@ Node_Match_All_And_Escape :: parser.Node_Match_All_And_Escape
|
||||
Opcode :: virtual_machine.Opcode
|
||||
Program :: [dynamic]Opcode
|
||||
|
||||
JUMP_SIZE :: size_of(Opcode) + 1 * size_of(u16)
|
||||
SPLIT_SIZE :: size_of(Opcode) + 2 * size_of(u16)
|
||||
Jump :: virtual_machine.Jump
|
||||
Split :: virtual_machine.Split
|
||||
Wait_For_Byte :: virtual_machine.Wait_For_Byte
|
||||
Wait_For_Rune :: virtual_machine.Wait_For_Rune
|
||||
Wait_For_Rune_Class :: virtual_machine.Wait_For_Rune_Class
|
||||
Wait_For_Rune_Class_Negated :: virtual_machine.Wait_For_Rune_Class_Negated
|
||||
Save :: virtual_machine.Save
|
||||
|
||||
JUMP_SIZE :: size_of(Jump)
|
||||
SPLIT_SIZE :: size_of(Split)
|
||||
|
||||
Compiler :: struct {
|
||||
flags: common.Flags,
|
||||
@@ -141,15 +148,13 @@ map_all_classes :: proc(tree: Node, collection: ^[dynamic]Rune_Class_Data) {
|
||||
|
||||
append_raw :: #force_inline proc(code: ^Program, data: $T) {
|
||||
// NOTE: This is system-dependent endian.
|
||||
for b in transmute([size_of(T)]byte)data {
|
||||
append(code, cast(Opcode)b)
|
||||
}
|
||||
data := transmute([size_of(T)]Opcode)data
|
||||
append(code, ..data[:])
|
||||
}
|
||||
inject_raw :: #force_inline proc(code: ^Program, start: int, data: $T) {
|
||||
// NOTE: This is system-dependent endian.
|
||||
for b, i in transmute([size_of(T)]byte)data {
|
||||
inject_at(code, start + i, cast(Opcode)b)
|
||||
}
|
||||
data := transmute([size_of(T)]Opcode)data
|
||||
inject_at(code, start, ..data[:])
|
||||
}
|
||||
|
||||
@require_results
|
||||
@@ -220,8 +225,8 @@ generate_code :: proc(c: ^Compiler, node: Node) -> (code: Program) {
|
||||
code = generate_code(c, specific.inner)
|
||||
|
||||
if specific.capture && .No_Capture not_in c.flags {
|
||||
inject_at(&code, 0, Opcode.Save)
|
||||
inject_at(&code, 1, Opcode(2 * specific.capture_id))
|
||||
save := Save{.Save, Opcode(2 * specific.capture_id)}
|
||||
inject_raw(&code, 0, save)
|
||||
|
||||
append(&code, Opcode.Save)
|
||||
append(&code, Opcode(2 * specific.capture_id + 1))
|
||||
@@ -236,9 +241,8 @@ generate_code :: proc(c: ^Compiler, node: Node) -> (code: Program) {
|
||||
// Avoiding duplicate allocation by reusing `left`.
|
||||
code = left
|
||||
|
||||
inject_at(&code, 0, Opcode.Split)
|
||||
inject_raw(&code, size_of(byte) , i16(SPLIT_SIZE))
|
||||
inject_raw(&code, size_of(byte) + size_of(i16), i16(SPLIT_SIZE + left_len + JUMP_SIZE))
|
||||
split := Split{.Split, i16(SPLIT_SIZE), i16(SPLIT_SIZE + left_len + JUMP_SIZE)}
|
||||
inject_raw(&code, 0, split)
|
||||
|
||||
append(&code, Opcode.Jump)
|
||||
append_raw(&code, i16(len(right) + JUMP_SIZE))
|
||||
@@ -259,9 +263,8 @@ generate_code :: proc(c: ^Compiler, node: Node) -> (code: Program) {
|
||||
code = generate_code(c, specific.inner)
|
||||
original_len := len(code)
|
||||
|
||||
inject_at(&code, 0, Opcode.Split)
|
||||
inject_raw(&code, size_of(byte) , i16(SPLIT_SIZE))
|
||||
inject_raw(&code, size_of(byte) + size_of(i16), i16(SPLIT_SIZE + original_len + JUMP_SIZE))
|
||||
split := Split{.Split, i16(SPLIT_SIZE), i16(SPLIT_SIZE + original_len + JUMP_SIZE)}
|
||||
inject_raw(&code, 0, split)
|
||||
|
||||
append(&code, Opcode.Jump)
|
||||
append_raw(&code, i16(-original_len - SPLIT_SIZE))
|
||||
@@ -270,9 +273,8 @@ generate_code :: proc(c: ^Compiler, node: Node) -> (code: Program) {
|
||||
code = generate_code(c, specific.inner)
|
||||
original_len := len(code)
|
||||
|
||||
inject_at(&code, 0, Opcode.Split)
|
||||
inject_raw(&code, size_of(byte) , i16(SPLIT_SIZE + original_len + JUMP_SIZE))
|
||||
inject_raw(&code, size_of(byte) + size_of(i16), i16(SPLIT_SIZE))
|
||||
split := Split{.Split, i16(SPLIT_SIZE + original_len + JUMP_SIZE), i16(SPLIT_SIZE)}
|
||||
inject_raw(&code, 0, split)
|
||||
|
||||
append(&code, Opcode.Jump)
|
||||
append_raw(&code, i16(-original_len - SPLIT_SIZE))
|
||||
@@ -359,17 +361,15 @@ generate_code :: proc(c: ^Compiler, node: Node) -> (code: Program) {
|
||||
code = generate_code(c, specific.inner)
|
||||
original_len := len(code)
|
||||
|
||||
inject_at(&code, 0, Opcode.Split)
|
||||
inject_raw(&code, size_of(byte) , i16(SPLIT_SIZE))
|
||||
inject_raw(&code, size_of(byte) + size_of(i16), i16(SPLIT_SIZE + original_len))
|
||||
split := Split{.Split, i16(SPLIT_SIZE), i16(SPLIT_SIZE + original_len)}
|
||||
inject_raw(&code, 0, split)
|
||||
|
||||
case ^Node_Optional_Non_Greedy:
|
||||
code = generate_code(c, specific.inner)
|
||||
original_len := len(code)
|
||||
|
||||
inject_at(&code, 0, Opcode.Split)
|
||||
inject_raw(&code, size_of(byte) , i16(SPLIT_SIZE + original_len))
|
||||
inject_raw(&code, size_of(byte) + size_of(i16), i16(SPLIT_SIZE))
|
||||
split := Split{.Split, i16(SPLIT_SIZE + original_len), i16(SPLIT_SIZE)}
|
||||
inject_raw(&code, 0, split)
|
||||
|
||||
case ^Node_Match_All_And_Escape:
|
||||
append(&code, Opcode.Match_All_And_Escape)
|
||||
@@ -412,32 +412,28 @@ compile :: proc(tree: Node, flags: common.Flags) -> (code: Program, class_data:
|
||||
seek_loop: for opcode, pc in virtual_machine.iterate_opcodes(&iter) {
|
||||
#partial switch opcode {
|
||||
case .Byte:
|
||||
inject_at(&code, pc_open, Opcode.Wait_For_Byte)
|
||||
pc_open += size_of(Opcode)
|
||||
inject_at(&code, pc_open, Opcode(code[pc + size_of(Opcode) + pc_open]))
|
||||
pc_open += size_of(u8)
|
||||
wait := Wait_For_Byte{.Wait_For_Byte, code[pc + size_of(Opcode) + pc_open]}
|
||||
inject_raw(&code, pc_open, wait)
|
||||
pc_open += size_of(Wait_For_Byte)
|
||||
break optimize_opening
|
||||
|
||||
case .Rune:
|
||||
operand := intrinsics.unaligned_load(cast(^rune)&code[pc+1])
|
||||
inject_at(&code, pc_open, Opcode.Wait_For_Rune)
|
||||
pc_open += size_of(Opcode)
|
||||
inject_raw(&code, pc_open, operand)
|
||||
pc_open += size_of(rune)
|
||||
wait := Wait_For_Rune{.Wait_For_Rune, operand}
|
||||
inject_raw(&code, pc_open, wait)
|
||||
pc_open += size_of(Wait_For_Rune)
|
||||
break optimize_opening
|
||||
|
||||
case .Rune_Class:
|
||||
inject_at(&code, pc_open, Opcode.Wait_For_Rune_Class)
|
||||
pc_open += size_of(Opcode)
|
||||
inject_at(&code, pc_open, Opcode(code[pc + size_of(Opcode) + pc_open]))
|
||||
pc_open += size_of(u8)
|
||||
wait := Wait_For_Rune_Class{.Wait_For_Rune_Class, code[pc + size_of(Opcode) + pc_open]}
|
||||
inject_raw(&code, pc_open, wait)
|
||||
pc_open += size_of(Wait_For_Rune_Class)
|
||||
break optimize_opening
|
||||
|
||||
case .Rune_Class_Negated:
|
||||
inject_at(&code, pc_open, Opcode.Wait_For_Rune_Class_Negated)
|
||||
pc_open += size_of(Opcode)
|
||||
inject_at(&code, pc_open, Opcode(code[pc + size_of(Opcode) + pc_open]))
|
||||
pc_open += size_of(u8)
|
||||
wait := Wait_For_Rune_Class_Negated{.Wait_For_Rune_Class_Negated, code[pc + size_of(Opcode) + pc_open]}
|
||||
inject_raw(&code, pc_open, wait)
|
||||
pc_open += size_of(Wait_For_Rune_Class_Negated)
|
||||
break optimize_opening
|
||||
|
||||
case .Save:
|
||||
@@ -452,27 +448,21 @@ compile :: proc(tree: Node, flags: common.Flags) -> (code: Program, class_data:
|
||||
}
|
||||
|
||||
// `.*?`
|
||||
inject_at(&code, pc_open, Opcode.Split)
|
||||
pc_open += size_of(byte)
|
||||
inject_raw(&code, pc_open, i16(SPLIT_SIZE + size_of(byte) + JUMP_SIZE))
|
||||
pc_open += size_of(i16)
|
||||
inject_raw(&code, pc_open, i16(SPLIT_SIZE))
|
||||
pc_open += size_of(i16)
|
||||
|
||||
inject_at(&code, pc_open, Opcode.Wildcard)
|
||||
pc_open += size_of(byte)
|
||||
|
||||
inject_at(&code, pc_open, Opcode.Jump)
|
||||
pc_open += size_of(byte)
|
||||
inject_raw(&code, pc_open, i16(-size_of(byte) - SPLIT_SIZE))
|
||||
pc_open += size_of(i16)
|
||||
|
||||
split := Split{.Split, i16(SPLIT_SIZE + size_of(byte) + JUMP_SIZE), i16(SPLIT_SIZE)}
|
||||
jump := Jump{.Jump, i16(-size_of(byte) - SPLIT_SIZE)}
|
||||
pack := struct {
|
||||
a: Split,
|
||||
b: Opcode,
|
||||
c: Jump,
|
||||
} { split, Opcode.Wildcard, jump }
|
||||
inject_raw(&code, pc_open, pack)
|
||||
pc_open += size_of(Split) + size_of(byte) + size_of(Jump)
|
||||
}
|
||||
|
||||
if .No_Capture not_in flags {
|
||||
// `(` <generated code>
|
||||
inject_at(&code, pc_open, Opcode.Save)
|
||||
inject_at(&code, pc_open + size_of(byte), Opcode(0x00))
|
||||
save := Save{.Save, Opcode(0x00)}
|
||||
inject_raw(&code, pc_open, save)
|
||||
|
||||
// `)`
|
||||
append(&code, Opcode.Save); append(&code, Opcode(0x01))
|
||||
|
||||
@@ -49,6 +49,35 @@ Opcode :: enum u8 {
|
||||
Wait_For_Rune_Class_Negated = 0x14, // | u8
|
||||
Match_All_And_Escape = 0x15, // |
|
||||
}
|
||||
Jump :: struct #packed {
|
||||
opcode: Opcode,
|
||||
target: i16,
|
||||
}
|
||||
Split :: struct #packed {
|
||||
opcode: Opcode,
|
||||
left: i16,
|
||||
right: i16,
|
||||
}
|
||||
Wait_For_Byte :: struct #packed {
|
||||
opcode: Opcode,
|
||||
operand: Opcode,
|
||||
}
|
||||
Wait_For_Rune :: struct #packed {
|
||||
opcode: Opcode,
|
||||
operand: rune,
|
||||
}
|
||||
Wait_For_Rune_Class :: struct #packed {
|
||||
opcode: Opcode,
|
||||
operand: Opcode,
|
||||
}
|
||||
Wait_For_Rune_Class_Negated :: struct #packed {
|
||||
opcode: Opcode,
|
||||
operand: Opcode,
|
||||
}
|
||||
Save :: struct #packed {
|
||||
opcode: Opcode,
|
||||
operand: Opcode,
|
||||
}
|
||||
|
||||
Thread :: struct {
|
||||
pc: int,
|
||||
|
||||
Reference in New Issue
Block a user