Ремонт принтеров, сканнеров, факсов и остальной офисной техники


назад Оглавление вперед




[168]

Компиляция того же самого выражения с типом связи return должна породить команды

(assign val (const 5)) (goto (reg continue))

В первом случае выполнение продолжится на следующей команде последовательности. Во втором мы вернемся из процедуры. В обоих случаях значение выражения будет помещено в целевой регистр val.

Последовательности команд и использование стека

Каждый генератор кода возвращает последовательность команд (instruction sequence), содержащую порожденный для выражения объектный код. Порождение кода для составных выражений достигается путем сочетания более простых сегментов, порожденных генераторами кода для подвыражений, так же, как вычисление составного выражения проходит через вычисление подвыражений.

Простейший способ сочетания последовательностей команд - процедура под названием append-instruction-sequences. Она принимает в качестве аргументов произвольное число последовательностей команд, которые надо выполнить одну за другой. Процедура склеивает их и возвращает полученную последовательность. А именно, если (посл]) и (посл) - последовательности команд, то вычисление

(append-instruction-sequences (посл]) (посл)

вернет последовательность

(посл]) (посл2)

Когда требуется сохранять регистры, генераторы кода используют preserving, более сложный метод сочетания последовательностей команд. Preserving принимает три аргумента: множество регистров и две последовательности, которые требуется выполнить одна за другой. Эта процедура склеивает последовательности таким образом, что содержимое всех регистров из множества сохраняется во время выполнения первой последовательности, если оно нужно при выполнении второй. Таким образом, если первая последовательность изменяет регистр, а второй последовательности нужно его исходное содержимое, preserving оборачивает вокруг первой последовательности команды save и restore для этого регистра, прежде чем склеить последовательности. В противном случае она просто возвращает склеенные последовательности команд. Так, например,

(preserving (list (рев]) (рев2)) (посл]) (посл)

порождает одну из следующих четырех последовательностей команд, в зависимости от того, как (посл]) и (посл) используют (рег]) и (рег):

(посл]) ( посл2 )


или

(save (рее)) (посл

(restore (рее) или

(save (рее2)) ( посл1 )

(restore (рее2)) ( посл2 )

или

(save (рее2)) (save реец)) ( посл1 )

(restore (рее1)) (restore (рее2))

(посл2)

Сочетая последовательности команд с помощью preserving, компилятор избегает лишних операций со стеком. Кроме того, при этом забота о том, стоит ли порождать save и restore, целиком оказывается заключенной в процедуре preserving и отделяется от забот, которые будут нас волновать при написании отдельных генераторов кода. В сущности, ни одна команда save или restore не порождается генераторами кода явно.

В принципе мы могли бы представлять последовательность команд просто как список отдельных команд. В таком случае append-instruction-se-quences могла бы склеивать последовательности с помощью обычного append для списков. Однако тогда preserving оказалась бы более сложной операцией, поскольку ей пришлось бы исследовать каждую последовательность команд и выяснять, как там используются регистры. Preserving была бы при этом сложной и неэффективной, поскольку она анализировала бы каждый из своих аргументов-последовательностей, при том, что сами эти последовательности могли быть созданы вызовами preserving, и в этом случае их части были бы уже проанализированы. Чтобы избежать такого многократного анализа, мы с каждой последовательностью команд будем связывать некоторую информацию о том, как она использует регистры. При порождении элементарной последовательности мы будем указывать эту информацию явно, а процедуры, сочетающие последовательности, будут выводить информацию об использовании регистров для составной последовательности из информации, связанной с ее последовательностями-компонентами.

Последовательность команд будет содержать три вида информации:

•множество регистров, которые должны быть инициализированы, прежде чем выполняются команды из последовательности (говорится, что последовательность нуждается (needs) в этих регистрах),

•множество регистров, значения которых последовательность изменяет, и

•сами команды (называемые также предложениями (statements)) в последовательности.


Мы будем представлять последовательность команд в виде списка из трех частей. Таким образом, конструктор для последовательностей команд таков:

(define (make-instruction-sequence needs modifies statements) (list needs modifies statements))

Например, последовательность из двух команд, которая ищет значение переменной x в текущем окружении, присваивает его val, а затем возвращается, требует, чтобы были проинициализированы регистры env и continue, и изменяет регистр val. Следовательно, эту последовательность можно построить так:

(make-instruction-sequence (env continue) (val) ((assign val

(op lookup-variable-value) (const x) (reg env)) (goto (reg continue))))

Иногда нам нужно будет строить последовательность без команд:

(define (empty-instruction-sequence)

(make-instruction-sequence () () ()))

Процедуры для сочетания последовательностей команд приведены в разделе 5.5.4.

Упражнение 5.31.

Во время вычисления вызова процедуры вычислитель с явным управлением всегда сохраняет и восстанавливает регистр env при вычислении оператора, сохраняет и восстанавливает env при вычислении каждого операнда (кроме последнего), сохраняет и восстанавливает argl при вычислении каждого операнда, а также сохраняет и восстанавливает proc при вычислении последовательности операндов. Для каждой из следующих комбинаций скажите, какие из этих операций save и restore излишни и могут быть исключены с помощью механизма preserving:

(f x y)

((f) x y)

(f (g x) y) (f (g x) y)

Упражнение 5.32.

С помощью механизма preserving компилятор сможет избежать сохранения и восстановления env при вычислении оператора комбинации в случае, если это символ. Такие оптимизации можно было бы встроить и в интерпретатор. В сущности, вычислитель с явным управлением из раздела 5.4 уже проводит одну подобную оптимизацию, поскольку рассматривает комбинацию без операндов как особый случай.

a.Расширьте вычислитель с явным управлением так, чтобы он как особый случай рассматривал комбинации, в которых оператором является символ, и при вычислении таких выражений использовал это свойство оператора.

b.Лиза П. Хакер говорит, что если заставить интерпретатор рассматривать все больше особых случаев, то можно включить в него все оптимизации компилятора, и при этом все преимущество компиляции пропадет. Каково Ваше мнение?



[стр.Начало] [стр.1] [стр.2] [стр.3] [стр.4] [стр.5] [стр.6] [стр.7] [стр.8] [стр.9] [стр.10] [стр.11] [стр.12] [стр.13] [стр.14] [стр.15] [стр.16] [стр.17] [стр.18] [стр.19] [стр.20] [стр.21] [стр.22] [стр.23] [стр.24] [стр.25] [стр.26] [стр.27] [стр.28] [стр.29] [стр.30] [стр.31] [стр.32] [стр.33] [стр.34] [стр.35] [стр.36] [стр.37] [стр.38] [стр.39] [стр.40] [стр.41] [стр.42] [стр.43] [стр.44] [стр.45] [стр.46] [стр.47] [стр.48] [стр.49] [стр.50] [стр.51] [стр.52] [стр.53] [стр.54] [стр.55] [стр.56] [стр.57] [стр.58] [стр.59] [стр.60] [стр.61] [стр.62] [стр.63] [стр.64] [стр.65] [стр.66] [стр.67] [стр.68] [стр.69] [стр.70] [стр.71] [стр.72] [стр.73] [стр.74] [стр.75] [стр.76] [стр.77] [стр.78] [стр.79] [стр.80] [стр.81] [стр.82] [стр.83] [стр.84] [стр.85] [стр.86] [стр.87] [стр.88] [стр.89] [стр.90] [стр.91] [стр.92] [стр.93] [стр.94] [стр.95] [стр.96] [стр.97] [стр.98] [стр.99] [стр.100] [стр.101] [стр.102] [стр.103] [стр.104] [стр.105] [стр.106] [стр.107] [стр.108] [стр.109] [стр.110] [стр.111] [стр.112] [стр.113] [стр.114] [стр.115] [стр.116] [стр.117] [стр.118] [стр.119] [стр.120] [стр.121] [стр.122] [стр.123] [стр.124] [стр.125] [стр.126] [стр.127] [стр.128] [стр.129] [стр.130] [стр.131] [стр.132] [стр.133] [стр.134] [стр.135] [стр.136] [стр.137] [стр.138] [стр.139] [стр.140] [стр.141] [стр.142] [стр.143] [стр.144] [стр.145] [стр.146] [стр.147] [стр.148] [стр.149] [стр.150] [стр.151] [стр.152] [стр.153] [стр.154] [стр.155] [стр.156] [стр.157] [стр.158] [стр.159] [стр.160] [стр.161] [стр.162] [стр.163] [стр.164] [стр.165] [стр.166] [стр.167] [стр.168] [стр.169] [стр.170] [стр.171] [стр.172] [стр.173] [стр.174] [стр.175] [стр.176] [стр.177] [стр.178] [стр.179] [стр.180] [стр.181] [стр.182] [стр.183] [стр.184] [стр.185] [стр.186] [стр.187] [стр.188] [стр.189] [стр.190] [стр.191] [стр.192] [стр.193] [стр.194] [стр.195] [стр.196]