Если вопрос стоит в том, как это сделать средствами исключительно логических операций - то см. ответ Wataru. 17 бинарных логический операций, если я правильно посчитал (с учетом того, что сдвиги на 9 и -9 можно маскировать совместно).
Если можно использовать LUT - то LUT, вероятно, будет выгоднее. Учитывая, что преобразование линейное - таблицу можно делить на части, выбирая между скоростью и памятью. Например, можно поделить на 2 части - отдельные таблицы для каждой половины из 16-битного входа, и получить расход 1кб памяти, 3 логических операции и два хождения в LUT.
Если речь о x86 cpu и можно использовать специфичные инструкции - то еще можно посмотреть в сторону sse/avx. Например, разбить вход побитово на байты и pshub, или (если есть XOP/AVX512) броадкаст его и vprotw/vpsllvw, или же vpshufbitqmb, или же vpermb,... Куча возможных вариантов.