un assembleur ( i.e. masm ou autre) convertit directement les mnémonique ( genre push mov ou jmp) en code hexa qui eur correspond. c´est ces codes héxa que le processeur comprend directement.
mais contrairement à un compilateur c++ qui fait un gros travail de fond, l´assembleur ne fait que s´occuper des label, des nom de variables et quelques petit autres trucs qui simplifie la tache du programmeur.
Mais quand tu tape un programme en asm tu peut savoir exactement quel tête il aura une fois assemblé ( ce qui n´est pas le cas du C par exemple).
quand on optimise on choisit ce qu´on veut optimiser justement, si on se concentre sur la vitesse ( dans ce cas là, on peut ( mais ce n´est pas toujours le mieux) inliner toute les fonction) ou alors sur la place ( dans ce cas là c´est el cotnraire) etc...
pour le i*2 ou i<<2 en c++ ça revient au même car un bon compilo mettra automatiquement ce qui prendra le moisn de cycle surle processeur que tu utilise ( et selon le contexte) le seul truc c´est qu´avec i<<2 tu risque de l´étonner.
mais effectivemtn les 2 instructions ont un équivalent en asm qui est équivalent.
Mais bon, il y a souvent plusieurs manière de faire les chose.
par exemple pour mettre ta variables à zéro, pourquoi ne pas faire
mov eax,o ?
ben, parce que
xor eax,eax est moins gourmand en mémoire et en temps ( à vérifier dans la doc intel pour le temps).
pour ta dernière question, je n´en connait pas, même si un débogueur fait un peu ça.
mais bon, il vaut mieux utiliser un traceur, enfin comme tu dit, concentre toi sur le langage, tu optimisera à mort après...