implemented more instructions
authorJacob Lifshay <programmerjake@gmail.com>
Thu, 3 Aug 2017 22:50:58 +0000 (15:50 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Thu, 3 Aug 2017 22:50:58 +0000 (15:50 -0700)
src/llvm_wrapper/llvm_wrapper.h
src/spirv_to_llvm/spirv_to_llvm.cpp
src/spirv_to_llvm/spirv_to_llvm.h
test-files/tri.frag [new file with mode: 0644]
test-files/tri.frag.spv [new file with mode: 0644]
test-files/tri.vert [new file with mode: 0644]
test-files/tri.vert.spv [new file with mode: 0644]

index f1fcb6cc4dc0670fed84a7f2b99c1adb2336e5db..91ccb0e95e466524197075c052b1ffeb00c812f6 100644 (file)
@@ -349,6 +349,29 @@ struct Builder : public Wrapper<::LLVMBuilderRef, Builder_deleter>
     {
         return Builder(::LLVMCreateBuilderInContext(context));
     }
+    static ::LLVMValueRef build_smod(::LLVMBuilderRef builder,
+                                     ::LLVMValueRef lhs,
+                                     ::LLVMValueRef rhs,
+                                     const char *result_name)
+    {
+        auto srem_result = ::LLVMBuildSRem(builder, lhs, rhs, "");
+        auto zero_constant = ::LLVMConstInt(::LLVMTypeOf(lhs), 0, false);
+        auto different_signs = ::LLVMBuildICmp(
+            builder, ::LLVMIntSLT, ::LLVMBuildXor(builder, lhs, rhs, ""), zero_constant, "");
+        auto imperfectly_divides =
+            ::LLVMBuildICmp(builder, ::LLVMIntNE, srem_result, zero_constant, "");
+        auto adjustment =
+            ::LLVMBuildSelect(builder,
+                              ::LLVMBuildAnd(builder, different_signs, imperfectly_divides, ""),
+                              rhs,
+                              zero_constant,
+                              "");
+        return ::LLVMBuildAdd(builder, srem_result, adjustment, result_name);
+    }
+    ::LLVMValueRef build_smod(::LLVMValueRef lhs, ::LLVMValueRef rhs, const char *result_name) const
+    {
+        return build_smod(get(), lhs, rhs, result_name);
+    }
 };
 
 inline ::LLVMTypeRef get_scalar_or_vector_element_type(::LLVMTypeRef type)
@@ -441,7 +464,8 @@ struct Orc_jit_stack : public Wrapper<::LLVMOrcJITStackRef, Orc_jit_stack_delete
         return add_eagerly_compiled_ir(
             get(), std::move(module), symbol_resolver_callback, symbol_resolver_user_data);
     }
-    static std::uintptr_t get_symbol_address(::LLVMOrcJITStackRef orc_jit_stack, const char *symbol_name)
+    static std::uintptr_t get_symbol_address(::LLVMOrcJITStackRef orc_jit_stack,
+                                             const char *symbol_name)
     {
         return ::LLVMOrcGetSymbolAddress(orc_jit_stack, symbol_name);
     }
index 09f567d5869e4b550caf68e712697180664f314f..1f901fab1ff7a29e44111d65865bd136e3263916 100644 (file)
@@ -654,6 +654,48 @@ private:
             throw Parser_error(instruction_start_index, instruction_start_index, "type mismatch");
         return retval;
     }
+    unsigned long long get_unsigned_integer_constant(Id id, std::size_t instruction_start_index)
+    {
+        auto &constant = get_id_state(id).constant;
+        if(!constant)
+            throw Parser_error(
+                instruction_start_index, instruction_start_index, "id is not a constant integer");
+        if(auto *type = dynamic_cast<Simple_type_descriptor *>(constant->type.get()))
+        {
+            auto llvm_type = type->get_or_make_type();
+            if(::LLVMGetTypeKind(llvm_type) != ::LLVMIntegerTypeKind)
+                throw Parser_error(instruction_start_index,
+                                   instruction_start_index,
+                                   "id is not a constant integer");
+        }
+        else
+        {
+            throw Parser_error(
+                instruction_start_index, instruction_start_index, "id is not a constant integer");
+        }
+        return ::LLVMConstIntGetZExtValue(constant->get_or_make_value());
+    }
+    long long get_signed_integer_constant(Id id, std::size_t instruction_start_index)
+    {
+        auto &constant = get_id_state(id).constant;
+        if(!constant)
+            throw Parser_error(
+                instruction_start_index, instruction_start_index, "id is not a constant integer");
+        if(auto *type = dynamic_cast<Simple_type_descriptor *>(constant->type.get()))
+        {
+            auto llvm_type = type->get_or_make_type();
+            if(::LLVMGetTypeKind(llvm_type) != ::LLVMIntegerTypeKind)
+                throw Parser_error(instruction_start_index,
+                                   instruction_start_index,
+                                   "id is not a constant integer");
+        }
+        else
+        {
+            throw Parser_error(
+                instruction_start_index, instruction_start_index, "id is not a constant integer");
+        }
+        return ::LLVMConstIntGetSExtValue(constant->get_or_make_value());
+    }
     std::string get_name(Id id)
     {
         auto &name = get_id_state(id).name;
@@ -2289,11 +2331,26 @@ void Spirv_to_llvm::handle_instruction_op_type_sampled_image(Op_type_sampled_ima
 void Spirv_to_llvm::handle_instruction_op_type_array(Op_type_array instruction,
                                                      std::size_t instruction_start_index)
 {
-#warning finish
-    throw Parser_error(instruction_start_index,
-                       instruction_start_index,
-                       "instruction not implemented: "
-                           + std::string(get_enumerant_name(instruction.get_operation())));
+    switch(stage)
+    {
+    case Stage::calculate_types:
+    {
+        auto &state = get_id_state(instruction.result);
+        auto length = get_unsigned_integer_constant(instruction.length, instruction_start_index);
+        if(length <= 0)
+            throw Parser_error(instruction_start_index,
+                               instruction_start_index,
+                               "OpTypeArray length must be a positive constant integer");
+        state.type = std::make_shared<Array_type_descriptor>(
+            state.decorations,
+            get_type(instruction.element_type, instruction_start_index),
+            length,
+            instruction_start_index);
+        break;
+    }
+    case Stage::generate_code:
+        break;
+    }
 }
 
 void Spirv_to_llvm::handle_instruction_op_type_runtime_array(Op_type_runtime_array instruction,
@@ -2739,7 +2796,10 @@ void Spirv_to_llvm::handle_instruction_op_function(Op_function instruction,
                                    + std::string(get_enumerant_name(instruction.get_operation())));
         auto function_type =
             get_type<Function_type_descriptor>(instruction.function_type, instruction_start_index);
-        auto function_name = get_or_make_prefixed_name(get_name(current_function_id));
+        auto function_name = get_name(current_function_id);
+        if(function_name.empty() && state.op_entry_points.size() == 1)
+            function_name = std::string(state.op_entry_points[0].entry_point.name);
+        function_name = get_or_make_prefixed_name(std::move(function_name));
         auto function = ::LLVMAddFunction(
             module.get(), function_name.c_str(), function_type->get_or_make_type());
         llvm_wrapper::Module::set_function_target_machine(function, target_machine);
@@ -3296,6 +3356,13 @@ void Spirv_to_llvm::handle_instruction_op_access_chain(Op_access_chain instructi
                 }
                 void operator()(Matrix_type_descriptor &)
                 {
+#warning finish
+                    throw Parser_error(instruction_start_index,
+                                       instruction_start_index,
+                                       "unimplemented composite type for OpAccessChain");
+                }
+                void operator()(Array_type_descriptor &)
+                {
 #warning finish
                     throw Parser_error(instruction_start_index,
                                        instruction_start_index,
@@ -3546,6 +3613,13 @@ void Spirv_to_llvm::handle_instruction_op_composite_construct(Op_composite_const
             }
             void operator()(Matrix_type_descriptor &)
             {
+#warning finish
+                throw Parser_error(instruction_start_index,
+                                   instruction_start_index,
+                                   "unimplemented result type for OpCompositeConstruct");
+            }
+            void operator()(Array_type_descriptor &)
+            {
 #warning finish
                 throw Parser_error(instruction_start_index,
                                    instruction_start_index,
@@ -3632,6 +3706,13 @@ void Spirv_to_llvm::handle_instruction_op_composite_extract(Op_composite_extract
                 }
                 void operator()(Matrix_type_descriptor &)
                 {
+#warning finish
+                    throw Parser_error(instruction_start_index,
+                                       instruction_start_index,
+                                       "unimplemented composite type for OpCompositeExtract");
+                }
+                void operator()(Array_type_descriptor &)
+                {
 #warning finish
                     throw Parser_error(instruction_start_index,
                                        instruction_start_index,
@@ -3957,11 +4038,28 @@ void Spirv_to_llvm::handle_instruction_op_convert_f_to_s(Op_convert_f_to_s instr
 void Spirv_to_llvm::handle_instruction_op_convert_s_to_f(Op_convert_s_to_f instruction,
                                                          std::size_t instruction_start_index)
 {
-#warning finish
-    throw Parser_error(instruction_start_index,
-                       instruction_start_index,
-                       "instruction not implemented: "
-                           + std::string(get_enumerant_name(instruction.get_operation())));
+    switch(stage)
+    {
+    case Stage::calculate_types:
+        break;
+    case Stage::generate_code:
+    {
+        auto &state = get_id_state(instruction.result);
+        if(!state.decorations.empty())
+            throw Parser_error(instruction_start_index,
+                               instruction_start_index,
+                               "decorations on instruction not implemented: "
+                                   + std::string(get_enumerant_name(instruction.get_operation())));
+        auto result_type = get_type(instruction.result_type, instruction_start_index);
+        state.value =
+            Value(::LLVMBuildSIToFP(builder.get(),
+                                    get_id_state(instruction.signed_value).value.value().value,
+                                    result_type->get_or_make_type(),
+                                    get_name(instruction.result).c_str()),
+                  result_type);
+        break;
+    }
+    }
 }
 
 void Spirv_to_llvm::handle_instruction_op_convert_u_to_f(Op_convert_u_to_f instruction,
@@ -4223,11 +4321,27 @@ void Spirv_to_llvm::handle_instruction_op_i_mul(Op_i_mul instruction,
 void Spirv_to_llvm::handle_instruction_op_f_mul(Op_f_mul instruction,
                                                 std::size_t instruction_start_index)
 {
-#warning finish
-    throw Parser_error(instruction_start_index,
-                       instruction_start_index,
-                       "instruction not implemented: "
-                           + std::string(get_enumerant_name(instruction.get_operation())));
+    switch(stage)
+    {
+    case Stage::calculate_types:
+        break;
+    case Stage::generate_code:
+    {
+        auto &state = get_id_state(instruction.result);
+        if(!state.decorations.empty())
+            throw Parser_error(instruction_start_index,
+                               instruction_start_index,
+                               "decorations on instruction not implemented: "
+                                   + std::string(get_enumerant_name(instruction.get_operation())));
+        auto result_type = get_type(instruction.result_type, instruction_start_index);
+        state.value = Value(::LLVMBuildFMul(builder.get(),
+                                            get_id_state(instruction.operand_1).value.value().value,
+                                            get_id_state(instruction.operand_2).value.value().value,
+                                            get_name(instruction.result).c_str()),
+                            result_type);
+        break;
+    }
+    }
 }
 
 void Spirv_to_llvm::handle_instruction_op_u_div(Op_u_div instruction,
@@ -4283,11 +4397,27 @@ void Spirv_to_llvm::handle_instruction_op_s_rem(Op_s_rem instruction,
 void Spirv_to_llvm::handle_instruction_op_s_mod(Op_s_mod instruction,
                                                 std::size_t instruction_start_index)
 {
-#warning finish
-    throw Parser_error(instruction_start_index,
-                       instruction_start_index,
-                       "instruction not implemented: "
-                           + std::string(get_enumerant_name(instruction.get_operation())));
+    switch(stage)
+    {
+    case Stage::calculate_types:
+        break;
+    case Stage::generate_code:
+    {
+        auto &state = get_id_state(instruction.result);
+        if(!state.decorations.empty())
+            throw Parser_error(instruction_start_index,
+                               instruction_start_index,
+                               "decorations on instruction not implemented: "
+                                   + std::string(get_enumerant_name(instruction.get_operation())));
+        auto result_type = get_type(instruction.result_type, instruction_start_index);
+        state.value =
+            Value(builder.build_smod(get_id_state(instruction.operand_1).value.value().value,
+                                     get_id_state(instruction.operand_2).value.value().value,
+                                     get_name(instruction.result).c_str()),
+                  result_type);
+        break;
+    }
+    }
 }
 
 void Spirv_to_llvm::handle_instruction_op_f_rem(Op_f_rem instruction,
index eda3fe2a21038a1d21a71a19852d083b27b1252a..475d521f225c60a6bddb4c62c60fe83b85d01958 100644 (file)
@@ -40,6 +40,7 @@ namespace spirv_to_llvm
 class Simple_type_descriptor;
 class Vector_type_descriptor;
 class Matrix_type_descriptor;
+class Array_type_descriptor;
 class Pointer_type_descriptor;
 class Function_type_descriptor;
 class Struct_type_descriptor;
@@ -55,6 +56,7 @@ public:
         virtual void visit(Simple_type_descriptor &type) = 0;
         virtual void visit(Vector_type_descriptor &type) = 0;
         virtual void visit(Matrix_type_descriptor &type) = 0;
+        virtual void visit(Array_type_descriptor &type) = 0;
         virtual void visit(Pointer_type_descriptor &type) = 0;
         virtual void visit(Function_type_descriptor &type) = 0;
         virtual void visit(Struct_type_descriptor &type) = 0;
@@ -94,6 +96,10 @@ public:
             {
                 std::forward<Fn>(fn)(type);
             }
+            virtual void visit(Array_type_descriptor &type) override
+            {
+                std::forward<Fn>(fn)(type);
+            }
             virtual void visit(Pointer_type_descriptor &type) override
             {
                 std::forward<Fn>(fn)(type);
@@ -247,6 +253,50 @@ public:
     }
 };
 
+class Array_type_descriptor final : public Type_descriptor
+{
+private:
+    ::LLVMTypeRef type;
+    std::shared_ptr<Type_descriptor> element_type;
+    std::size_t element_count;
+    std::size_t instruction_start_index;
+    Recursion_checker_state recursion_checker_state;
+
+public:
+    explicit Array_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
+                                   std::shared_ptr<Type_descriptor> element_type,
+                                   std::size_t element_count,
+                                   std::size_t instruction_start_index) noexcept
+        : Type_descriptor(std::move(decorations)),
+          type(::LLVMVectorType(element_type->get_or_make_type(), element_count)),
+          element_type(std::move(element_type)),
+          element_count(element_count),
+          instruction_start_index(instruction_start_index)
+    {
+    }
+    virtual ::LLVMTypeRef get_or_make_type() override
+    {
+        if(!type)
+        {
+            Recursion_checker recursion_checker(recursion_checker_state, instruction_start_index);
+            type = ::LLVMArrayType(element_type->get_or_make_type(), element_count);
+        }
+        return type;
+    }
+    virtual void visit(Type_visitor &type_visitor) override
+    {
+        type_visitor.visit(*this);
+    }
+    const std::shared_ptr<Type_descriptor> &get_element_type() const noexcept
+    {
+        return element_type;
+    }
+    std::size_t get_element_count() const noexcept
+    {
+        return element_count;
+    }
+};
+
 class Pointer_type_descriptor final : public Type_descriptor
 {
 private:
diff --git a/test-files/tri.frag b/test-files/tri.frag
new file mode 100644 (file)
index 0000000..efe2ee8
--- /dev/null
@@ -0,0 +1,8 @@
+#version 450
+
+layout(location = 0) out vec4 color;
+
+void main()
+{
+    color = vec4(1, 0, 1, 1);
+}
diff --git a/test-files/tri.frag.spv b/test-files/tri.frag.spv
new file mode 100644 (file)
index 0000000..e5e5fe0
Binary files /dev/null and b/test-files/tri.frag.spv differ
diff --git a/test-files/tri.vert b/test-files/tri.vert
new file mode 100644 (file)
index 0000000..eea2ca9
--- /dev/null
@@ -0,0 +1,6 @@
+#version 450
+
+void main()
+{
+    gl_Position = vec4(gl_VertexIndex * 0.25, gl_VertexIndex % 2 * 0.5, 0.0, 1.0);
+}
diff --git a/test-files/tri.vert.spv b/test-files/tri.vert.spv
new file mode 100644 (file)
index 0000000..f786d09
Binary files /dev/null and b/test-files/tri.vert.spv differ