# encoding: utf-8 # frozen_string_literal: true module Carbon module Tacky class Instruction < Value # Generation logic for instructions. module Generation private # Generates a "normal" instruction. It maps the parameters, then sends # the instruction over to a builder for LLVM, before returning the # result of the instruction. # # @param context [Tacky::Context] The context. # @param block [::LLVM::BasicBlock] The block. # @return [::LLVM::Value] The result of the llvm instruction. def generate_normal(context, block) params = mapped_parameters(context) value = nil block.build { |b| value = b.public_send(@instruction, *params) } value end def generate_null(context, _block) params = mapped_parameters(context) context.find(params.first).null end def generate_sizeof(context, _block) params = mapped_parameters(context) context.find(params.first).size end def generate_typeof(context, block) context.find(typeof_value(@parameters.first, context)) end # [Concrete::Type, String | Symbol, *Value] def generate_mcall(context, block) mod, name = @parameters[0..1] types = @parameters[2..-1].map { |p| typeof_value(p, context) } fname = mod.call(name, types) item, func = context.functions.fetch(fname) params = @parameters[2..-1].map { |p| mapped_parameter(p, context) } result = nil block.build { |b| result = b.call(func, *params) } context.type(result, item.return) end # [Value, String | Symbol, *Value] def generate_ucall(context, block) mod = typeof_value(@parameters[0], context, block) name = @parameters[1] types = @parameters[2..-1].map { |p| typeof_value(p, context) } fname = mod.call(name, [mod, *types]) item, func = context.functions.fetch(fname) params = [@parameters[0], *@parameters[2..-1]] .map { |p| mapped_parameter(p, context) } result = nil block.build { |b| result = b.call(func, params) } concrete.type(result, item.return) end def mapped_parameters(context) @parameters.map { |p| mapped_parameter(p, context) } end # rubocop:disable Metrics/CyclomaticComplexity def mapped_parameter(param, context) case param when Concrete::Type then context.find(param) when Tacky::Reference then context.instructions.fetch(param.id) when Tacky::Parameter then context.params.fetch(param.value) when Tacky::Typed then mapped_parameter(param.value, context) when ::Integer then LLVM.Int(param) when ::Float then LLVM.Float(param) when ::String then param else fail ArgumentError, "Unexpected parameter #{param.class}" end end # rubocop:enable Metrics/CyclomaticComplexity end end end end