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