Как вычислительная система выбирает какой набор инструкций использовать для исполнения кода?
Обязательно ли в самом коде программы задавать, что необходимо произвести работу с помощью определенных инструкций?
Нет, в коде это указывать не обязательно, компилятор производит оптимизации сам.Может ли, например, для быстрой обработки массива данных с плавающей запятой компилятор сам задать использование векторной обработки? 
Все так и происходит. 
Далее немного о том как устроен наш суровый мир.
1) При исполнении код не изменяется, какие инструкции компилятор указал делать те и исполняются.
2) При компиляции указывается совместимость с какими архитектурами требуется, исходя из этого используется разный набор инструкций.
3) Ну и как следствие для совместимости бинарники распространяются собранные с целевой древней архитектурой и новые инструкции не используются. Ну почти так. Иногда в местах с высоким требованием к скорости работы разработчики заморачиваются и делают так что исполняется код для вашей архитектуры со всеми оптимизациями.
ни как не выбирает. выбирает компилятор, в соответствии с параметрами целевой платформы. после компиляции ни какого выбора не происходит. следует учесть что платформы типа .Net, JVM, node.js и браузеры, позволяют писать относительно переносимые программы (и то с ограничениями), но сами виртуальны машины/движки, все равно реализованы под свою платформу на этапе компиляции, и даже могут иметь существенные отличия не только в опциях компилирования, но и в исходном коде для разных платформ
updПрограмма, написанная и скомпилированная один раз, может выполняться на процессорах с разными наборами инструкций и на разных версиях Windows. такая программа использует не все инструкции процессора, а только гарантированно совместимый набор инструкций. в случае игр, или ПО для проектирования, в комплект поставки могут входить наборы dll(если мы говорим о винде, или другие способы разбиения на модули), оптимизированных для разных наборов инструкций на этапе компиляции, в том числе для для использования GPU, для достижения максимального быстродействия. в этом случае, какой модуль можно использовать, определяет опять же не вся вычислительная система а головная программа (та что на универсальном наборе инструкций). и все это происходит ни коим образом не автоматически, а закладывается на этапе проектирования и реализуется в программном коде. хотя для определения типа процессора и набора инструкций, уже давно существуют стандартизированные api, обычно на уровне ОС