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
22typedef LLVMValueRef (*binop_func_t)(LLVMBuilderRef, LLVMValueRef LHS,
23 LLVMValueRef RHS, const char *Name);
24
25static 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
41static 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 LLVMContextRef C = LLVMGetBuilderContext(Builder: builder);
49
50 for (i = 0; i < ntokens; i++) {
51 char tok = tokens[i][0];
52 switch (tok) {
53 case '+':
54 case '-':
55 case '*':
56 case '/':
57 case '&':
58 case '|':
59 case '^':
60 if (depth < 2) {
61 printf(format: "stack underflow\n");
62 return NULL;
63 }
64
65 stack[depth - 2] = LLVMBuildBinOp(B: builder, Op: op_to_opcode(op: tok),
66 LHS: stack[depth - 1], RHS: stack[depth - 2], Name: "");
67 depth--;
68
69 break;
70
71 case '@': {
72 LLVMValueRef off;
73
74 if (depth < 1) {
75 printf(format: "stack underflow\n");
76 return NULL;
77 }
78
79 LLVMTypeRef ty = LLVMInt64TypeInContext(C);
80 off = LLVMBuildGEP2(B: builder, Ty: ty, Pointer: param, Indices: &stack[depth - 1], NumIndices: 1, Name: "");
81 stack[depth - 1] = LLVMBuildLoad2(builder, Ty: ty, PointerVal: off, Name: "");
82
83 break;
84 }
85
86 default: {
87 char *end;
88 long val = strtol(nptr: tokens[i], endptr: &end, base: 0);
89 if (end[0] != '\0') {
90 printf(format: "error parsing number\n");
91 return NULL;
92 }
93
94 if (depth >= MAX_DEPTH) {
95 printf(format: "stack overflow\n");
96 return NULL;
97 }
98
99 stack[depth++] = LLVMConstInt(IntTy: LLVMInt64TypeInContext(C), N: val, SignExtend: 1);
100 break;
101 }
102 }
103 }
104
105 if (depth < 1) {
106 printf(format: "stack underflow at return\n");
107 return NULL;
108 }
109
110 LLVMBuildRet(builder, V: stack[depth - 1]);
111
112 return stack[depth - 1];
113}
114
115static void handle_line(char **tokens, int ntokens) {
116 char *name = tokens[0];
117 LLVMValueRef param;
118 LLVMValueRef res;
119
120 LLVMContextRef C = LLVMContextCreate();
121 LLVMModuleRef M = LLVMModuleCreateWithNameInContext(ModuleID: name, C);
122
123 LLVMTypeRef I64ty = LLVMInt64TypeInContext(C);
124 LLVMTypeRef I64Ptrty = LLVMPointerType(ElementType: I64ty, AddressSpace: 0);
125 LLVMTypeRef Fty = LLVMFunctionType(ReturnType: I64ty, ParamTypes: &I64Ptrty, ParamCount: 1, IsVarArg: 0);
126
127 LLVMValueRef F = LLVMAddFunction(M, Name: name, FunctionTy: Fty);
128 LLVMBuilderRef builder = LLVMCreateBuilderInContext(C);
129 LLVMPositionBuilderAtEnd(Builder: builder,
130 Block: LLVMAppendBasicBlockInContext(C, Fn: F, Name: "entry"));
131
132 LLVMGetParams(Fn: F, Params: &param);
133 LLVMSetValueName(Val: param, Name: "in");
134
135 res = build_from_tokens(tokens: tokens + 1, ntokens: ntokens - 1, builder, param);
136 if (res) {
137 char *irstr = LLVMPrintModuleToString(M);
138 puts(s: irstr);
139 LLVMDisposeMessage(Message: irstr);
140 }
141
142 LLVMDisposeBuilder(Builder: builder);
143
144 LLVMDisposeModule(M);
145 LLVMContextDispose(C);
146}
147
148int llvm_calc(void) {
149
150 llvm_tokenize_stdin(cb: handle_line);
151
152 return 0;
153}
154