1 /*===-- calc.c - tool for testing libLLVM and llvm-c API ------------------===*\
2 |*                                                                            *|
3 |* Part of the LLVM Project, under the Apache License v2.0 with LLVM          *|
4 |* Exceptions.                                                                *|
5 |* See https://llvm.org/LICENSE.txt for license information.                  *|
6 |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception                    *|
7 |*                                                                            *|
8 |*===----------------------------------------------------------------------===*|
9 |*                                                                            *|
10 |* This file implements the --calc command in llvm-c-test. --calc reads lines *|
11 |* from stdin, parses them as a name and an expression in reverse polish      *|
12 |* notation and prints a module with a function with the expression.          *|
13 |*                                                                            *|
14 \*===----------------------------------------------------------------------===*/
15 
16 #include "llvm-c-test.h"
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <assert.h>
21 
22 typedef LLVMValueRef (*binop_func_t)(LLVMBuilderRef, LLVMValueRef LHS,
23                                      LLVMValueRef RHS, const char *Name);
24 
op_to_opcode(char op)25 static LLVMOpcode op_to_opcode(char op) {
26   switch (op) {
27   case '+': return LLVMAdd;
28   case '-': return LLVMSub;
29   case '*': return LLVMMul;
30   case '/': return LLVMSDiv;
31   case '&': return LLVMAnd;
32   case '|': return LLVMOr;
33   case '^': return LLVMXor;
34   }
35   assert(0 && "unknown operation");
36   return 0;
37 }
38 
39 #define MAX_DEPTH 32
40 
build_from_tokens(char ** tokens,int ntokens,LLVMBuilderRef builder,LLVMValueRef param)41 static LLVMValueRef build_from_tokens(char **tokens, int ntokens,
42                                       LLVMBuilderRef builder,
43                                       LLVMValueRef param) {
44   LLVMValueRef stack[MAX_DEPTH];
45   int depth = 0;
46   int i;
47 
48   for (i = 0; i < ntokens; i++) {
49     char tok = tokens[i][0];
50     switch (tok) {
51     case '+':
52     case '-':
53     case '*':
54     case '/':
55     case '&':
56     case '|':
57     case '^':
58       if (depth < 2) {
59         printf("stack underflow\n");
60         return NULL;
61       }
62 
63       stack[depth - 2] = LLVMBuildBinOp(builder, op_to_opcode(tok),
64                                         stack[depth - 1], stack[depth - 2], "");
65       depth--;
66 
67       break;
68 
69     case '@': {
70       LLVMValueRef off;
71 
72       if (depth < 1) {
73         printf("stack underflow\n");
74         return NULL;
75       }
76 
77       off = LLVMBuildGEP(builder, param, &stack[depth - 1], 1, "");
78       stack[depth - 1] = LLVMBuildLoad(builder, off, "");
79 
80       break;
81     }
82 
83     default: {
84       char *end;
85       long val = strtol(tokens[i], &end, 0);
86       if (end[0] != '\0') {
87         printf("error parsing number\n");
88         return NULL;
89       }
90 
91       if (depth >= MAX_DEPTH) {
92         printf("stack overflow\n");
93         return NULL;
94       }
95 
96       stack[depth++] = LLVMConstInt(LLVMInt64Type(), val, 1);
97       break;
98     }
99     }
100   }
101 
102   if (depth < 1) {
103     printf("stack underflow at return\n");
104     return NULL;
105   }
106 
107   LLVMBuildRet(builder, stack[depth - 1]);
108 
109   return stack[depth - 1];
110 }
111 
handle_line(char ** tokens,int ntokens)112 static void handle_line(char **tokens, int ntokens) {
113   char *name = tokens[0];
114   LLVMValueRef param;
115   LLVMValueRef res;
116 
117   LLVMModuleRef M = LLVMModuleCreateWithName(name);
118 
119   LLVMTypeRef I64ty = LLVMInt64Type();
120   LLVMTypeRef I64Ptrty = LLVMPointerType(I64ty, 0);
121   LLVMTypeRef Fty = LLVMFunctionType(I64ty, &I64Ptrty, 1, 0);
122 
123   LLVMValueRef F = LLVMAddFunction(M, name, Fty);
124   LLVMBuilderRef builder = LLVMCreateBuilder();
125   LLVMPositionBuilderAtEnd(builder, LLVMAppendBasicBlock(F, "entry"));
126 
127   LLVMGetParams(F, &param);
128   LLVMSetValueName(param, "in");
129 
130   res = build_from_tokens(tokens + 1, ntokens - 1, builder, param);
131   if (res) {
132     char *irstr = LLVMPrintModuleToString(M);
133     puts(irstr);
134     LLVMDisposeMessage(irstr);
135   }
136 
137   LLVMDisposeBuilder(builder);
138 
139   LLVMDisposeModule(M);
140 }
141 
llvm_calc(void)142 int llvm_calc(void) {
143 
144   llvm_tokenize_stdin(handle_line);
145 
146   return 0;
147 }
148