diff --git a/ext/llvm_value.cpp b/ext/llvm_value.cpp index d914299..b5f7a0d 100644 --- a/ext/llvm_value.cpp +++ b/ext/llvm_value.cpp @@ -101,6 +101,68 @@ llvm_value_get_immediate_constant(VALUE self, VALUE v) { return llvm_value_wrap(ConstantInt::get(type, (long)v)); } +VALUE +llvm_value_is_constant(VALUE self) { + Value *v; + Data_Get_Struct(self, Value, v); + return isa(v) ? Qtrue : Qfalse; +} + +VALUE +llvm_value_is_int_constant(VALUE self) { + Value *v; + Data_Get_Struct(self, Value, v); + return isa(v) ? Qtrue : Qfalse; +} + +VALUE +llvm_value_is_float_constant(VALUE self) { + Value *v; + Data_Get_Struct(self, Value, v); + return isa(v) ? Qtrue : Qfalse; +} + +VALUE +llvm_value_get_int_constant_value(VALUE self) { + Value *v; + Data_Get_Struct(self, Value, v); + if (ConstantInt *C = dyn_cast(v)) { + APInt val = C->getValue(); + return LL2NUM(val.getLimitedValue()); + } else { + rb_raise(rb_eTypeError, "Argument not an integer constant"); + } +} + +VALUE +llvm_value_get_float_constant_value(VALUE self) { + Value *v; + Data_Get_Struct(self, Value, v); + if (ConstantFP *C = dyn_cast(v)) { + APFloat val = C->getValueAPF(); + return rb_float_new(val.convertToFloat()); + } else { + rb_raise(rb_eTypeError, "Argument not a float constant"); + } +} + + +VALUE +llvm_value_is_null(VALUE self) { + Value *v; + Data_Get_Struct(self, Value, v); + if (Constant *C = dyn_cast(v)) + return C->isNullValue() ? Qtrue : Qfalse; + return Qfalse; +} + +VALUE +llvm_value_is_undef(VALUE self) { + Value *v; + Data_Get_Struct(self, Value, v); + return isa(v) ? Qtrue : Qfalse; +} + VALUE llvm_type_pointer(VALUE self, VALUE rtype) { Type *type; diff --git a/ext/llvmruby.c b/ext/llvmruby.c index 36d00e7..8c0fb94 100644 --- a/ext/llvmruby.c +++ b/ext/llvmruby.c @@ -129,6 +129,14 @@ VALUE llvm_value_num_uses(VALUE); VALUE llvm_value_used_in_basic_block(VALUE, VALUE); VALUE llvm_value_replace_all_uses_with(VALUE, VALUE); +VALUE llvm_value_is_constant(VALUE self); +VALUE llvm_value_is_int_constant(VALUE self); +VALUE llvm_value_is_float_constant(VALUE self); +VALUE llvm_value_get_int_constant_value(VALUE self); +VALUE llvm_value_get_float_constant_value(VALUE self); +VALUE llvm_value_is_null(VALUE self); +VALUE llvm_value_is_undef(VALUE self); + VALUE llvm_user_get_operand_list(VALUE); VALUE llvm_user_get_num_operands(VALUE); VALUE llvm_user_get_operand(VALUE, VALUE); @@ -209,6 +217,14 @@ void Init_llvmruby() { rb_define_method(cLLVMValue, "used_in_basic_block?", llvm_value_used_in_basic_block, 1); rb_define_method(cLLVMValue, "replace_all_uses_with", llvm_value_replace_all_uses_with, 1); + rb_define_method(cLLVMValue, "is_constant", llvm_value_is_constant, 0); + rb_define_method(cLLVMValue, "is_int_constant", llvm_value_is_int_constant, 0); + rb_define_method(cLLVMValue, "is_float_constant", llvm_value_is_float_constant, 0); + rb_define_method(cLLVMValue, "get_int_constant_value", llvm_value_get_int_constant_value, 0); + rb_define_method(cLLVMValue, "get_float_constant_value", llvm_value_get_float_constant_value, 0); + rb_define_method(cLLVMValue, "is_null", llvm_value_is_null, 0); + rb_define_method(cLLVMValue, "is_undef", llvm_value_is_undef, 0); + rb_define_method(cLLVMUser, "get_operand_list", llvm_user_get_operand_list, 0); rb_define_method(cLLVMUser, "get_num_operands", llvm_user_get_num_operands, 0); rb_define_method(cLLVMUser, "get_operand", llvm_user_get_operand, 1); diff --git a/test/test_value.rb b/test/test_value.rb new file mode 100644 index 0000000..da99ee8 --- /dev/null +++ b/test/test_value.rb @@ -0,0 +1,63 @@ +require 'test/unit' +require 'llvm' + +include LLVM + +class ValueTests < Test::Unit::TestCase + + def setup + @assembly=<<-EOF + ; ModuleID = 'constants.o' + target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" + target triple = "i386-apple-darwin9" + @CONST_PI = constant float 0x400921FA00000000 ; [#uses=0] + + define float @circle_area(float %radius) nounwind { + entry: + %tmp2 = mul float %radius, 0x400921FA00000000 ; [#uses=1] + %tmp4 = mul float %tmp2, %radius ; [#uses=1] + ret float %tmp4 + } + + define i32 @add_42(i32 %x) nounwind { + entry: + %tmp2 = add i32 %x, 42 ; [#uses=1] + ret i32 %tmp2 + } + EOF + + @m = LLVM::Module.read_assembly(@assembly) + end + + def test_check_value_is_constant + add42 = @m.get_function("add_42") + assert(add42) + ins = add42.get_basic_block_list[0].get_instruction_list + add_ins = ins[0] + assert_equal(false,add_ins.get_operand(0).is_constant()) + assert_equal(true,add_ins.get_operand(1).is_constant()) + end + + def test_get_integer_constant_values + add42 = @m.get_function("add_42") + assert(add42) + ins = add42.get_basic_block_list[0].get_instruction_list + add_ins = ins[0] + assert(add_ins.get_operand(1).is_constant()) + assert(add_ins.get_operand(1).is_int_constant()) + assert_equal(42,add_ins.get_operand(1).get_int_constant_value()) + end + + def test_get_float_constant_values + circle_area = @m.get_function("circle_area") + assert(circle_area) + ins = circle_area.get_basic_block_list[0].get_instruction_list + add_ins = ins[0] + assert_equal(false,add_ins.get_operand(0).is_constant()) + assert_equal(true,add_ins.get_operand(1).is_constant()) + assert_equal(true,add_ins.get_operand(1).is_float_constant()) + assert_in_delta(3.14159, add_ins.get_operand(1).get_float_constant_value(), 2 ** -20) + end + +end +