Forum: Compiler & IDEs sign extension bei unsigned?


von Benedikt K. (benedikt)


Angehängte Dateien:

Lesenswert?

Mittlerweile bin ich schon soweit, anstelle eines NE555 einen AVR zu 
verwenden, nur um eine PWM zu erzeugen. Daher ist das Programm auch 
extrem kurz. Das Listung des erzeugten Codes ist aber dennoch etwas 
merkwürdig.
Und zwar geht es um die Zeile
OCR0A=adcval/128;
adcval ist unsigned int. Die Division durch 128 macht der Compiler 
intelligent indem er das High Byte nach links schiebt und das Low Byte 
verwirft. Dass der Compiler wieder einen 16bit Wert erzeugt, wo doch nur 
8bit benötigt werden, daran habe ich mich schon gewöhnt, aber wiso macht 
der Compiler hier eine sign extension (das ist doch eine, oder ?) ?
Nicht dass es mich in diesem Fall stören würde, aber ich möchte dennoch 
gerne wissen, was der Compiler sich dabei denkt, sowas zu machen...

  47                 .L2:
  48                 .LM9:
  49 001a 85B7          in r24,85-0x20
  50 001c 8062          ori r24,lo8(32)
  51 001e 85BF          out 85-0x20,r24
  52                 /* #APP */
  53 0020 8895          sleep
  54
  55                 /* #NOAPP */
  56 0022 85B7          in r24,85-0x20
  57 0024 8F7D          andi r24,lo8(-33)
  58 0026 85BF          out 85-0x20,r24
  59                 .LM10:
  60 0028 8091 0000     lds r24,adcval
  61 002c 9091 0000     lds r25,(adcval)+1
  62 0030 880F          lsl r24
  63 0032 892F          mov r24,r25
  64 0034 881F          rol r24
  65 0036 990B          sbc r25,r25
  66 0038 9195          neg r25
  67 003a 86BF          out 86-0x20,r24
  68 003c 00C0          rjmp .L2

von Andreas K. (a-k)


Lesenswert?

Das ist keine sign extension. Das ist der Weg, das bei ROL 
rausgeschobene Bit an der richtigen Stelle zu plazieren.

Bei
  unsigned int temp = adcval >> 7;
ergibt sich ja ein für temp ein Wertebereich von 0..511, für R25 also 0 
oder 1. Und genau so kommt's auch raus. Eine sign extension sieht anders 
aus.

von Benedikt K. (benedikt)


Lesenswert?

Stimmt, das ist ja echt tricky. Ich habe eine Weile gebraucht bis ich 
das verstanden habe:
Gibt es bei der Multiplikation mit 2 einen Überlauf (also das Carry ist 
nach dem Schieben gesetzt), wird r25 auf 255 gesetzt (und das in einem 
Befehl, echt genial gelöst). Anschließend wird die 255 noch negiert um 
daraus eine 1 zu gewinnen.
Wenn jetzt der Compiler auch noch merken würde, dass diese geniale 
Lösung sinnlos ist, da das Highbyte nicht gebraucht wird, dann käme das 
schon an eine Assembler Lösung ran...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Benedikt K. wrote:

> Wenn jetzt der Compiler auch noch merken würde, dass diese geniale
> Lösung sinnlos ist, da das Highbyte nicht gebraucht wird, dann käme das
> schon an eine Assembler Lösung ran...

Ich habe nicht nachgeguckt, aber ich fürchte, die entsprechende
Befehlsfolge ist im Compiler einfach als Muster ,,handoptimiert''
abgelegt.  Damit kann der Compiler nicht einfach einen Teil davon
weglassen.  (Das ist also beinahe so, als wäre es in inline asm
geschrieben, da kann der Compiler auch nicht ,,reinsehen''.)

Ja, es hatte mich gerade interessiert, hier ist die Stelle im
Compiler:
1
/* 16bit logic shift right ((unsigned short)x >> i) */
2
3
const char *
4
lshrhi3_out (rtx insn, rtx operands[], int *len)
5
{
6
  if (GET_CODE (operands[2]) == CONST_INT)
7
...
8
        case 7:
9
          *len = 5;
10
          return (AS1 (lsl,%A0)     CR_TAB
11
                  AS2 (mov,%A0,%B0) CR_TAB
12
                  AS1 (rol,%A0)     CR_TAB
13
                  AS2 (sbc,%B0,%B0) CR_TAB
14
                  AS1 (neg,%B0));

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.