If VAR?0
to simply If VAR
For(A,0,11)
For(B,0,7)
If {Y/8+B*16+(X/8)+A+L1}
Pt-On(A*8-(X^8),B*8-(Y^8),{Y/8+B*32+(X/8)+A}*8+Pic0
End
End
End
There is a HUGE speed gain from simply preevaluating some of the expressions before entering the loop:X/8->E
Y/8->F
X^8->I
Y^8->J
For(A,0,7)
For(B,0,11)
If {F+B*16+E+A+L1}->C
Pt-On(A*8-I,B*8-J,C*8+Pic0
End
End
End
{20*12+L6+2}^^re4
This optimization relies on the fact that the numbers can basically be pre-computed: use the following formula to derive the numbers you should use: {Y*12+L6+(X/8)}e(X^8)
So for another example, the command pxl-Test(8,1) becomes {12+L6}e1.If A=EXP
optimizes to !If A xor EXP
Note that you should use !If A – EXP if it is an optimized addition/subtraction (See Optimized Math)If A=EXP and (B=EXP)
optimizes to !If A-EXP + (B-EXP)
where + is the 16bit 'or' operator.If A=EXP1 or (A=EXP2)
to If inData(A,Data(EXP1,EXP2,0))
You just have to make sure that you take care of the 0 case first, since this will return a non-zero value if the variable=0 :P Also, as Quigibo pointed out, this only works with constant, 8bit values. Text(0,0,PTR)
optimizes to Text(0,,PTR)
See how that works? When Axe goes to parse the second argument of Text(, it would normally load the second argument into HL and then use that as the Y position of the text. However, in the optimized piece it doesn't find anything to load for the second argument, so it just uses what was already in HL, namely, 0.If A>3: 1?B
becomes If A>3: ?B
But wait! What if you want to use this optimization on an equality check? Normally, If A=1:?B would work, but if we wanted to optimize the equality check as well, it doesn't work quite right. !If A-1 returns zero if true (or rather, if false), so you might then think that it's probably best to skip this particular optimization and go !If A-1:1?B
However, although it may seem counterintuitive, the following is actually smaller and faster: !If A-1:+1?B
Similarly, If EXP: -1?B:End
(with a minus sign) is preferable to If EXP:0?B:End
0?B: 0?A
becomes 0?B?A
note: When initializing variables that are 2 or less apart, it also yields further optimization to do this:0?A: 1?B: 3?C
to 0?A+1?B+2?C
An example of HL abuse in a subroutine:sub(LBL,EXP).....Lbl LBL: EXP*2?{L1}
to sub(LBL,EXP)....Lbl LBL:*2?{L1]
It will execute the loop n times, with A starting at n-1 and decreasing down to 0:Code: [Select]n
While
-1?A
;Code
A
End
:.SMILE
:[004466000000817E]->Pic1
:DiagnosticOff
:0->X->Y
:Repeat getkey(15)
:ClrDraw
:getKey(3)-getKey(2)+X //check getkeys for X. But we're not going to store the value just yet...
:!If +1 //First, check if X is negative one; that is, we'll check if X+1=0
:+1 //if so, add one to make the value in HL 1 (!If statements return 0 if true)
:End
:-1 //subtract 1 since we added 1 earlier
:Pt-On(min(,88)?X,getKey(1)-getKey(4)+Y+(=?1)min(,56)?Y,Pic1) //now we'll use the smallest value of either HL or 88 as the X position. For Y, we'll first handle keypresses, then add 1 (the boolean value of y=-1) if Y=-1. Then we'll use the smallest value of either HL or 56 as the Y position.
:DispGraph
:End
Lbl A : Stuff : sub(B) : Return
to this: Lbl A: Stuff : Goto B
The Return is not needed because you end up "stealing" subroutine B's return instead of having to return to A and then return again to the main program.If EXP1 and EXP2
to If EXP1 : If EXP2
Make sure to have EXP1 (the outside If block) be the expression that is less likely to be true to gain the most speed.EXP*96
to EXP*32*3
Also, a little-known fact regarding printing text at constant coordinates:
[/list]Code: [Select].Coordinate=Y*256+X
Is 7 bytes smaller than:
Text(30*256+20)
Text "Stuff"Code: [Select]Text(20,30,"Stuff")
The same applies for text drawn to the home screen:Code: [Select].Coordinate=X*256+Y
Is smaller than:
Output(20*256+30)
Disp "Stuff"Code: [Select]Output(20,30,"Stuff")
By even more, 8 bytes.
One major optimization that usually gets ignored is recycling large axe commands. Axe is not like BASIC and so each command needs its own subroutine to add to your program. For instance, lets say you use Pt-On() and Pt-Mask() in your code. Each one has to bring its own 100+ byte subroutine into your program. But you can probably get away with having just a Pt-Mask routine, recycling it to act like Pt-On by simply adding a 2nd layer to your sprite which is only 8 bytes extra instead of 100ish. Or you could do the opposite too and only have Pt-On() and Pt-Change() to manually change both buffers at once. This generally reduces the overall size of the program by a lot when you use the routines only once or very rarely in your code. And I don't mean calling it rarely, it could be the most used routine in your code, I just mean rarely appears in your source.
EPIC!!! I just HAD to bookmark this.
Part VI: Miscellaneousthis has speed improvement as well as size right?
All the stuff I couldn't fit into another category...
If you need to draw horizontal or vertical lines, use the Rect() function with a width or height of 1 instead:Code: [Select]Line(0,,20,0)
toCode: [Select]Rect(0,,20,1)
Part III: "HL is the Ans of Axe" -Runer112
Now, if you are checking the same variable for more than one possible expression, then it yields a greater optimization to do this:Shouldn't that first one beCode: [Select]If A=EXP1 or (B=EXP2)
toCode: [Select]If inData(A,Data(EXP1,EXP2,0))
You just have to make sure that you take care of the 0 case first, since this will return a non-zero value if the variable=0 :P
If A=EXP1 or (A=EXP2)
I'm feeling slightly... astounded by this...
Remembering the code of splut, I'm missing ALOT of optimizations :w00t:
Alot? (http://hyperboleandahalf.blogspot.com/2010/04/alot-is-better-than-you-at-everything.html) :p
!If A-EXP1 [16bit and] (A-EXP2)
0->X
While +26
Do stuff...
X-2->X
End
By the way, you can't have non-constant data as part of the Data() command. And that whole inData() optimization only works for comparisons with numbers between 0-255. You can optimize it to this always though:Wait, but you can't use bitwise-and like a logical "and" the same way you can with "or".Code: [Select]!If A-EXP1 [16bit and] (A-EXP2)
By the way, you can't have non-constant data as part of the Data() command. And that whole inData() optimization only works for comparisons with numbers between 0-255. You can optimize it to this always though:Wait, but you can't use bitwise-and like a logical "and" the same way you can with "or".Code: [Select]!If A-EXP1 [16bit and] (A-EXP2)
!If A-EXP1 + (B-EXP2)
This doesn't work because there are more solutions than there should be. For instance, if A were EXP2 and B were EXP1 the expression would be zero when it should be non-zero.If A=EXP1 + (B=EXP2)
!If A-EXP1 [16-bit or] (B-EXP2)
n
While
-1→A
;Code
A
End
n
Lbl L
→A
;Code
!If A-1
Goto L
End
In case anyone was wondering, here is the smallest loop structure that I know of in Axe.
is this an optimization?
if x=5
0->A
end
to
If x=5
-1->A (minus)
end
:!If A-5
:→A
:End
:banghead:
i'm an idiot sometimes.
thank you very much
[edit]
also,
would this be better?
?*256
to
?*2*2*2*2*2*2*2*2
and.
?/8
to
?/2/2/2
Thanks in advance.
[/edit]
.TEST
For(A,0,50000)
*2*2*2*2*2*2*2*2
End
vs.TEST
For(A,0,50000)
*256
End
.TEST
For(A,0,50000)
*2*2*2*2*2*2*2
End
completed in 1.8 seconds while.TEST
For(A,0,50000)
*128
End
completed in 2.4 secondsJust ran some tests:
5*8
Lbl LY
→Y
5*8
Lbl LX
→X
Pt-On(,Y,Pic1)
If X
-8
Goto LX
End
If Y
-8
Goto LY
End
While I
Disp "O
End
:If EXP
:1->A
:End
:If EXP
:->A
:End
:EXP->A
Hey thats ok :) Sometimes this optimization works even if there is a difference ^^fixed
Welcome to Omnimaga too! It's nice to see another Axe user around here :) Why don't you make a post in the Introduce Yourself page so we can all give you a proper peanut filled welcome :D
Question mark!How about this:
0-A->B->C->D.....->Z->0
to
0->{l1-56}
fill(l1-56,56)
0→A→B→X→Y→{L₁}ʳ
0→{°A}ʳ
Fill(°A+1,52)
ᴇ1337→{°A}ʳ
Copy(°A,+2,52)
Pre-evaluating expressions: Especially in games that heavily reference arrays throughout a section of code, it is often good both for speed and memory to pre-evaluate expressions that do not change throughout the loop. Look at this code for drawing a scrolling 16x16 tilemapper with X and Y positions in pixels:Code: [Select]For(A,0,7)
There is a HUGE speed gain from simply preevaluating some of the expressions before entering the loop:
For(B,0,11)
If {Y/8+B*16+(X/8)+A+L1}
Pt-On(A*8-(X^8),B*8-(Y^8),{Y/8+B*32+(X/8)+A}*8+Pic0
End
End
EndCode: [Select]X/8->E
Y/8->F
X^8->I
Y^8->J
For(A,0,7)
For(B,0,11)
If {F+B*16+E+A+L1}->C
Pt-On(A*8-I,B*8-J,C*8+Pic0
End
End
End
X/8->E
Y/8->F
X^8->I
Y^8->J
For(A,0,7)
*8-I->G
For(B,0,11)
If {F+B*16+E+A+L1}->C
Pt-On(G,B*8-J,C*8+Pic0
End
End
End
Even pre-evaluating for inner For( loops ;D
X/8->E
Y/8->F
X^8->I
Y^8->J
For(A,0,7)
*8-I->G
For(B,0,11)
If {+F*16+E+A+L1}->C
Pt-On(G,B*8-J,C*8+Pic0
End
End
End
Code: (Code) [Select] Y and ᴇF8*2+(X/2/2/2)+L₁→D | Code: (Comments) [Select] Tilemap offset; optimized version of Y/8*16+(X/8)+L₁→D |
Epic. I love return'd value hacks :D
:crazy: That's amazing, Runer. Do you always come up with code like this? :P
Epic. I love return'd value hacks :D
My favorite Axe optimization trick! ;D
That's going be a thing of the past. That optimization is built into Axe now. ;)
A-1->A
!If A
...
would be auto-opted toA-1->A
!If
...
That's going be a thing of the past. That optimization is built into Axe now. ;)Woah, really? Awesome! ;D I can't wait for a new version. :D
Repeat getKey(15)
...code...
End
While 1
...code...
EndIf getKey(15)
{20*12+L6+2}^^r e4
This optimization relies on the fact that the numbers can basically be pre-computed: use the following formula to derive the numbers you should use: {Y*12+L6+(X/8)}e(X^8)
So for another example, the command pxl-Test(8,1) becomes {12+L6}e1.If you are pixel testing a constant pixel, like pxl-Test(20,20), you can more than halve the speed of this command with the following optimization:Code: [Select]{20*12+L6+2}e4
{20*12+L₆+2}ʳe4
Is using Rect( to draw straight horizontal/vertical lines faster than Line( ?
Lbl HL
→r₆
ReturnIf and b11000000
ᴇFFFF→{r₆*12+L₆}ʳ
Fill(,10)
Return
saving of OVER 9000 CYCLES!
Here's something really cool I found out yesterday:
DispGraphr is faster than DispGraph. By more than 10000 cycles, too. It varies from calc to calc, but on mine its a full 15000 cycles faster O.o This means that if you're making a monochrome game, and you're not using the backbuffer....(at the cost of around 15 bytes or so) you can make asaving of OVER 9000 CYCLES!
Here's something really cool I found out yesterday:
DispGraphr is faster than DispGraph. By more than 10000 cycles, too. It varies from calc to calc, but on mine its a full 15000 cycles faster O.o This means that if you're making a monochrome game, and you're not using the backbuffer....(at the cost of around 15 bytes or so) you can make asaving of OVER 9000 CYCLES!
A quick and small way to determine the sign of a value (better than >>0) isCode: [Select]EXP//32768
. It will return -1 if the value is negative, and 0 if the value is 0 or positive
No matter what the value of {P+D} is, it always returns true, be it any number that appears in the level (any num from 0 to 11)Even when it equaled, say, 8, it would return as true (is that the right way to say it btw) and draw a door.
!If {P+D}/2-1
.{P+D}=2 or 3
End
also, i think 'number less than 256' /256 might be more efficient than just 0Actually no, both of those are 3 bytes. But 'number less than 256' and 0 is only 2 bytes and it does the same thing :)
If A+1->A
instead of A+1->A
If A
Also DispGraph is just as fast as DispGraphr