How many machine instructions does PIND >> 7 compile to?

I'm looking at some timing issues, and C code (and it's disassembly) is not my strong suite. So as the subject suggests, how many instructions does this code snippet compile to please?

PIND >> 7

I'm specifically interested in the >> part. Is seven right shifts seven individual right shift operations, or does the CPU have this as a single op code as a performance measure? I'm wondering if the duration of a right shift is proportional to the number of places? I'm compiling to an Uno.

Which processor? for the AVR's it will take 7 operations:

( I googled AVR shift instruction)

I'm looking at some timing issues

What sort of timing issues specifically?

Pete

Why don't you test the highest bit directly?

GCC will roll the bit left and around through the carry bit:

rol r24       /* bit 7 -> carry */
clr r24       /* clear register */
rol r24       /* carry -> bit 0 */

I'm actually looking at the fastest way to make a byte out of two high nibble reads of I/O port D. The >>7 was actually just an arbitrary number to illustrate the question. Sorry. So in reality what I have is,

byte b = (PIND & 0b11110000) + (PIND >> 4)

with data on 4 high pins of the port, which will require 4 right shift operations which is 4 clock cycles.

Thanks for the link to the AVR instructions.

byte b = (PIND & 0b11110000) + (PIND >> 4)

Addition? Surely you mean bitwise-or.

which will require 4 right shift operations which is 4 clock cycles

Nope.

  byte b = (PIND & 0b11110000) + (PIND >> 4);
 502:	89 b1       	in	r24, 0x09	; 9
 504:	29 b1       	in	r18, 0x09	; 9
 506:	22 95       	swap	r18
 508:	2f 70       	andi	r18, 0x0F	; 15
 50a:	80 7f       	andi	r24, 0xF0	; 240
 50c:	82 0f       	add	r24, r18

I suggest you stop playing games. By failing to include important details you have wasted @KeithRB's, @el_supremo's, @Whandall,'s, and @oqibidipo's time.

Bear in mind that the high nibble and low nibble of b can have different values.

Err, what about:-

KeithRB:
...or the AVR's it will take 7 operations:

If >> 7 takes 7 clock cycles, doesn't it follow that >> 4 takes 4?

No. See reply #6.

That's all very nice, but I can't understand what lines 502 -50c are really telling me. As I explained in the very first bit of my original post, I'm not familiar with disassembly. Are those lines the actual instructions? So my entire "byte b = (PIND & 0b11110000) + (PIND >> 4)" will compile to only 6 instructions in total? And that'll only take 6 cycles to make byte b?

That's even better then :slight_smile:

PS. How are you making those instructions appear? Is there something in the standard IDE?

You don't know how many cycles it will take until you put it into context, with the exact code you'll have in the final version.

  • The AVR only has one-bit shifts.
  • But it also has "swap", which swaps the two 4-bit nibbles of a register. The compiler will (sometimes?) optimize a shift longer than 3bits to use swap (as in reply 6)
  • But that won't work if you have a value longer than a single byte.
  • But shifts longer than 8bits can take advantage of byte moves. Theoretically, anyway.
  • or a shift value that isn't a constant (in which case the compiler will put together a loop.)
  • If you're doing bit tests or something, the compiler may optimize away the shift entirely.

So my entire "byte b = (PIND & 0b11110000) + (PIND >> 4)" will compile to only 6 instructions in total?

That leaves the result in a register; if b needs to get stored somewhere that will be an additional couple of cycles.

Are those lines the actual instructions?

Yes.
The compiler produces an assembly code listing, along with the source code. It is quite enlightening to study.

cossoft:
If >> 7 takes 7 clock cycles...

You assume that is true. Depending on how the value is used there may be no actual shifting.

For example, this...

  byte b = (PIND >> 7);
  Serial.println( b );

...produces this...

 508:	69 b1       	in	r22, 0x09	; 9
 50c:	70 e0       	ldi	r23, 0x00	; 0
 50e:	66 0f       	add	r22, r22
 510:	67 2f       	mov	r22, r23
 512:	66 1f       	adc	r22, r22
 514:	77 0b       	sbc	r23, r23
; actual code for printlin not included

No shift.

How are you making those instructions appear?

import fnmatch
import os
import subprocess
import string

pathok = False
pathlist = os.environ['PATH'].split( os.pathsep )
for path in pathlist:
  testme = os.path.join(path,'avr-objdump.exe')
  if os.path.exists(testme):
    pathok = True
    break

if not( pathok ):
  arduinoroot = 'C:\\Arduino\\arduino-1.0.1\\'
  pathlist.append( arduinoroot + 'hardware\\tools\\avr\\utils\\bin' )
  pathlist.append( arduinoroot + 'hardware\\tools\\avr\\bin' )
  pathlist.append( arduinoroot + 'hardware\\tools\\avr\\etc' )
  pathnew = os.pathsep.join( pathlist )
  os.environ['PATH'] = pathnew

tempdir = os.environ.get('TEMP')
tempfile = os.path.join(tempdir,'Junk.cpp')

matches = []
for root, dirnames, filenames in os.walk(tempdir):
  for filename in fnmatch.filter(filenames, '*.elf'):
    matches.append(os.path.join(root, filename))

matches.sort( key=os.path.getmtime )

if len(matches) > 0:
  f = open(tempfile, 'w')
  subprocess.call(['avr-objdump.exe','-S',matches[len(matches)-1]],stdout=f)
  f.close()
  os.system( 'start ' + tempfile )