Работа посвящена решению проблемы автоматического распараллеливания C-программ с применением средств построения языковых расширений языка Planning C 2.0. Предложены механизмы реализации расширений, доказана теорема об их реализуемости. Предложена новая технология распараллеливания тел циклов, состоящих из двух зависимых по данным частей. Предложена технология оптимизирующей векторизации многократно выполняемых циклов с расходящимися трассами итераций на векторных расширителях.
Приведённый ознакомительный фрагмент книги Технологии автоматического дедуктивного распараллеливания в языке Planning C предоставлен нашим книжным партнёром — компанией ЛитРес.
Купить и скачать полную версию книги в форматах FB2, ePub, MOBI, TXT, HTML, RTF и других
Глава 2. Встроенная трансформация программ в языке Planning C
Как уже неоднократно упоминалось, задача трансформации программы в общем случае может быть достаточно нетривиальным алгоритмом, требующим применения интеллектуальных технологий логического программирования. В таком аспекте указанная задача может быть сведена к трем основным этапам: а) разбору программы с формированием набора представленных в ней фактов и взаимосвязей между ними; б) анализу полученной базы фактов с генерацией дополнительных фактов, представляющих распараллеливающие конструкции; в) генерации выходной программы на основе результирующего набора фактов.
Соответственно, целью данной главы является определение набора языковых средств Planning C 2.0, на базе которых могут быть реализованы все вышеупомянутые этапы.
Для реализации данной цели необходимо решить задачи по реализации вышеупомянутых этапов с применением логического программирования или его элементов.
2.1. Дедуктивные макромодули: средства решения задач распараллеливания и генерации выходной программы
Первоначально в языке Planning C дедуктивные макромодули предназначались для гибкой генерации описаний вычислительных топологий (этим и объясняются некоторые их не вполне очевидные синтаксические особенности), впоследствии же их применение было расширено: в настоящее время дедуктивные макромодули используются для гибкой дедуктивной генерации произвольных фрагментов программы на основе логических правил, записанных на языке GNU Prolog, имеющем бесплатный и свободно распространяемый интерпретатор. Как будет показано в настоящей работе, дедуктивные макромодули вполне могут сгенерировать и полноценную параллельную программу.
Дедуктивный макромодуль является совокупностью статических и динамических (генерируемых на одной из стадий компиляции в ходе применения предикатов GNU-Prolog) элементов. Он оформлен в виде специального программного блока и имеет параметры, в зависимости от которых им генерируется фрагмент программного кода. Соответствующий код будет вставлен в программу в точке обращения к макромодулю, в котором будут указаны конкретные значения его параметров. Предполагается, что макромодуль будет генерировать код на этапе компиляции, точнее, на стадии препроцессинговой обработки. Соответственно, это накладывает определенные ограничения на возможные значения его параметров — это должны быть выражения, которые можно вычислить на этапе препроцессинга: предположим, что это выражения, содержащие исключительно именованные и неименованные константы, в том числе те, которые формируются в результате классических макроподстановок C/C++.
2.1.1. Синтаксис и семантика макромодуля
Предлагается следующий синтаксис декларации дедуктивного макромодуля (все элементы в описании могут разделяться пробелами):
«#» «def_module» « (» префиксная_строка»)» имя_модуля « (» [имя_параметра] {»,» имя_параметра}»)» « {»
(предикат цель произвольный_Planning_C_код)
{(предикат цель произвольный_Planning_C_код}
«}» «;»
предикат = «@» имя_предиката [» (» переменные_предиката»)»] [»: — » GNU_PROLOG_выражение]».»
цель = «@» «goal» «:-» GNU_PROLOG_выражение».»
Здесь произвольный_Planning_C_код должен представлять собой фрагмент синтаксически корректного языкового выражения, не содержащего символа «@». Это может быть описатель любого статического элемента генерируемого кода. GNU_PROLOG_выражение может содержать вызовы любых предикатов GNU Prolog, в том числе генерирующих консольный вывод — результаты этого вывода и будут использоваться в качестве сгенерированных фрагментов кода. В большинстве случаев вывод будет генерироваться предикатом write.
Обращение к макромодулю имеет формат:
имя_модуля « (» [значение_параметра] {»,» значение_параметра}»)» «;»
В точке обращении к макромодулю компилятором выполняются следующие действия:
а) вычисляются все параметры обращения;
б) значения параметров подставляются в текст модуля вместо соответствующих лексем — имен параметров;
в) из текста модуля исключаются все предикаты, из которых формируется текст логической GNU Prolog-программы;
г) фрагмент модуля, содержащий какую-либо из целей, заменяется результатом доказательства этой цели (то есть блоком выведенных на консоль в ходе доказательства строк) в контексте сформированной логической GNU Prolog-программы;
д) в программу на Planning C вместо обращения к макромодулю вставляется код, содержащий префиксную строку (которая может быть пустой) и результирующий текст модуля, обрамленный фигурными скобками.
Необходимо детализировать возможные типы параметров. Каждый параметр (после выполнения всех макроподстановок и подстановок значений констант, определенных в программе с помощью ключевого слова const) должен быть константным выражением, содержащим только неименованные константы. Такое выражение может быть числом/числовым выражением, или строкой (заключенной в апострофы), или списком, который может содержать числа, строки и другие списки. Числовые выражения вычисляются, применительно к результирующим значениям действуют следующие простые правила:
— целые числа так и считаются целыми;
— близкие к нулю вещественные константы считаются целочисленными нулями;
— близкие к целым вещественные значения считаются соответствующими целыми (с округлением);
— прочие значения считаются вещественными.
Развернутый в константное выражение параметр распознается по следующим правилам:
а) если он начинается с « [», то это список, который передается в макромодуль без изменения вплоть до»]» с учетом сбалансированности по вложенным парам квадратных скобок;
б) если он начинается с «'», то это строка, которая передается без изменения вплоть до закрывающего апострофа «'» с учетом наличия в строке возможных пар апострофов, представляющих апостроф, являющийся одним из символов строки;
в) иначе делается попытка распознать параметр как число/числовое выражение.
Определение макромодуля может содержать обращения к иным макромодулям, записанным в той же форме «имя_модуля (параметры);». Таким образом, реализованы вложенные макромодули, с помощью которых можно (в некоторых случаях) сократить общий объем модулей и повысить гибкость их применения.
2.1.2. Расширение базовой семантики макромодуля: порождающее программирование
Приведем общую схему порожденного макромодулем фрагмента, которая, в ранних версиях языка, предназначалась почти исключительно для генерации описателей вычислительных топологий:
префиксная_строка « {» сгенерированный_макромодулем_код»}»
Уже очевидно, что возможно применение макромодулей для параметризованной генерации синтаксических конструкций, включающих префиксованный блок (П-блок) в фигурных скобках: деклараций структур, классов, уний, функций. Очевидно, что если ввести синтаксические средства, позволяющие убрать префиксную строку (возможность ее изменения заложена в макромодуль изначально) и обрамляющие скобки, то задача порождения принципиально произвольного Planning C-кода будет решена. Соответственно, определим два специальных предиката, управляющих порождением кода:
— prefix_off, выключающий префиксную строку,
— brackets_off, выключающий обрамляющие фигурные скобки.
Эти предикаты имеют глобальный для всего макромодуля эффект, соответственно они могут быть вызваны в любом из предикатов/целей модуля.
Таким образом, реализовано полноценное логическое порождающее программирование, которое может быть применено для решения сложных, интеллектуальных задач:
а) дедуктивного анализа фактов, представляющих, в частности, разобранную входную программу, с выработкой фактов, указывающих на необходимость применения распараллеливающих конструкций;
б) генерации кода на основании исходных и полученных фактов.
2.1.3. Некоторые простые примеры логического порождающего программирования на базе макромодулей
1. Пусть макромодуль генерирует серию заголовков цикла — в этом случае используется П-блок с опущенными префиксом и скобками. Далее приведен пример, содержащий соответствующий макромодуль big_loop, который вызывается для генерации тройного вложенного цикла (i = 0..2, j = 0..3, k = 0..4).
#include <iostream>
using namespace std;
#def_module () big_loop (Vars, Lows, Highs) {
@goal:-brackets_off.
@loop ([], [], []):-!.
@loop ([V VT], [L LT], [H HT]):-
write (’for (int»),write (V),write (»=»),write (L),write (»;»),
write (V),write (»<=»),write (H),write (»;»),
write (V),write (»++)»),
loop (VT, LT, HT).
@goal:-loop (Vars, Lows, Highs).
};
int main () {
big_loop ([’i’,’j’,’k’], [0,0,0], [2,3,4])
cout <<«1»;
cout <<endl;
return 0;
}
2. Рассмотрим применение макромодуля tree_node для формирования декларацию типа элемента n-арного дерева (n> = 2).
#def_module (struct) tree_node (ID, Type, Name, Arity) {
@goal:-brackets_off.
@goal:-write (ID). {
@goal:-write (Type),write (»»),write (Name),write (»;»).
Конец ознакомительного фрагмента.
Приведённый ознакомительный фрагмент книги Технологии автоматического дедуктивного распараллеливания в языке Planning C предоставлен нашим книжным партнёром — компанией ЛитРес.
Купить и скачать полную версию книги в форматах FB2, ePub, MOBI, TXT, HTML, RTF и других