plessl-llvmruby 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,259 @@
1
+ #include "llvmruby.h"
2
+ #include <sstream>
3
+
4
+ extern VALUE cLLVMInstruction;
5
+ extern VALUE cLLVMBinaryOps;
6
+
7
+ extern "C" {
8
+
9
+ #define LAST_INSTRUCTION_NUM 100
10
+ VALUE gInstructionClasses[LAST_INSTRUCTION_NUM];
11
+
12
+ #define DATA_GET_INSTRUCTION Instruction *i; Data_Get_Struct(self, Instruction, i);
13
+
14
+ VALUE
15
+ llvm_instruction_wrap(Instruction* i) {
16
+ return Data_Wrap_Struct(gInstructionClasses[i->getOpcode()], NULL, NULL, i);
17
+ }
18
+
19
+ VALUE
20
+ llvm_instruction_inspect(VALUE self) {
21
+ Instruction *i = LLVM_INSTRUCTION(self);
22
+ std::ostringstream strstrm;
23
+ strstrm << *i;
24
+ return rb_str_new2(strstrm.str().c_str());
25
+ }
26
+
27
+ VALUE
28
+ llvm_instruction_get_opcode_name(VALUE self) {
29
+ Instruction *i = LLVM_INSTRUCTION(self);
30
+ std::string name = i->getOpcodeName();
31
+ return rb_str_new2(name.c_str());
32
+ }
33
+
34
+ VALUE
35
+ llvm_instruction_may_read_from_memory(VALUE self) {
36
+ DATA_GET_INSTRUCTION
37
+ return i->mayReadFromMemory() ? Qtrue : Qfalse;
38
+ }
39
+
40
+ VALUE
41
+ llvm_instruction_may_write_to_memory(VALUE self) {
42
+ DATA_GET_INSTRUCTION
43
+ return i->mayWriteToMemory() ? Qtrue : Qfalse;
44
+ }
45
+
46
+ VALUE
47
+ llvm_instruction_is_identical_to(VALUE self, VALUE ri2) {
48
+ DATA_GET_INSTRUCTION
49
+ CHECK_TYPE(ri2, cLLVMInstruction);
50
+ Instruction *i2 = LLVM_INSTRUCTION(ri2);
51
+ return i->isIdenticalTo(i2) ? Qtrue : Qfalse;
52
+ }
53
+
54
+ VALUE
55
+ llvm_instruction_is_same_operation_as(VALUE self, VALUE ri2) {
56
+ DATA_GET_INSTRUCTION
57
+ CHECK_TYPE(ri2, cLLVMInstruction);
58
+ Instruction *i2 = LLVM_INSTRUCTION(ri2);
59
+ return i->isSameOperationAs(i2) ? Qtrue : Qfalse;
60
+ }
61
+
62
+ VALUE
63
+ llvm_instruction_is_used_outside_of_block(VALUE self, VALUE rbb) {
64
+ DATA_GET_INSTRUCTION
65
+ CHECK_TYPE(rbb, cLLVMBasicBlock);
66
+ BasicBlock *bb = LLVM_BASIC_BLOCK(rbb);
67
+ return i->isUsedOutsideOfBlock(bb) ? Qtrue: Qfalse;
68
+ }
69
+
70
+ #define DATA_GET_TERMINATOR_INST TerminatorInst *ti; Data_Get_Struct(self, TerminatorInst, ti);
71
+
72
+ VALUE
73
+ llvm_terminator_inst_num_successors(VALUE self) {
74
+ DATA_GET_TERMINATOR_INST
75
+ return INT2FIX(ti->getNumSuccessors());
76
+ }
77
+
78
+ VALUE
79
+ llvm_terminator_inst_get_successor(VALUE self, VALUE ridx) {
80
+ DATA_GET_TERMINATOR_INST
81
+ BasicBlock *bb = ti->getSuccessor(FIX2INT(ridx));
82
+ return llvm_basic_block_wrap(bb);
83
+ }
84
+
85
+ VALUE
86
+ llvm_terminator_inst_set_successor(VALUE self, VALUE ridx, VALUE rbb) {
87
+ DATA_GET_TERMINATOR_INST
88
+
89
+ BasicBlock *bb;
90
+ Data_Get_Struct(rbb, BasicBlock, bb);
91
+
92
+ ti->setSuccessor(FIX2INT(ridx), bb);
93
+ return rbb;
94
+ }
95
+
96
+ #define DATA_GET_BRANCH_INST BranchInst *bi; Data_Get_Struct(self, BranchInst, bi);
97
+
98
+ VALUE
99
+ llvm_branch_inst_is_unconditional(VALUE self) {
100
+ DATA_GET_BRANCH_INST
101
+ return bi->isUnconditional() ? Qtrue : Qfalse;
102
+ }
103
+
104
+ VALUE
105
+ llvm_branch_inst_is_conditional(VALUE self) {
106
+ DATA_GET_BRANCH_INST
107
+ return bi->isConditional() ? Qtrue : Qfalse;
108
+ }
109
+
110
+ VALUE
111
+ llvm_branch_inst_get_condition(VALUE self) {
112
+ DATA_GET_BRANCH_INST
113
+ return llvm_value_wrap(bi->getCondition());
114
+ }
115
+
116
+ VALUE
117
+ llvm_branch_inst_set_condition(VALUE self, VALUE rv) {
118
+ DATA_GET_BRANCH_INST
119
+
120
+ Value *v;
121
+ Data_Get_Struct(rv, Value, v);
122
+
123
+ bi->setCondition(v);
124
+ return rv;
125
+ }
126
+
127
+ #define DATA_GET_SWITCH_INST SwitchInst *si; Data_Get_Struct(self, SwitchInst, si);
128
+
129
+ VALUE
130
+ llvm_switch_inst_get_default_dest(VALUE self) {
131
+ DATA_GET_SWITCH_INST
132
+ BasicBlock *bb = si->getDefaultDest();
133
+ return llvm_basic_block_wrap(bb);
134
+ }
135
+
136
+ VALUE
137
+ llvm_switch_inst_get_num_cases(VALUE self) {
138
+ DATA_GET_SWITCH_INST
139
+ return INT2FIX(si->getNumCases());
140
+ }
141
+
142
+ VALUE
143
+ llvm_switch_inst_add_case(VALUE self, VALUE rci, VALUE rbb) {
144
+ DATA_GET_SWITCH_INST
145
+
146
+ ConstantInt *ci;
147
+ Data_Get_Struct(rci, ConstantInt, ci);
148
+
149
+ BasicBlock *bb;
150
+ Data_Get_Struct(rbb, BasicBlock, bb);
151
+
152
+ si->addCase(ci, bb);
153
+ return self;
154
+ }
155
+
156
+ #define DATA_GET_ALLOCATION_INST AllocationInst *ai; Data_Get_Struct(self, AllocationInst, ai);
157
+
158
+ VALUE
159
+ llvm_allocation_inst_is_array_allocation(VALUE self) {
160
+ DATA_GET_ALLOCATION_INST
161
+ return ai->isArrayAllocation() ? true : false;
162
+ }
163
+
164
+ VALUE
165
+ llvm_allocation_inst_array_size(VALUE self) {
166
+ DATA_GET_ALLOCATION_INST
167
+ return llvm_value_wrap(ai->getArraySize());
168
+ }
169
+
170
+ VALUE
171
+ llvm_allocation_inst_allocated_type(VALUE self) {
172
+ DATA_GET_ALLOCATION_INST
173
+ Type *at = const_cast<Type*>(ai->getAllocatedType());
174
+ return Data_Wrap_Struct(cLLVMType, NULL, NULL, at);
175
+ }
176
+
177
+ VALUE
178
+ llvm_allocation_inst_alignment(VALUE self) {
179
+ DATA_GET_ALLOCATION_INST
180
+ return INT2FIX(ai->getAlignment());
181
+ }
182
+
183
+ #define DEFINE_INST(type, name) rb_define_const(cLLVMInstruction, #name, INT2FIX(Instruction::name));
184
+ #define DEFINE_BINARY_INST(name) DEFINE_INST(cLLVMBinaryOps, name)
185
+ #define DEFINE_PRED(name) rb_define_const(cLLVMInstruction, #name, INT2FIX(ICmpInst::name));
186
+ #define DEFINE_FPRED(name) rb_define_const(cLLVMInstruction, #name, INT2FIX(FCmpInst::name));
187
+ #define DEFINE_CAST(name) rb_define_const(cLLVMInstruction, #name, INT2FIX(Instruction::name));
188
+
189
+ void init_instructions() {
190
+ for(int i = 0; i < LAST_INSTRUCTION_NUM; ++i) {
191
+ gInstructionClasses[i] = cLLVMInstruction;
192
+ }
193
+
194
+ // Need to be able to quickly look up at runtime Ruby classes cooresponding to LLVM classes
195
+ #define HANDLE_TERM_INST(Num, Opcode, Klass) gInstructionClasses[Num] = cLLVM##Klass;
196
+ #define HANDLE_BINARY_INST(Num, Opcode, Klass) gInstructionClasses[Num] = cLLVM##Klass;
197
+ #define HANDLE_MEMORY_INST(Num, Opcode, Klass) gInstructionClasses[Num] = cLLVM##Klass;
198
+ #include "llvm/Instruction.def"
199
+
200
+ // Standard binary operators
201
+ DEFINE_BINARY_INST(Add)
202
+ DEFINE_BINARY_INST(Sub)
203
+ DEFINE_BINARY_INST(Mul)
204
+ DEFINE_BINARY_INST(UDiv)
205
+ DEFINE_BINARY_INST(SDiv)
206
+ DEFINE_BINARY_INST(FDiv)
207
+ DEFINE_BINARY_INST(URem)
208
+ DEFINE_BINARY_INST(SRem)
209
+ DEFINE_BINARY_INST(FRem)
210
+
211
+ // Logical operators (integer operands)
212
+ DEFINE_BINARY_INST(Shl) // Shift left (logical)
213
+ DEFINE_BINARY_INST(LShr) // Shift right (logical)
214
+ DEFINE_BINARY_INST(AShr) // shift right (arithmetic)
215
+ DEFINE_BINARY_INST(And)
216
+ DEFINE_BINARY_INST(Or)
217
+ DEFINE_BINARY_INST(Xor)
218
+
219
+ // Integer predicates
220
+ DEFINE_PRED(ICMP_EQ) // equal
221
+ DEFINE_PRED(ICMP_NE) // not equal
222
+ DEFINE_PRED(ICMP_UGT) // unsigned greater than
223
+ DEFINE_PRED(ICMP_UGE) // unsigned greater or equal
224
+ DEFINE_PRED(ICMP_ULT) // unsigned less than
225
+ DEFINE_PRED(ICMP_ULE) // unsigned less or equal
226
+ DEFINE_PRED(ICMP_SGT) // signed greater than
227
+ DEFINE_PRED(ICMP_SGE) // signed greater or equal
228
+ DEFINE_PRED(ICMP_SLT) // signed less than
229
+ DEFINE_PRED(ICMP_SLE) // signed less or equal
230
+
231
+ DEFINE_FPRED(FCMP_OEQ)
232
+ DEFINE_FPRED(FCMP_OGT)
233
+ DEFINE_FPRED(FCMP_OGE)
234
+ DEFINE_FPRED(FCMP_OLT)
235
+ DEFINE_FPRED(FCMP_OLE)
236
+ DEFINE_FPRED(FCMP_ONE)
237
+ DEFINE_FPRED(FCMP_ORD)
238
+ DEFINE_FPRED(FCMP_UNO)
239
+ DEFINE_FPRED(FCMP_UEQ)
240
+ DEFINE_FPRED(FCMP_UGT)
241
+ DEFINE_FPRED(FCMP_UGE)
242
+ DEFINE_FPRED(FCMP_ULT)
243
+ DEFINE_FPRED(FCMP_ULE)
244
+ DEFINE_FPRED(FCMP_UNE)
245
+
246
+ DEFINE_CAST(Trunc)
247
+ DEFINE_CAST(ZExt)
248
+ DEFINE_CAST(SExt)
249
+ DEFINE_CAST(FPToUI)
250
+ DEFINE_CAST(FPToSI)
251
+ DEFINE_CAST(UIToFP)
252
+ DEFINE_CAST(SIToFP)
253
+ DEFINE_CAST(FPTrunc)
254
+ DEFINE_CAST(FPExt)
255
+ DEFINE_CAST(PtrToInt)
256
+ DEFINE_CAST(IntToPtr)
257
+ DEFINE_CAST(BitCast)
258
+ }
259
+ }
@@ -0,0 +1,189 @@
1
+ #include "llvmruby.h"
2
+ #include "llvm/Assembly/Parser.h"
3
+ #include "llvm/Bitcode/ReaderWriter.h"
4
+ #include "llvm/Analysis/Verifier.h"
5
+ #include "llvm/Support/MemoryBuffer.h"
6
+ #include <fstream>
7
+ #include <sstream>
8
+
9
+ extern "C" {
10
+
11
+ VALUE
12
+ llvm_module_allocate(VALUE klass) {
13
+ return Data_Wrap_Struct(klass, NULL, NULL, NULL);
14
+ }
15
+
16
+ VALUE
17
+ llvm_module_initialize(VALUE self, VALUE rname) {
18
+ Check_Type(rname, T_STRING);
19
+ DATA_PTR(self) = new Module(StringValuePtr(rname));
20
+ return self;
21
+ }
22
+
23
+ VALUE
24
+ llvm_module_get_or_insert_function(VALUE self, VALUE name, VALUE rtype) {
25
+ Check_Type(name, T_STRING);
26
+ CHECK_TYPE(rtype, cLLVMFunctionType);
27
+
28
+ Module *m = LLVM_MODULE(self);
29
+ FunctionType *type = LLVM_FUNC_TYPE(rtype);
30
+ Function *f = cast<Function>(m->getOrInsertFunction(StringValuePtr(name), type));
31
+ return llvm_function_wrap(f);
32
+ }
33
+
34
+ VALUE
35
+ llvm_module_get_function(VALUE self, VALUE name) {
36
+ Check_Type(name, T_STRING);
37
+ Module *m = LLVM_MODULE(self);
38
+ Function *f = m->getFunction(StringValuePtr(name));
39
+ return llvm_function_wrap(f);
40
+ }
41
+
42
+ VALUE
43
+ llvm_module_global_variable(VALUE self, VALUE rtype, VALUE rinitializer) {
44
+ Module *m = LLVM_MODULE(self);
45
+ Type *type = LLVM_TYPE(rtype);
46
+ Constant *initializer = (Constant*)DATA_PTR(rinitializer);
47
+ GlobalVariable *gv = new GlobalVariable(type, true, GlobalValue::InternalLinkage, initializer, "", m);
48
+ return llvm_value_wrap(gv);
49
+ }
50
+
51
+
52
+ VALUE
53
+ llvm_module_inspect(VALUE self) {
54
+ Module *m = LLVM_MODULE(self);
55
+ std::ostringstream strstrm;
56
+ strstrm << *m;
57
+ return rb_str_new2(strstrm.str().c_str());
58
+ }
59
+
60
+ VALUE
61
+ llvm_pass_manager_allocate(VALUE klass) {
62
+ return Data_Wrap_Struct(klass, NULL, NULL, NULL);
63
+ }
64
+
65
+ VALUE
66
+ llvm_pass_manager_initialize(VALUE self) {
67
+ PassManager *pm = new PassManager;
68
+ DATA_PTR(self) = pm;
69
+ return self;
70
+ }
71
+
72
+ VALUE
73
+ llvm_pass_manager_run(VALUE self, VALUE module) {
74
+ PassManager *pm = (PassManager*) DATA_PTR(self);
75
+ Module *m = LLVM_MODULE(module);
76
+
77
+ pm->add(new TargetData(m));
78
+ pm->add(createVerifierPass());
79
+ pm->add(createLowerSetJmpPass());
80
+ pm->add(createRaiseAllocationsPass());
81
+ pm->add(createCFGSimplificationPass());
82
+ pm->add(createPromoteMemoryToRegisterPass());
83
+ pm->add(createGlobalOptimizerPass());
84
+ pm->add(createGlobalDCEPass());
85
+ pm->add(createFunctionInliningPass());
86
+
87
+ pm->run(*m);
88
+ return Qtrue;
89
+ }
90
+
91
+ static ExecutionEngine *EE = NULL;
92
+
93
+ VALUE
94
+ llvm_execution_engine_get(VALUE klass, VALUE module) {
95
+ CHECK_TYPE(module, cLLVMModule);
96
+
97
+ Module *m = LLVM_MODULE(module);
98
+ ExistingModuleProvider *MP = new ExistingModuleProvider(m);
99
+
100
+ if(EE == NULL) {
101
+ EE = ExecutionEngine::create(MP, false);
102
+ } else {
103
+ EE->addModuleProvider(MP);
104
+ }
105
+
106
+ return Qtrue;
107
+ }
108
+
109
+ VALUE
110
+ llvm_module_external_function(VALUE self, VALUE name, VALUE type) {
111
+ Check_Type(name, T_STRING);
112
+ CHECK_TYPE(type, cLLVMFunctionType);
113
+
114
+ Module *module = LLVM_MODULE(self);
115
+ Function *f = Function::Create(
116
+ LLVM_FUNC_TYPE(type),
117
+ Function::ExternalLinkage,
118
+ StringValuePtr(name),
119
+ module
120
+ );
121
+ return Data_Wrap_Struct(cLLVMFunction, NULL, NULL, f);
122
+ }
123
+
124
+ VALUE
125
+ llvm_module_read_assembly(VALUE self, VALUE assembly) {
126
+ Check_Type(assembly, T_STRING);
127
+
128
+ ParseError e;
129
+ Module *module = ParseAssemblyString(
130
+ StringValuePtr(assembly),
131
+ LLVM_MODULE(self),
132
+ &e
133
+ );
134
+ //TODO How do we handle errors?
135
+ return Data_Wrap_Struct(cLLVMModule, NULL, NULL, module);
136
+ }
137
+
138
+ VALUE
139
+ llvm_module_read_bitcode(VALUE self, VALUE bitcode) {
140
+ Check_Type(bitcode, T_STRING);
141
+
142
+ MemoryBuffer *buf = MemoryBuffer::getMemBufferCopy(RSTRING(bitcode)->ptr,RSTRING(bitcode)->ptr+RSTRING(bitcode)->len);
143
+ Module *module = ParseBitcodeFile(buf);
144
+ delete buf;
145
+ return Data_Wrap_Struct(cLLVMModule, NULL, NULL, module);
146
+ }
147
+
148
+
149
+ VALUE
150
+ llvm_module_write_bitcode(VALUE self, VALUE file_name) {
151
+ Check_Type(file_name, T_STRING);
152
+
153
+ // Don't really know how to handle c++ streams well,
154
+ // dumping all into string buffer and then saving
155
+ std::ofstream file;
156
+ file.open(StringValuePtr(file_name));
157
+ WriteBitcodeToFile(LLVM_MODULE(self), file); // Convert value into a string.
158
+ return Qtrue;
159
+ }
160
+
161
+ VALUE
162
+ llvm_execution_engine_run_function(int argc, VALUE *argv, VALUE klass) {
163
+ if(argc < 1) { rb_raise(rb_eArgError, "Expected at least one argument"); }
164
+ CHECK_TYPE(argv[0], cLLVMFunction);
165
+ Function *func = LLVM_FUNCTION(argv[0]);
166
+
167
+ // Using run function is much slower than getting C function pointer
168
+ // and calling that, but it lets us pass in arbitrary numbers of
169
+ // arguments easily for now, which is nice
170
+ std::vector<GenericValue> arg_values;
171
+ for(int i = 1; i < argc; ++i) {
172
+ GenericValue arg_val;
173
+ arg_val.IntVal = APInt(sizeof(long)*8, argv[i]);
174
+ arg_values.push_back(arg_val);
175
+ }
176
+
177
+ GenericValue v = EE->runFunction(func, arg_values);
178
+ VALUE val = v.IntVal.getZExtValue();
179
+ return val;
180
+ }
181
+
182
+ /* For tests: assume no args, return uncoverted int and turn it into fixnum */
183
+ VALUE llvm_execution_engine_run_autoconvert(VALUE klass, VALUE func) {
184
+ std::vector<GenericValue> args;
185
+ GenericValue v = EE->runFunction(LLVM_FUNCTION(func), args);
186
+ VALUE val = INT2NUM(v.IntVal.getZExtValue());
187
+ return val;
188
+ }
189
+ }
@@ -0,0 +1,9 @@
1
+ #include "llvmruby.h"
2
+
3
+ extern "C" {
4
+ VALUE
5
+ llvm_use_wrap(Use *u) {
6
+ return Data_Wrap_Struct(cLLVMUse, NULL, NULL, u);
7
+ }
8
+
9
+ }