xref: /llvm-project/llvm/tools/llvm-c-test/calc.c (revision 573a9bc4ad7fed92db5105ea75e0f9573712f973)
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       LLVMTypeRef ty = LLVMInt64Type();
78       off = LLVMBuildGEP2(builder, ty, param, &stack[depth - 1], 1, "");
79       stack[depth - 1] = LLVMBuildLoad2(builder, ty, off, "");
80 
81       break;
82     }
83 
84     default: {
85       char *end;
86       long val = strtol(tokens[i], &end, 0);
87       if (end[0] != '\0') {
88         printf("error parsing number\n");
89         return NULL;
90       }
91 
92       if (depth >= MAX_DEPTH) {
93         printf("stack overflow\n");
94         return NULL;
95       }
96 
97       stack[depth++] = LLVMConstInt(LLVMInt64Type(), val, 1);
98       break;
99     }
100     }
101   }
102 
103   if (depth < 1) {
104     printf("stack underflow at return\n");
105     return NULL;
106   }
107 
108   LLVMBuildRet(builder, stack[depth - 1]);
109 
110   return stack[depth - 1];
111 }
112 
handle_line(char ** tokens,int ntokens)113 static void handle_line(char **tokens, int ntokens) {
114   char *name = tokens[0];
115   LLVMValueRef param;
116   LLVMValueRef res;
117 
118   LLVMModuleRef M = LLVMModuleCreateWithName(name);
119 
120   LLVMTypeRef I64ty = LLVMInt64Type();
121   LLVMTypeRef I64Ptrty = LLVMPointerType(I64ty, 0);
122   LLVMTypeRef Fty = LLVMFunctionType(I64ty, &I64Ptrty, 1, 0);
123 
124   LLVMValueRef F = LLVMAddFunction(M, name, Fty);
125   LLVMBuilderRef builder = LLVMCreateBuilder();
126   LLVMPositionBuilderAtEnd(builder, LLVMAppendBasicBlock(F, "entry"));
127 
128   LLVMGetParams(F, &param);
129   LLVMSetValueName(param, "in");
130 
131   res = build_from_tokens(tokens + 1, ntokens - 1, builder, param);
132   if (res) {
133     char *irstr = LLVMPrintModuleToString(M);
134     puts(irstr);
135     LLVMDisposeMessage(irstr);
136   }
137 
138   LLVMDisposeBuilder(builder);
139 
140   LLVMDisposeModule(M);
141 }
142 
llvm_calc(void)143 int llvm_calc(void) {
144 
145   llvm_tokenize_stdin(handle_line);
146 
147   return 0;
148 }
149