Module: Ikra::Translator

Defined in:
lib/translator/translator.rb,
lib/translator/ast_translator.rb,
lib/translator/kernel_builder.rb,
lib/translator/program_builder.rb,
lib/translator/block_translator.rb,
lib/translator/input_translator.rb,
lib/translator/program_launcher.rb,
lib/translator/environment_builder.rb,
lib/translator/last_returns_visitor.rb,
lib/translator/commands/array_zip_command.rb,
lib/translator/commands/command_translator.rb,
lib/translator/host_section/ast_translator.rb,
lib/translator/variable_classifier_visitor.rb,
lib/translator/array_command_struct_builder.rb,
lib/translator/commands/array_index_command.rb,
lib/translator/host_section/program_builder.rb,
lib/translator/commands/array_reduce_command.rb,
lib/translator/commands/array_combine_command.rb,
lib/translator/commands/array_stencil_command.rb,
lib/translator/commands/array_identity_command.rb,
lib/translator/kernel_launcher/kernel_launcher.rb,
lib/translator/host_section/array_host_section_command.rb,
lib/translator/kernel_launcher/for_loop_kernel_launcher.rb,
lib/translator/host_section/array_in_host_section_command.rb,
lib/translator/kernel_launcher/while_loop_kernel_launcher.rb,
lib/translator/host_section/parallel_section_invocation_visitor.rb

Overview

This module contains functionality for translating Ruby code to CUDA (C++) code.

Defined Under Namespace

Modules: Constants, KernelLaunchArgumentGenerator Classes: ASTTranslator, ArrayCommandStructBuilder, BlockTranslationResult, CommandTranslator, EntireInputTranslationResult, EnvironmentBuilder, HostSectionASTTranslator, HostSectionCommandTranslator, InputTranslationResult, LastStatementReturnsVisitor, ParallelSectionInvocationVisitor, Variable, VariableClassifier

Constant Summary collapse

BlockSelectorDummy =
:"<BLOCK>"

Class Method Summary collapse

Class Method Details

.read_file(file_name:, replacements: {}) ⇒ Object

Reads a CUDA source code file and replaces identifiers by provided substitutes.

Parameters:

  • file_name (String)

    name of source code file

  • replacements (Hash{String => String}) (defaults to: {})

    replacements



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/translator/translator.rb', line 55

def read_file(file_name:, replacements: {})
    full_name = Ikra::Configuration.resource_file_name(file_name)
    if !File.exist?(full_name)
        raise AssertionError.new("File does not exist: #{full_name}")
    end

    contents = File.open(full_name, "rb").read

    replacements.each do |s1, s2|
        replacement = "/*{#{s1}}*/"
        contents = contents.gsub(replacement, s2)
    end

    contents
end

.translate_block(block_def_node:, environment_builder:, command_id:, lexical_variables: {}, entire_input_translation: nil, pre_execution: nil, override_block_parameters: nil, block_parameters: nil) ⇒ BlockTranslationResult

Translates a Ruby block to CUDA source code. collecting information about lexical variables (environment) to the block accessed within the block block parameters that this block accepts. ‘translate_entire_input`

Parameters:

  • block_def_node (AST::BlockDefNode)

    AST (abstract syntax tree) of the block

  • environment_builder (EnvironmentBuilder)

    environment builder instance

  • block_parameters (Array{Variable}) (defaults to: nil)

    types and names of parameters

  • lexical_variables (Hash{Symbol => Object}) (defaults to: {})

    all lexical variables that are

  • command_id (Fixnum)

    a unique identifier of the block

  • pre_execution (String) (defaults to: nil)

    source code that should be run before executing the

  • override_block_parameters (Array{Variable}) (defaults to: nil)

    overrides the the declaration of

  • entire_input_translation (EntireInputTranslationResult) (defaults to: nil)

    The result of

Returns:



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
# File 'lib/translator/block_translator.rb', line 54

def translate_block(
    block_def_node:, 
    environment_builder:, 
    command_id:, 
    lexical_variables: {}, 

    # One one of the two following parameter configurations is valid:
    # a) Either this parameter is given:
    entire_input_translation: nil,

    # b) or these parameters are given (some are optional):
    pre_execution: nil, 
    override_block_parameters: nil,
    block_parameters: nil)

    # Check and prepare arguments
    if pre_execution != nil and entire_input_translation != nil
        raise ArgumentError.new("pre_execution and entire_input_translation given")
    elsif entire_input_translation != nil
        pre_execution = entire_input_translation.pre_execution
    elsif pre_execution == nil
        pre_execution = ""
    end

    if block_parameters != nil and entire_input_translation != nil
        raise ArgumentError.new("block_parameters and entire_input_translation given")
    elsif entire_input_translation != nil
        block_parameters = entire_input_translation.block_parameters
    elsif block_parameters == nil
        block_parameters = []
    end

    if override_block_parameters != nil and entire_input_translation != nil
        raise ArgumentError.new("override_block_parameters and entire_input_translation given")
    elsif entire_input_translation != nil
        override_block_parameters = entire_input_translation.override_block_parameters
    elsif override_block_parameters == nil
        override_block_parameters = block_parameters
    end


    # Build hash of parameter name -> type mappings
    block_parameter_types = {}
    for variable in block_parameters
        block_parameter_types[variable.name] = variable.type
    end

    parameter_types_string = "[" + block_parameter_types.map do |id, type| "#{id}: #{type}" end.join(", ") + "]"
    Log.info("Translating block with input types #{parameter_types_string}")

    # Add information to block_def_node
    block_def_node.parameters_names_and_types = block_parameter_types

    # Lexical variables
    lexical_variables.each do |name, value|
        block_def_node.lexical_variables_names_and_types[name] = value.ikra_type.to_union_type
    end

    # Type inference
    type_inference_visitor = TypeInference::Visitor.new
    return_type = type_inference_visitor.process_block(block_def_node)
    
    # Translation to source code
    ast_translator = ASTTranslator.new

    # Auxiliary methods are instance methods that are called by the block
    aux_methods = type_inference_visitor.all_methods.map do |method|
        ast_translator.translate_method(method)
    end

    # Generate method predeclarations
    aux_methods_predecl = type_inference_visitor.all_methods.map do |method|
        ast_translator.translate_method_predecl(method)
    end

    # Start with predeclarations
    aux_methods = aux_methods_predecl + aux_methods

    # Classify variables (lexical or local)
    block_def_node.accept(VariableClassifier.new(
        lexical_variable_names: lexical_variables.keys))

    # Translate to CUDA/C++ code
    translation_result = ast_translator.translate_block(block_def_node)

    # Load environment variables
    lexical_variables.each do |name, value|
        type = value.ikra_type
        mangled_name = environment_builder.add_object(name, value)
        translation_result.prepend("#{type.to_c_type} #{Constants::LEXICAL_VAR_PREFIX}#{name} = #{Constants::ENV_IDENTIFIER}->#{mangled_name};\n")
    end

    # Declare local variables
    block_def_node.local_variables_names_and_types.each do |name, type|
        translation_result.prepend("#{type.to_c_type} #{name};\n")
    end

    # Function signature
    mangled_name = "_block_k_#{command_id}_"

    function_parameters = ["environment_t *#{Constants::ENV_IDENTIFIER}"]

    parameter_decls = override_block_parameters.map do |variable|
        "#{variable.type.to_c_type} #{variable.name}"
    end

    function_parameters.push(*parameter_decls)

    translation_result = Translator.read_file(
        file_name: "block_function_head.cpp",
        replacements: { 
            "name" => mangled_name, 
            "result_type" => return_type.to_c_type,
            "parameters" => function_parameters.join(", "),
            "body" => wrap_in_c_block(pre_execution + "\n" + translation_result)})

    # TODO: handle more than one result type
    return BlockTranslationResult.new(
        c_source: translation_result, 
        result_type: return_type,
        function_name: mangled_name,
        aux_methods: aux_methods)
end

.wrap_in_c_block(str) ⇒ Object



48
49
50
# File 'lib/translator/translator.rb', line 48

def wrap_in_c_block(str)
    "{\n" + str.split("\n").map do |line| "    " + line end.join("\n") + "\n}\n"
end