Как вы контролируете то, что оптимизирует ваш компилятор C? - PullRequest
2 голосов
/ 15 апреля 2010

Я пишу прошивку для встроенного устройства в C, используя IDE Silicon Labs и компилятор SDCC. Архитектура устройства основана на семействе 8051. Рассматриваемая функция показана ниже. Эта функция используется для настройки портов на моем MCU для управления шаговым двигателем. Он вызывается обработчиком прерывания. Большой оператор switch просто устанавливает для портов правильное значение для следующего шага двигателя. Нижняя часть функции рассматривает вход от датчика эффекта Холла и количество перемещенных шагов, чтобы определить, не остановился ли двигатель. Проблема в том, что почему-то второе утверждение IF, которое выглядит так if (StallDetector > (GapSize + 20)) { HandleStallEvent(); }, всегда кажется оптимизированным. Если я пытаюсь установить точку останова на HandleStallEvent() вызове, IDE выдает мне сообщение «Нет корреляции адресов с этим номером строки». Я не очень хорош в чтении ассемблера, чтобы сказать, что он делает, но я вставил фрагмент из вывода asm ниже. Любая помощь будет высоко ценится.

void OperateStepper(void)
{
    //static bit LastHomeMagState = HomeSensor;
    static bit LastPosMagState = PosSensor;
    if(PulseMotor)
    {
        if(MoveDirection == 1) // Go clockwise
        {
            switch(STEPPER_POSITION) 
            {
                case 'A': 
                     STEPPER_POSITION = 'B';
                     P1 = 0xFD;
                     break;
                case 'B':
                     STEPPER_POSITION = 'C';
                     P1 = 0xFF;
                     break;
                case 'C':
                     STEPPER_POSITION = 'D';
                     P1 = 0xFE;
                     break;
                case 'D':
                     STEPPER_POSITION = 'A';
                     P1 = 0xFC;
                     break; 
                default:
                     STEPPER_POSITION = 'A';
                     P1 = 0xFC;
            }   //end switch
        }
        else                // Go CounterClockwise
        {
            switch(STEPPER_POSITION) 
            {
                case 'A': 
                     STEPPER_POSITION = 'D';
                     P1 = 0xFE;
                     break;
                case 'B': 
                     STEPPER_POSITION = 'A';
                     P1 = 0xFC;
                     break;
                case 'C': 
                     STEPPER_POSITION = 'B';
                     P1 = 0xFD;
                     break;
                case 'D': 
                     STEPPER_POSITION = 'C';
                     P1 = 0xFF;
                     break; 
                default: 
                     STEPPER_POSITION = 'A';
                     P1 = 0xFE;
            }   //end switch
        }   //end else

        MotorSteps++;
        StallDetector++;

        if(PosSensor != LastPosMagState)
        {
            StallDetector = 0;

            LastPosMagState = PosSensor;
        }
        else
        {
            if (PosSensor == ON) 
            {
                if (StallDetector > (MagnetSize + 20))
                {
                    HandleStallEvent();
                }
            }
            else if (PosSensor == OFF) 
            {
                if (StallDetector > (GapSize + 20))
                {
                    HandleStallEvent();
                }
            }
        }

    }   //end if PulseMotor
}

... и вывод asm для нижней части этой функции ...

;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:653: if(PosSensor != LastPosMagState)
    mov c,_P1_4
    jb  _OperateStepper_LastPosMagState_1_1,00158$
    cpl c
00158$:
    jc  00126$
    C$MotionControl.c$655$3$7 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:655: StallDetector = 0;
    clr a
    mov _StallDetector,a
    mov (_StallDetector + 1),a
    C$MotionControl.c$657$3$7 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:657: LastPosMagState = PosSensor;
    mov c,_P1_4
    mov _OperateStepper_LastPosMagState_1_1,c
    ret
00126$:
    C$MotionControl.c$661$2$8 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:661: if (PosSensor == ON) 
    jb  _P1_4,00123$
    C$MotionControl.c$663$4$9 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:663: if (StallDetector > (MagnetSize + 20))
    mov a,_MagnetSize
    mov r2,a
    rlc a
    subb    a,acc
    mov r3,a
    mov a,#0x14
    add a,r2
    mov r2,a
    clr a
    addc    a,r3
    mov r3,a
    clr c
    mov a,r2
    subb    a,_StallDetector
    mov a,r3
    subb    a,(_StallDetector + 1)
    jnc 00130$
    C$MotionControl.c$665$5$10 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:665: HandleStallEvent();
    ljmp    _HandleStallEvent
00123$:
    C$MotionControl.c$668$2$8 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:668: else if (PosSensor == OFF) 
    jnb _P1_4,00130$
    C$MotionControl.c$670$4$11 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:670: if (StallDetector > (GapSize + 20))
    mov a,#0x14
    add a,_GapSize
    mov r2,a
    clr a
    addc    a,(_GapSize + 1)
    mov r3,a
    clr c
    mov a,r2
    subb    a,_StallDetector
    mov a,r3
    subb    a,(_StallDetector + 1)
    jnc 00130$
    C$MotionControl.c$672$5$12 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:672: HandleStallEvent();
    C$MotionControl.c$678$2$1 ==.
    XG$OperateStepper$0$0 ==.
    ljmp    _HandleStallEvent
00130$:
    ret

Мне кажется, что компилятор НЕ оптимизирует в этот второй оператор if из представлений asm, но если это так, почему среда IDE не позволяет мне устанавливать точку останова там? Может быть, это просто тупая IDE!

Ответы [ 4 ]

5 голосов
/ 16 апреля 2010

Это называется "оптимизация хвостового вызова".

OperateStepper () ничего не делает после вызова HandleStallEvent (), поэтому нет смысла возвращаться к нему. Вы просто выполняете RET для RET, что является пустой тратой инструкции И слот стека.

Для получения более подробной информации прочитайте заметки MIT AI Lab "Lambda: The Ultimate ...".

Установите точку останова в процедуре HandleStallEvent (), а не в вызове.

3 голосов
/ 16 апреля 2010

Оператор IF не оптимизируется. Это код для него.

    C$MotionControl.c$670$4$11 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:670: if (StallDetector > (GapSize + 20))
    mov a,#0x14       ; r2,r3 = 20 + GapSize
    add a,_GapSize    ; (adding a 16-bit number in two 8-bit steps)
    mov r2,a
    clr a
    addc    a,(_GapSize + 1)
    mov r3,a
    clr c
    mov a,r2          ; subtracting in two 8-bit steps
    subb    a,_StallDetector
    mov a,r3
    subb    a,(_StallDetector + 1)
    jnc 00130$        ; jump if carry not set (fall through if carry set)
    C$MotionControl.c$672$5$12 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:672: HandleStallEvent();
    C$MotionControl.c$678$2$1 ==.
    XG$OperateStepper$0$0 ==.
    ljmp    _HandleStallEvent    ; it knows HandleStallEvent does not return!
00130$:                            ; or rather, it knows this handler cannot return, so there's no need to call.
    ret

Я заметил, что в 3-й до последней строки происходит нечто забавное. Это не вызов функции для HandleStallEvent. Он делает прыжок в длину, поэтому он, очевидно, знает, что HandleStallEvent не может вернуться. Я также вижу, что в двух вышеупомянутых строках определяются символы ассемблера, которые связывают номер строки с инструкцией перехода. Итак, у него есть символ для строки 678. Если среда IDE не позволит вам установить точку останова в строке 678, возможно, вы сможете получить шестнадцатеричный адрес строки 678 и установить его в шестнадцатеричном адресе. Еще одна вещь, которую вы могли бы попробовать, это вставить определение локальной переменной, например, int breakhere = 1 перед этой строкой, и посмотреть, дает ли это вам некоторые инструкции, которые вы можете разбить.

Кстати, вы можете видеть, что процессор мыслит в терминах 8-битных чисел, поэтому, если вы можете использовать char вместо short, он сохранит инструкции. Стоит ли сэкономленное время, зависит от того, какой процент времени машина находится в этом коде.

Кстати, если вы хотите выжать производительность из этого щенка, то, на что я опирался, когда занимался встроенной работой, случайным образом останавливал IDE (или Intel "Blue Box" ICE). Вот кое-что об этом.

1 голос
/ 16 апреля 2010

Способ настройки оптимизации зависит от компилятора. Руководство для SDCC имеет опции оптимизации, перечисленные в разделе 3.28. Вы можете использовать обе опции командной строки или прагмы на уровне исходного кода. Попробуйте отключить оптимизацию во всем мире, чтобы увидеть, получаете ли вы тот же эффект. Обычно пошаговое выполнение кода в отладчике с отключенными оптимизациями устраняет проблему невозможности установить точку останова. Если это работает нормально, вы можете попробовать отключить подозрительные оптимизации на функциональном уровне с помощью прагм, чтобы увидеть, какая из них может быть причиной проблемы.

1 голос
/ 15 апреля 2010

Обычно вы можете настроить оптимизатор с помощью операторов #pragma. Я не знаю точный синтаксис вашего компилятора, но вы сможете найти его в документации, поставляемой с вашим компилятором / ide.

Примерно так

#pragma optimize( "", off )
//now the function which should not be optimized
#pragma optimize( "", on )
...