Ich vermute mal, du verwendest GCC und Optimierst. Dann macht deine ganze Funktion delay_ms() einfach *nichts*, denn die Ergebnisse von deinem Runterzählen etc werden nicht verwendet. Daher wird ein optimierender Compiler das Zeug in die Tonne kloppen, wie es sich auch gehört. Oder sonstige Optimierungen werden vorgenommen, so daß das ganze fixer läuft. Falls du nicht optimierst, dann brauchst du pro Durchlauf länger als gedacht.
Wenn du nicht über Timer als Zeitbasis gehen willst und von C aus genau kontrollieren willst, welche asm-Befehle erzeugt werden, dann ist inline Assembler dein Freund.