How to put a value from a variable to a register? - variables

I want to compare the end character of my string to a period.
I counted the length of the string and saved it in a variable named strlen. So, I did cmp [string + strlen], '.', but it didn't work, Then, I tried moving strlen to a register, but it didnt work as well. The program crashes. I'm using x86 32-bit Windows 10 architecture
MOV BL, [strlen-1] ;the length of the string minus 1 so i would end up
in the last character of the string
cmp [string + BL], '.'
JE func1

MOV BL, [strlen-1]
This isn't actually doing what you think it's doing. It's not storing the value of strlen - 1 in bl. Rather, it is storing the value at the address strlen - 1 in bl.
If you know C, it is the difference between:
byte* strlen = ...;
BL = *strlen - 1;
and:
byte* strlen = ...;
BL = *(strlen - 1);
In assembly notation, you can think of the brackets ([...]) as meaning "address to dereference", where "address" is interchangeable with "memory location"—like a pointer in C.
If you want to subtract 1 from the actual value of strlen, then you need to load the value into a register first, and then subtract 1 from it.
In C:
byte* strlen = ...;
bl = *strlen;
bl -= 1;
In assembly:
movzx ebx, BYTE PTR [strlen]
sub ebx, 1 ; (or dec ebx)
The BL register will now contain the length of the string, minus 1. So, you can do:
mov al, BYTE PTR [startOfString + ebx] ; al = startOfString[bl]
to load the last character in the string (which start at address startOfString) into the variable al.
Then, follow it up with:
cmp al, '.'
to set flags. Or, as you had it originally, you could use a CISC-style instruction that combines the load with the comparison:
cmp BYTE PTR [startOfString + ebx], '.'

Related

Which is the fastest way to find the last N bits of an integer?

Which algorithm is fastest for returning the last n bits in an unsigned integer?
1.
return num & ((1 << bits) - 1)
2.
return num % (1 << bits)
3.
let shift = num.bitWidth - bits
return (num << shift) >> shift
(where bitWidth is the width of the integer, in bits)
Or is there another, faster algorithm?
This is going to depend heavily on what compiler you have, what the optimization settings are, and what size of integers you're working with.
My hypothesis going into this section was that the answer would be "the compiler will be smart enough to optimize all of these in a way that's better than whatever you'd choose to write." And in some sense, that's correct. Consider the following three pieces of code:
#include <stdint.h>
#include <limits.h>
uint32_t lastBitsOf_v1(uint32_t number, uint32_t howManyBits) {
return number & ((1 << howManyBits) - 1);
}
uint32_t lastBitsOf_v2(uint32_t number, uint32_t howManyBits) {
return number % (1 << howManyBits);
}
uint32_t lastBitsOf_v3(uint32_t number, uint32_t howManyBits) {
uint32_t shift = sizeof(number) * CHAR_BIT - howManyBits;
return (number << shift) >> shift;
}
Over at the godbolt compiler explorer with optimization turned up to -Ofast with -march=native enabled, we get this code generated for the three functions:
lastBitsOf_v1(unsigned int, unsigned int):
bzhi eax, edi, esi
ret
lastBitsOf_v2(unsigned int, unsigned int):
bzhi eax, edi, esi
ret
lastBitsOf_v3(unsigned int, unsigned int):
mov eax, 32
sub eax, esi
shlx edi, edi, eax
shrx eax, edi, eax
ret
Notice that the compiler recognized what you were trying to do with the first two versions of this function and completely rewrote the code to use the bzhi x86 instruction. This instruction copies the lower bits of one register into another. In other words, the compiler was able to generate a single assembly instruction! On the other hand, the compiler didn't recognize what the last version was trying to do, so it actually generated the code as written and actually did the shifts and subtraction.
But that's not the end of the story. Imagine that the number of bits to extract is known in advance. For example, suppose we want the lower 13 bits. Now, watch what happens with this code:
#include <stdint.h>
#include <limits.h>
uint32_t lastBitsOf_v1(uint32_t number) {
return number & ((1 << 13) - 1);
}
uint32_t lastBitsOf_v2(uint32_t number) {
return number % (1 << 13);
}
uint32_t lastBitsOf_v3(uint32_t number) {
return (number << 19) >> 19;
}
These are literally the same functions, just with the bit amount hardcoded. Now look at what gets generated:
lastBitsOf_v1(unsigned int):
mov eax, edi
and eax, 8191
ret
lastBitsOf_v2(unsigned int):
mov eax, edi
and eax, 8191
ret
lastBitsOf_v3(unsigned int):
mov eax, edi
and eax, 8191
ret
All three versions get compiled to the exact same code. The compiler saw what we're doing in each case and replaced it with this much simpler code that's basically the first version.
After seeing all of this, what should you do? My recommendation would be the following:
Unless this code is an absolute performance bottleneck - as in, you've measured your code's runtime and you're absolutely certain that the code for extracting the low bits of numbers is what's actually slowing you down - I wouldn't worry too much about this at all. Pick the most readable code that you can. I personally find option (1) the cleanest, but that's just me.
If you absolutely must get every ounce of performance out of this that you can, rather than taking my word for it, I'd recommend tinkering around with different versions of the code and seeing what assembly gets generated in each case and running some performance experiments. After all, if something like this is really important, you'd want to see it for yourself!
Hope this helps!

Direct2D COM calls returning 64-bit structs and C++Builder 2010

I'm trying to get the size of a Direct2D Bitmap and getting an immediate crash.
// props and target etc all set up beforehand.
CComPtr<ID2D1Bitmap> &b;
target->CreateBitmap(D2D1::SizeU(1024,1024), frame.p_data, 1024* 4, &props, &b));
D2D_SIZE_U sz = b->GetPixelSize(); // Crashes here.
All other operations using the bitmap (including drawing it) work correctly. It's just returning the size that seems to be the problem.
Based on a articles like this by Rudy V, my suspicion is that it's some incompatibility with C++Builder 2010 and how COM functions return 64-bit structures. http://rvelthuis.de/articles/articles-convert.html
The Delphi declaration of GetPixelSize looks like this: (from D2D1.pas)
// Returns the size of the bitmap in resolution dependent units, (pixels).
procedure GetPixelSize(out pixelSize: TD2D1SizeU); stdcall;
... and in D2D1.h it's
//
// Returns the size of the bitmap in resolution dependent units, (pixels).
//
STDMETHOD_(D2D1_SIZE_U, GetPixelSize)(
) CONST PURE;
Can I fix this without rewriting the D2D headers?
All suggestions welcome - except upgrading from C++Builder 2010 which is more of a task than I'm ready for at the moment.
„getInfo“ is a function derived from Delphi code, which can work around.
void getInfo(void* itfc, void* info, int vmtofs)
{
asm {
push info // pass pointer to return result
mov eax,itfc // eax poionts to interface
push eax // pass pointer to interface
mov eax,[eax] // eax points to VMT
add eax,vmtofs // eax points rto address of virtual function
call dword ptr [eax] // call function
}
}
Disassembly of code generated by CBuilder, which results in a crash:
Graphics.cpp.162: size = bmp->GetSize();
00401C10 8B4508 mov eax,[ebp+$08]
00401C13 FF7004 push dword ptr [eax+$04]
00401C16 8D55DC lea edx,[ebp-$24]
00401C19 52 push edx
00401C1A 8B4D08 mov ecx,[ebp+$08]
00401C1D 8B4104 mov eax,[ecx+$04]
00401C20 8B10 mov edx,[eax]
00401C22 FF5210 call dword ptr [edx+$10]
00401C25 8B4DDC mov ecx,[ebp-$24]
00401C28 894DF8 mov [ebp-$08],ecx
00401C2B 8B4DE0 mov ecx,[ebp-$20]
00401C2E 894DFC mov [ebp-$04],ecx
„bmp“ is declared as
ID2D1Bitmap* bmp;
Code to call „getInfo“:
D2D1_SIZE_F size;
getInfo(bmp,&pf,0x10);
You get 0x10 (vmtofs) from disassembly line „call dword ptr [edx+$10]“
You can call „GetPixelSize“, „GetPixelFormat“ and others by calling „getInfo“
D2D1_SIZE_U ps;// = bmp->GetPixelSize();
getInfo(bmp,&ps,0x14);
D2D1_PIXEL_FORMAT pf;// = bmp->GetPixelFormat();
getInfo(bmp,&pf,0x18);
„getInfo“ works with methods „STDMETHOD_ ... CONST PURE;“, which return a result.
STDMETHOD_(D2D1_SIZE_F, GetSize)(
) CONST PURE;
For this method CBuilder generates malfunctional code.
In case of
STDMETHOD_(void, GetDpi)(
__out FLOAT *dpiX,
__out FLOAT *dpiY
) CONST PURE;
the CBuilder code works fine, „getDpi“ results void.

Assembly variables are deleted (16 bit x86 assembly)

I'm still playing with retro programming in turbo C for MS-DOS, and I found some trounble using variables.
If I define some variables at the start of the assembly code (in BSS or DATA), and try to use them inside the assembly function, most of the time these variables are deleted, or end up containing random data.
I learned a bit of assembly for the game boy :) and variables always worked well and never were deleted or modified, I guess x86 asm is different.
Then I tried this using inline assembly and it was a bit better, there is just one variable (width) not working.
void draw_map_column(MAP map, TILE *t){
word *tiledata = &t->data;
int *mapdata = map.data;
int width = map.width<<1;
word tile_offset = 0;
word map_offset = 0;
word screen_offset = 0;
asm{
push ds
push di
push si
mov dx,12 //column
lds bx,[tiledata]
lds si,ds:[bx] //ds:si data address
mov [tile_offset],ds
mov [tile_offset+2],si
les bx,[mapdata]
mov ax,es:[bx]
mov cl,8
shl ax,cl
add si,ax
mov di,screen_offset //es:di screen address
}
loop_tile:
asm{
mov ax,0A000h
mov es,ax
mov ax,16
}
copy_tile:
asm{
mov cx,8
rep movsw
add di,320-16
dec ax
jnz copy_tile
mov ds,[tile_offset]
mov si,[tile_offset+2]
mov ax,map_offset
add ax,[width] //"width" does never contain the value stored at the start
mov map_offset,ax
les bx,[mapdata]
add bx,ax
mov ax,es:[bx]
mov cl,8
shl ax,cl
add si,ax
dec dx
jnz loop_tile
pop si
pop di
pop ds
}
}
Just note the "witdh" variable which is not working at all, if I replace it with a number (40), the code just works as expected (this draws a column of tiles using a map array, and some tiles stored in ram).
I guess it has something to do with the push/pop etc, and something is not set as it should.
Also what happens in pure assembly? none of the variables were working. I defined them as DW and also added:
push bp
mov bp,sp
;function
mov sp,bp
pop bp
Thanks.
Well once again thanks a lot, next time I'll be more patient before asking.
Just in case this is useful for someone, I had defined a variable using the wrong size.
There are other things that can be improved, but that's another question.
Variable "tileoffset" holds a 32 bit address, so it must be a "dword", not a "word". Then the function should be like this:
void draw_map_column(MAP map, TILE *t){
word *tiledata = &t->data;
int *mapdata = map.data;
int width = map.width<<1;
dword tile_offset = 0; //changed to dword to store 32 bit address
word map_offset = 0;
word screen_offset = 0;
asm{
push ds
push di
push si
mov dx,12 //column
lds bx,[tiledata]
lds si,ds:[bx] //ds:si data address
mov word ptr[tile_offset],ds //store a word
mov word ptr[tile_offset+2],si
les bx,[mapdata]
mov ax,es:[bx]
mov cl,8
shl ax,cl
add si,ax
mov di,screen_offset //es:di screen address
}
loop_tile:
asm{
mov ax,0A000h
mov es,ax
mov ax,16
}
copy_tile:
asm{
mov cx,8
rep movsw
add di,320-16
dec ax
jnz copy_tile
mov ds,word ptr[tile_offset] //read a word to the register
mov si,word ptr[tile_offset+2]
mov ax,map_offset
add ax,[width]
mov map_offset,ax
les bx,[mapdata]
add bx,ax
mov ax,es:[bx]
mov cl,8
shl ax,cl
add si,ax
dec dx
jnz loop_tile
pop si
pop di
pop ds
}

How unwind ARM Cortex M3 stack

The ARM Coretex STM32's HardFault_Handler can only get several registers values, r0, r1,r2, r3, lr, pc, xPSR, when crash happened. But there is no FP and SP in the stack. Thus I could not unwind the stack.
Is there any solution for this? Thanks a lot.
[update]
Following a web instruction to let ARMGCC(Keil uvision IDE) generate FP by adding a compiling option "--use_frame_pointer", but I could not find the FP in the stack. I am a real newbie here. Below is my demo code:
int test2(int i, int j)
{
return i/j;
}
int main()
{
SCB->CCR |= 0x10;
int a = 10;
int b = 0;
int c;
c = test2(a,b);
}
enum { r0 = 0, r1, r2, r3, r11, r12, lr, pc, psr};
void Hard_Fault_Handler(uint32_t *faultStackAddress)
{
uint32_t r0_val = faultStackAddress[r0];
uint32_t r1_val = faultStackAddress[r1];
uint32_t r2_val = faultStackAddress[r2];
uint32_t r3_val = faultStackAddress[r3];
uint32_t r12_val = faultStackAddress[r12];
uint32_t r11_val = faultStackAddress[r11];
uint32_t lr_val = faultStackAddress[lr];
uint32_t pc_val = faultStackAddress[pc];
uint32_t psr_val = faultStackAddress[psr];
}
I have two questions here:
1. I am not sure where the index of FP(r11) in the stack, or whether it is pushed into stack or not. I assume it is before r12, because I compared the assemble source before and after adding the option "--use_frame_pointer". I also compared the values read from Hard_Fault_Handler, seems like r11 is not in the stack. Because r11 address I read points to a place where the code is not my code.
[update] I have confirmed that FP is pushed into the stack. The second question still needs to be answered.
See below snippet code:
Without the option "--use_frame_pointer"
test2 PROC
MOVS r0,#3
BX lr
ENDP
main PROC
PUSH {lr}
MOVS r0,#0
BL test2
MOVS r0,#0
POP {pc}
ENDP
with the option "--use_frame_pointer"
test2 PROC
PUSH {r11,lr}
ADD r11,sp,#4
MOVS r0,#3
MOV sp,r11
SUB sp,sp,#4
POP {r11,pc}
ENDP
main PROC
PUSH {r11,lr}
ADD r11,sp,#4
MOVS r0,#0
BL test2
MOVS r0,#0
MOV sp,r11
SUB sp,sp,#4
POP {r11,pc}
ENDP
2. Seems like FP is not in the input parameter faultStackAddress of Hard_Fault_Handler(), where can I get the caller's FP to unwind the stack?
[update again]
Now I understood the last FP(r11) is not stored in the stack. All I need to do is to read the value of r11 register, then I can unwind the whole stack.
So now my final question is how to read it using inline assembler of C. I tried below code, but failed to read the correct value from r11 following the reference of http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472f/Cihfhjhg.html
volatile int top_fp;
__asm
{
mov top_fp, r11
}
r11's value is 0x20009DCC
top_fp's value is 0x00000004
[update 3] Below is my whole code.
int test5(int i, int j, int k)
{
char a[128] = {0} ;
a[0] = 'a';
return i/j;
}
int test2(int i, int j)
{
char a[18] = {0} ;
a[0] = 'a';
return test5(i, j, 0);
}
int main()
{
SCB->CCR |= 0x10;
int a = 10;
int b = 0;
int c;
c = test2(a,b); //create a divide by zero crash
}
/* The fault handler implementation calls a function called Hard_Fault_Handler(). */
#if defined(__CC_ARM)
__asm void HardFault_Handler(void)
{
TST lr, #4
ITE EQ
MRSEQ r0, MSP
MRSNE r0, PSP
B __cpp(Hard_Fault_Handler)
}
#else
void HardFault_Handler(void)
{
__asm("TST lr, #4");
__asm("ITE EQ");
__asm("MRSEQ r0, MSP");
__asm("MRSNE r0, PSP");
__asm("B Hard_Fault_Handler");
}
#endif
void Hard_Fault_Handler(uint32_t *faultStackAddress)
{
volatile int top_fp;
__asm
{
mov top_fp, r11
}
//TODO: use top_fp to unwind the whole stack.
}
[update 4] Finally, I made it out. My solution:
Note: To access r11, we have to use embedded assembler, see here, which costs me much time to figure it out.
//we have to use embedded assembler.
__asm int getRegisterR11()
{
mov r0,r11
BX LR
}
//call it from Hard_Fault_Handler function.
/*
Function call stack frame:
FP1(r11) -> | lr |(High Address)
| FP2|(prev FP)
| ...|
Current FP(r11) ->| lr |
| FP1|(prev FP)
| ...|(Low Address)
With FP, we can access lr(link register) which is the address to return when the current functions returns(where you were).
Then (current FP - 1) points to prev FP.
Thus we can unwind the stack.
*/
void unwindBacktrace(uint32_t topFp, uint16_t* backtrace)
{
uint32_t nextFp = topFp;
int j = 0;
//#define BACK_TRACE_DEPTH 5
//loop backtrace using FP(r11), save lr into an uint16_t array.
for(int i = 0; i < BACK_TRACE_DEPTH; i++)
{
uint32_t lr = *((uint32_t*)nextFp);
if ((lr >= 0x08000000) && (lr <= 0x08FFFFFF))
{
backtrace[j*2] = LOW_16_BITS(lr);
backtrace[j*2 + 1] = HIGH_16_BITS(lr);
j += 1;
}
nextFp = *((uint32_t*)nextFp - 1);
if (nextFp == 0)
{
break;
}
}
}
#if defined(__CC_ARM)
__asm void HardFault_Handler(void)
{
TST lr, #4
ITE EQ
MRSEQ r0, MSP
MRSNE r0, PSP
B __cpp(Hard_Fault_Handler)
}
#else
void HardFault_Handler(void)
{
__asm("TST lr, #4");
__asm("ITE EQ");
__asm("MRSEQ r0, MSP");
__asm("MRSNE r0, PSP");
__asm("B Hard_Fault_Handler");
}
#endif
void Hard_Fault_Handler(uint32_t *faultStackAddress)
{
//get back trace
int topFp = getRegisterR11();
unwindBacktrace(topFp, persistentData.faultStack.back_trace);
}
Very primitive method to unwind the stack in such case is to read all stack memory above SP seen at the time of HardFault_Handler and process it using arm-none-eabi-addr2line. All link register entries saved on stack will be transformed into source line (remember that actual code path goes the line before LR points to). Note, if functions in between were called using branch instruction (b) instead of branch and link (bl) you'll not see them using this method.
(I don't have enough reputation points to write comments, so I'm editing my answer):
UPDATE for question 2:
Why do you expect that Hard_Fault_Handler has any arguments? Hard_Fault_Handler is usally a function to which address is stored in vector (exception) table. When the processor exception happens then Hard_Fault_Handler will be executed. There is no arguments passing involved doing this. But still, all registers at the time the fault happens are preserved. Specifically, if you compiled without omit-frame-pointer you can just read value of R11 (or R7 in Thumb-2 mode). However, to be sure that in your code Hard_Fault_Handler is actually a real hard fault handler, look into startup.s code and see if Hard_Fault_Handler is at the third entry in vector table. If there is an other function, it means Hard_Fault_Handler is just called from that function explicitly. See this article for details. You can also read my blog :) There is a chapter about stack which is based on Android example, but a lot of things are the same in general.
Also note, most probably in faultStackAddress should be stored a stack pointer, not a frame pointer.
UPDATE 2
Ok, lets clarify some things. Firstly, please paste the code from which you call Hard_Fault_Handler. Secondly, I guess you call it from within real HardFault exception handler. In that case you cannot expect that R11 will be at faultStackAddress[r11]. You've already mentioned it at the first sentence in your question. There will be only r0-r3, r12, lr, pc and psr.
You've also written:
But there is no FP and SP in the stack. Thus I could not unwind the
stack. Is there any solution for this?
The SP is not "in the stack" because you have it already in one of the stack registers (msp or psp). See again THIS ARTICLE. Also, FP is not crucial to unwind stack because you can do it without it (by "navigating" through saved Link Registers). Other thing is that if you dump memory below your SP you can expect FP to be just next to saved LR if you really need it.
Answering your last question: I don't now how you're verifying this code and how you're calling it (you need to paste full code). You can look into assembly of that function and see what's happening under the hood. Other thing you can do is to follow this post as a template.

x=x+1 vs. x +=1

I'm under the impression that these two commands result in the same end, namely incrementing X by 1 but that the latter is probably more efficient.
If this is not correct, please explain the diff.
If it is correct, why should the latter be more efficient? Shouldn't they both compile to the same IL?
Thanks.
From the MSDN library for +=:
Using this operator is almost the same as specifying result = result + expression, except that result is only evaluated once.
So they are not identical and that is why x += 1 will be more efficient.
Update: I just noticed that my MSDN Library link was to the JScript page instead of the VB page, which does not contain the same quote.
Therefore upon further research and testing, that answer does not apply to VB.NET. I was wrong. Here is a sample console app:
Module Module1
Sub Main()
Dim x = 0
Console.WriteLine(PlusEqual1(x))
Console.WriteLine(Add1(x))
Console.WriteLine(PlusEqual2(x))
Console.WriteLine(Add2(x))
Console.ReadLine()
End Sub
Public Function PlusEqual1(ByVal x As Integer) As Integer
x += 1
Return x
End Function
Public Function Add1(ByVal x As Integer) As Integer
x = x + 1
Return x
End Function
Public Function PlusEqual2(ByVal x As Integer) As Integer
x += 2
Return x
End Function
Public Function Add2(ByVal x As Integer) As Integer
x = x + 2
Return x
End Function
End Module
IL for both PlusEqual1 and Add1 are indeed identical:
.method public static int32 Add1(int32 x) cil managed
{
.maxstack 2
.locals init (
[0] int32 Add1)
L_0000: nop
L_0001: ldarg.0
L_0002: ldc.i4.1
L_0003: add.ovf
L_0004: starg.s x
L_0006: ldarg.0
L_0007: stloc.0
L_0008: br.s L_000a
L_000a: ldloc.0
L_000b: ret
}
The IL for PlusEqual2 and Add2 are nearly identical to that as well:
.method public static int32 Add2(int32 x) cil managed
{
.maxstack 2
.locals init (
[0] int32 Add2)
L_0000: nop
L_0001: ldarg.0
L_0002: ldc.i4.2
L_0003: add.ovf
L_0004: starg.s x
L_0006: ldarg.0
L_0007: stloc.0
L_0008: br.s L_000a
L_000a: ldloc.0
L_000b: ret
}
I wrote a simple console app:
static void Main(string[] args)
{
int i = 0;
i += 1;
i = i + 1;
Console.WriteLine(i);
}
I disassembled it using Reflector and here's what i got:
private static void Main(string[] args)
{
int i = 0;
i++;
i++;
Console.WriteLine(i);
}
They are the same.
they compile to the same, the second is just easier to type.
IMPORTANT:
The answers specifying evaluation are certainly correct in terms of what a += do, in general languages. But in VB.NET, I assume X specified in the OP is a variable or a property.
They'll probably compile to the same IL.
UPDATE (to address the probably controversy):
VB.NET is a specification of a programming language. Any compiler that conforms to what's defined in the spec can be a VB.NET implementation. If you edit the source code of the MS VB.NET compiler to generate crappy code for X += 1 case, you'll still conform to VB.NET spec (because it didn't say anything about how it's going to work. It just says the effect will be exactly the same, which makes it logical to generate the same code, indeed).
While the compiler is very very likely (and I feel it really does) generate the same code for both, but it's pretty complex piece of software. Heck, you can't even guarantee that a compiler generates the exact same code when the same code is compiled twice!
What you can feel 100% secure to say (unless you know the source code of the compiler intimately) is that a good compiler should generate the same code, performance-wise, which might or might not be the exact same code.
So many speculations! Even the conclusion with the Reflector thingy is not necessarily true because it can do optimizations while dissassembling.
So why does none of you guys just have a look into the IL code? Have a look at the following C# programme:
static void Main(string[] args)
{
int x = 2;
int y = 3;
x += 1;
y = y + 1;
Console.WriteLine(x);
Console.WriteLine(y);
}
This code snippet compiles to:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 25 (0x19)
.maxstack 2
.locals init ([0] int32 x,
[1] int32 y)
// some commands omitted here
IL_0004: ldloc.0
IL_0005: ldc.i4.1
IL_0006: add
IL_0007: stloc.0
IL_0008: ldloc.1
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stloc.1
// some commands omitted here
}
As you can see, it's in fact absolutely the same. And why is it? Because IL's purpose is to tell what to do, not how to. The optimization will be a job of the JIT compiler. Btw it's the same in VB.Net
On x86, if x is in register eax, they will both result in something like
inc eax;
So you're right, after some compilation stage, the IL will be the same.
There's a whole class of questions like this that can be answered with "trust your optimizer."
The famous myth is that
x++;
is less efficient than
++x;
because it has to store a temporary value. If you never use the temporary value, the optimizer will remove that store.
Yes, they behave the same.
No, they are probably equally efficient. Optimizers are good at that sort of thing. If you'd like to double check, write the optimized code and view it in reflector.
The optimizer probably produces the same result, if x is a simple type like int or float.
If you'd use some other language (limited VB knowledge here, can you overload +=?) where x could be one big honking object, the former creates and extra copy, which can be hundreds of megs. The latter does not.
are the same.
x=x+1
is mathematical seen a contradiction whereas
x+=1
isn't and is light to be typed.
They may be the same in VB; they are not necessarily the same in C (where the operator comes from).
In C++ it depends what datatype is x and how are operators defined. If x is an instance of some class you can get completely different results.
Or maybe you should fix the question and specify that x is an integer or whatever.
i thought the differences are due to the additional clock cycles used for memory references, but i turned out to be wrong! can't understand this thing myself
instruction type example cycles
===================================================================
ADD reg,reg add ax,bx 1
ADD mem,reg add total, cx 3
ADD reg,mem add cx,incr 2
ADD reg,immed add bx,6 1
ADD mem,immed add pointers[bx][si],6 3
ADD accum,immed add ax,10 1
INC reg inc bx 1
INC mem inc vpage 3
MOV reg,reg mov bp,sp 1
MOV mem,reg mov array[di],bx 1
MOV reg,mem mov bx,pointer 1
MOV mem,immed mov [bx],15 1
MOV reg,immed mov cx,256 1
MOV mem,accum mov total,ax 1
MOV accum,mem mov al,string 1
MOV segreg,reg16 mov ds,ax 2, 3
MOV segreg,mem16 mov es,psp 2, 3
MOV reg16,segreg mov ax,ds 1
MOV mem16,segreg mov stack_save,ss 1
MOV reg32,controlreg mov eax,cr0 22
mov eax,cr2 12
mov eax,cr3 21, 46
mov eax,cr4 14
MOV controlreg,reg32 mov cr0,eax 4
MOV reg32,debugreg mov edx,dr0 DR0-DR3,DR6,DR7=11;
DR4,DR5=12
MOV debugreg,reg32 mov dr0,ecx DR0-DR3,DR6,DR7=11;
DR4,DR5=12
source:http://turkish_rational.tripod.com/trdos/pentium.txt
the instructions may be tranlated as:
;for i = i+1 ; cycles
mov ax, [i] ; 1
add ax, 1 ; 1
mov [i], ax ; 1
;for i += 1
; dunno the syntax of instruction. it should be the pointers one :S
;for i++
inc i ; 3
;or
mov ax, [i] ; 1
inc ax ; 1
mov [i], ax ; 1
;for ++i
mov ax, [i] ; 1
;do stuff ; matters not
inc ax ; 1
mov [i], ax ; 1
all turn out to be same :S
its just some data that may be helpful. please comment!
Something worth noting is that +=, -=, *= etc. do an implicit cast.
int i = 0;
i = i + 5.5; // doesn't compile.
i += 5.5; // compiles.
At run time (at least with PERL) there is no difference. x+=1 is roughly .5 seconds faster to type than x = x+1 though
There is no difference in programmatic efficiency; just typing efficiency.
Back in the early 1980s, one of the really cool optimizations of the Lattice C Compiler was that "x = x + 1;", "x += 1;" and "x++;" all produced exactly the same machine code. If they could do it, a compiler written in this millenium should definitely be able to do it.
If x is a simple integer scalar variable, they should be the same.
If x is a large expression, possibly with side effects, +=1 and ++ should be twice as fast.
Many people concentrate on this kind of low-level optimization as if that's what optimization is all about. I assume you know it's a much bigger subject.