Starting to use ChatGPT to write optimizer for SpinCAD

Digital Larry

Active member
This falls into the "may-never-finish-it-but-who-knows" category. I was working on something for work and complaining about the need for a small utility that would take me half a day to try to write because I don't do that sort of thing all the time. My boss says "see if you can get ChatGPT to write it" and it took two tries. It was the first time I'd ever done that and it sort of blew my mind in spite of me being aware this is what people do nowadays so they can have a nice big layoff of software engineers.

So then I started asking about the problem of the Spin optimizer. I have long been able to describe the optimizations, but it's a programming exercise whose level of complexity means it won't get done for leisure.

This was pretty interesting. First of all ChatGPT is eager to please but makes a LOT of mistakes. I gave it the entire Spin ASM manual to read for reference, but I don't think it gets it. Also, it doesn't have a way to enter a line break AFAICT which means you hit "ENTER" before your question is really done and then it starts trying to answer. I had to tell it "wait until I say "cheese"" which it said it would but I think its eagerness still got the best of it a couple times. It also forgets what you told it earlier and can jump to the wrong conclusion easily. So I messedd with it interactively but then also built up my query in a text editor so it would take it all at once.

I know some of you are programmers or in IT so might find this interesting. Right now I had it implement it in Python assuming I would read a file. If I can get that all working then I'll tell it to write it in Java assuming the ASM listing is in whatever structure SpinCAD uses for it.

Here's what I told it:

; full optimizer example
; individual rules are separated by a small letter followed by close parenthesis.
RDAX and WRAX statements are of the form:

RDAX reg, gain
"reg" in the following examples is any integer between 32 and 64, as well as strings in the pattern "REGx" or "regx", where x is an integer between 1 and 32.

a)
rule description:
if RDAX reg, 1.0 follows WRAX reg, 0 (ignoring comments) and there is no further reference to reg
then comment out both statements. Only modify these lines. Do not change any other lines.

example:
; ------- Smoother

RDAX 37, 1.0
RDFX 40, 0.0700
WRAX 40, 0.0
; ------- Scale/Offset
RDAX 40, 1.0
SOF 0.2700, 0.7300
WRAX 41, 0.0

should produce:

RDAX 37, 1.0
RDFX 40, 0.0700
; optimized WRAX 40, 0.0
; ------- Scale/Offset
; optimized RDAX 40, 1.0
SOF 0.2700, 0.7300
WRAX 41, 0.0
---


b)

rule description:
if RDAX reg, 1.0 follows WRAX reg, 0 (ignoring comments) however there is a further reference to reg:
1) Insert a comment above the WRAX statement: "; optimized - changed gain to 1.0"
2) insert the WRAX statement, changing the gain to 1.0.
3) Comment out the RDAX statement as shown below
Only modify these lines. Do not change any other lines.

example:
; ------- Smoother

RDAX 37, 1.0
RDFX 40, 0.0700
WRAX 40, 0.0
; ------- Scale/Offset
RDAX 40, 1.0
SOF 0.2700, 0.7300
WRAX 40, 0.0

should produce:

RDAX 37, 1.0
RDFX 40, 0.0700
; optimized - changed gain to 1.0
WRAX 40, 1.0
; ------- Scale/Offset
; optimized - RDAX 40, 1.0
SOF 0.2700, 0.7300
WRAX 40, 0.0

====================
Here's the Python 3.9 code it created (which you should be able to use if you like).

import re
import sys
import os

def optimize_fv1_code(assembly_code):
lines = assembly_code.split('\n')
optimized_lines = []
skip_next = False

i = 0
while i < len(lines):
if skip_next:
skip_next = False
i += 1
continue

stripped = lines.strip()

# Skip processing comment lines
if stripped.startswith(';'):
optimized_lines.append(stripped)
i += 1
continue

# Find the next non-comment instruction
j = i + 1
while j < len(lines) and lines[j].strip().startswith(';'):
j += 1

# Detect WRAX reg, 0 followed by RDAX reg, 1.0
match_wrax = re.match(r'WRAX\s+(\S+),\s*0(?:\.0+)?', stripped)
match_rdax = re.match(r'RDAX\s+(\S+),\s*1.0+', lines[j].strip()) if j < len(lines) else None

if match_wrax and match_rdax and match_wrax.group(1) == match_rdax.group(1):
reg = match_wrax.group(1)
# Check if reg is used between current instruction and the last instruction
used_later = any(
re.search(r'\b' + re.escape(reg) + r'\b', lines[k]) and not lines[k].strip().startswith(';')
for k in range(j + 1, len(lines))
)
if not used_later:
# Rule (a): No further reference, comment out only WRAX and RDAX, keep following instructions
optimized_lines.append(f"; optimized {stripped}")
optimized_lines.append(f"; optimized {lines[j].strip()}")
i = j + 1 # Skip to the next instruction after RDAX
continue
else:
# Rule (b): Further reference exists, change WRAX and comment out RDAX, keep following instructions
optimized_lines.append("; optimized - changed gain to 1.0")
optimized_lines.append(f"WRAX {reg}, 1.0")
optimized_lines.append(f"; optimized {lines[j].strip()}")
i = j + 1 # Skip to the next instruction after RDAX
continue

optimized_lines.append(stripped)
i += 1

return '\n'.join(optimized_lines)

if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python optimizer.py <input_file>")
sys.exit(1)

input_file = sys.argv[1]
file_root, file_ext = os.path.splitext(input_file)
output_file = f"{file_root}-optimized{file_ext}"

with open(input_file, "r") as file:
input_code = file.read()

optimized_code = optimize_fv1_code(input_code)

with open(output_file, "w") as file:
file.write(optimized_code)

print(f"Optimized file created: {output_file}")
==============
Before code sample:

; test case A
; RDAX ref, 1.0 following WRAX reg, 0 and there is no further use of reg
; remove both WRAX and RDAX
RDAX 37, 1.0
RDFX 40, 0.0700
; next instruction should optimize out
WRAX 40, 0.0
; ------- Scale/Offset
; next instruction should optimize out
RDAX 40, 1.0
SOF 0.2700, 0.7300
WRAX 41, 0.0

; test case B
; RDAX ref, 1.0 following WRAX reg, 0 and there is further use of reg
RDAX 38, 1.0
RDFX 42, 0.0700
; change gain in following instruction to 1.0
WRAX 42, 0.0
; ------- Scale/Offset
; next instruction should optimize out
RDAX 42, 1.0
SOF 0.2700, 0.7300
WRAX 42, 0.0

====
after (optimized) code sample

; test case A
; RDAX ref, 1.0 following WRAX reg, 0 and there is no further use of reg
; remove both WRAX and RDAX
RDAX 37, 1.0
RDFX 40, 0.0700
; next instruction should optimize out
; optimized WRAX 40, 0.0
; optimized RDAX 40, 1.0
SOF 0.2700, 0.7300
WRAX 41, 0.0

; test case B
; RDAX ref, 1.0 following WRAX reg, 0 and there is further use of reg
RDAX 38, 1.0
RDFX 42, 0.0700
; change gain in following instruction to 1.0
; optimized - changed gain to 1.0
WRAX 42, 1.0
; optimized RDAX 42, 1.0
SOF 0.2700, 0.7300
WRAX 42, 0.0

====================
 
Last edited:
Nope, I checked in some code on a branch, but in my experience, chatGPT either gets it or starts going in circles, and I wasn't getting anywhere. Then my annual reserve of energy to deal with SpinCAD (which gets lower every year; I'm fully a geezer now) ran out!
 
Nope, I checked in some code on a branch, but in my experience, chatGPT either gets it or starts going in circles, and I wasn't getting anywhere. Then my annual reserve of energy to deal with SpinCAD (which gets lower every year; I'm fully a geezer now) ran out!
Fair enough. I get it. Some long-haul projects can were a person down. I'm aging out too and just like to keep my whistle wet. Your SpinCAD is still a great tool to explore and toy with. And thank you for your response.
 
Nope, I checked in some code on a branch, but in my experience, chatGPT either gets it or starts going in circles, and I wasn't getting anywhere. Then my annual reserve of energy to deal with SpinCAD (which gets lower every year; I'm fully a geezer now) ran out!
I feel that. ChatGPT can for sure save some time, but on more sophisticated problems it still requires a lot of effort and upfront work. Lots of refinement, breaking down tasks and subtasks. Deciding at what point to have it generate a summary intended to be pasted into a new session to reduce the context size. Add to that the constant validation required to catch subtle mistakes.
 
Okay, I am having to use AI for work now, so while I understand that in general it is probably going to be the end of us all, I thought I would try it on the dang optimizer problem. I switched from chatGPT to Claude as it has a better reputation for code generation. I now present to you the first iteration.


This is an update which expands the capabilities of the optimizer to both remove instructions and registers which are not ultimately necessary, and to compact the register list as much as possible in the case that optimization leaves holes in the list.

These code changes were performed by Claude and inserted manually, along with some needed modifications to specific instruction classes to handle the new feature.

The resource count toolbar and simulated patch are not optimized. The optimization occurs when you select "File->Save patch as Spin ASM". "Copy ASM to clipboard" is not optimized, so you can compare the 2 approaches if you want.

I am aware of at least one optimization which is not being performed, so please let me know if you can find any others. In this particular program (at the end of the original):
MULX ADCL
RDAX REG16,1.0000000000
WRAX REG15,0.0000000000
;------ HPF 1P
RDAX REG14,1.0000000000
RDFX REG18,0.0439547406
WRAX REG18,-1.0000000000
RDAX REG14,1.0000000000
WRAX REG17,0.0000000000
;------ FB In 1
RDAX REG17,-1.2000000000
WRAX REG1,0.0000000000
;------ Output
RDAX REG15,1.0000000000
WRAX DACL,0.0000000000
RDAX REG15,1.0000000000
WRAX DACR,0.0000000000

can be replaced by:

MULX ADCL
RDAX REG16,1.0000000000
;------ Output
WRAX DACL,1.0000000000
WRAX DACR,0.0000000000

;------ HPF 1P
RDAX REG14,1.0000000000
RDFX REG18,0.0439547406
WRAX REG18,-1.0000000000
RDAX REG14,1.0000000000
WRAX REG17,0.0000000000
;------ FB In 1
RDAX REG17,-1.2000000000
WRAX REG1,0.0000000000

Eliminating 3 instructions and 1 register. Figuring out how to describe these situations is now the challenge.

I am attaching a couple files I generated using these 2 methods. They attempt to capture the random pitch wobbles of avant-garde jazz guitarist Mary Halvorson.

If you want to see what is going on, you can run SpinCAD Designer in debug mode and watch the console.

e.g., in a terminal window:

java -jar .\SpinCAD-Designer-build-1043.jar

Here is the optimization report on this particular design.

Optimizer Case 2: collapsed wrax/rdax to wrax 37, 1.0 (saved 1 instruction)
Optimizer Case 1: removed wrax/rdax pair for reg 40 (saved 2 instructions, 1 register)
Optimizer Case 1: removed wrax/rdax pair for reg 41 (saved 2 instructions, 1 register)
Optimizer Case 1: removed wrax/rdax pair for reg 44 (saved 2 instructions, 1 register)
Optimizer Case 3: replaced wrax/rdax with sof -1.2, 0.0 for reg 49 (saved 1 instruction, 1 register)
Optimization complete: saved 8 instruction(s) and 4 register(s).
----------------------------------------
Register compaction report:
Registers before compaction : 19 (highest was REG18 / 0x32)
Holes removed : 5
Registers after compaction : 14 (highest is now REG13 / 0x2d)
OK: all registers fit within REG0?REG31.
----------------------------------------

If this interests you, give it a shot and let me know what happens. Since at the moment, the optimized patch is not what gets simulated, you'll have to actually load it onto an FV-1 to see whether it broke anything. This particular patch is nice in that it exercises all 3 cases which I identified so far at: https://holy-city-audio.gitbook.io/...1-assembly-code-generated-by-spincad-designer

With my new found super powers, I may actually try to address some of the other issues in SpinCAD, or encourage others to try the same.

Thanks,

DL
 

Attachments

Last edited:
Okay, I am having to use AI for work now, so while I understand that in general it is probably going to be the end of us all, I thought I would try it on the dang optimizer problem. I switched from chatGPT to Claude as it has a better reputation for code generation. I now present to you the first iteration.


This is an update which expands the capabilities of the optimizer to both remove instructions and registers which are not ultimately necessary, and to compact the register list as much as possible in the case that optimization leaves holes in the list.

These code changes were performed by Claude and inserted manually, along with some needed modifications to specific instruction classes to handle the new feature.

The resource count toolbar and simulated patch are not optimized. The optimization occurs when you select "File->Save patch as Spin ASM". "Copy ASM to clipboard" is not optimized, so you can compare the 2 approaches if you want.

I am aware of at least one optimization which is not being performed, so please let me know if you can find any others. In this particular program (at the end of the original):


can be replaced by:



Eliminating 3 instructions and 1 register. Figuring out how to describe these situations is now the challenge.

I am attaching a couple files I generated using these 2 methods. They attempt to capture the random pitch wobbles of avant-garde jazz guitarist Mary Halvorson.

If you want to see what is going on, you can run SpinCAD Designer in debug mode and watch the console.

e.g., in a terminal window:

java -jar .\SpinCAD-Designer-build-1043.jar

Here is the optimization report on this particular design.



If this interests you, give it a shot and let me know what happens. Since at the moment, the optimized patch is not what gets simulated, you'll have to actually load it onto an FV-1 to see whether it broke anything. This particular patch is nice in that it exercises all 3 cases which I identified so far at: https://holy-city-audio.gitbook.io/...1-assembly-code-generated-by-spincad-designer

With my new found super powers, I may actually try to address some of the other issues in SpinCAD, or encourage others to try the same.

Thanks,

DL
Cool beans! Is there an accompanying SpinCAD Designer file to go with the Mary Halvorson SpinASM (txt) file for comparison?
 
Cool beans! Is there an accompanying SpinCAD Designer file to go with the Mary Halvorson SpinASM (txt) file for comparison?
Hello Sir Cow, please see the attachment. Wow I'm so honored that .spcd is an accepted file format!

I pushed ahead a little and incorporated the optimizer into everything and made sure the resources toolbar showed the correct post-optimization counts. I was also curious as to why the report showed 4 registers had been saved while 5 holes were removed. Turns out there is a bug in the 3-tap block where a register is allocated but never used! I probably never would have found that. I also asked Claude to scan the entire file i/o java class to look for unhandled exceptions (I'd seen some e.g. when cancelling a file save) and there were 11 of them. I slapped that fix in there as well. I'll put it up some time this week.

I'm just having a little fun with this at the moment, I'm not convinced I'm going to start spending hours and hours on this stuff. If it had existed when I first started working on the project, well...

Another cool development in the FV-1 world is the Visual Studio Code plugin offered by the guys who make the Easy-Spin pedal.


This offers the ability to create your own blocks, step by step Spin ASM debugging, simulation, optimization, etc. At least they were kind enough to mention SpinCAD as an inspiration. I already have one of their pedals, it's pretty nice. Hats off to the younger generation!


Cheers,

DL
 

Attachments

Last edited:
EDIT: (see below - at the bottom)
Hello Sir Cow, please see the attachment. Wow I'm so honored that .spcd is an accepted file format!

I pushed ahead a little and incorporated the optimizer into everything and made sure the resources toolbar showed the correct post-optimization counts. I was also curious as to why the report showed 4 registers had been saved while 5 holes were removed. Turns out there is a bug in the 3-tap block where a register is allocated but never used! I probably never would have found that. I also asked Claude to scan the entire file i/o java class to look for unhandled exceptions (I'd seen some e.g. when cancelling a file save) and there were 11 of them. I slapped that fix in there as well. I'll put it up some time this week.
Sweet! (y)
I'm just having a little fun with this at the moment, I'm not convinced I'm going to start spending hours and hours on this stuff. If it had existed when I first started working on the project, well...

Another cool development in the FV-1 world is the Visual Code plugin offered by the guys who make the Easy-Spin pedal.


This offers the ability to create your own blocks, step by step Spin ASM debugging, simulation, optimization, etc. At least they were kind enough to mention SpinCAD as an inspiration. I already have one of their pedals, it's pretty nice. Hats off to the younger generation!


Cheers,

DL
Thank you DL! Yeah, my SpinASM coding is in its infancy still, so the SpinCAD file is appreciated for my better understanding.

The VC plugin looks promising, but I dropped the VC development tools over 10 years ago. Hats off to the younger generation indeed!

EDIT: I just tried to open the Mary Halvorson SpinCAD file in the latest SpinCAD Designer release (0.43) and was told that the sped file is from an incompatible version SpinCAD Designer. I'm guessing the newest release (0.44 ???) is not yet out?
 
Last edited:
There's nothing in the Mary Halvorson spcd file that should prevent loading in 1043. I just downloaded it here and it's fine.

Not sure what's going on there. Do you see anything on the debug console that might give a clue?
 
Back
Top