1/*===-- calc.c - tool for testing libLLVM and llvm-c API ------------------===*\
2|*                                                                            *|
3|*                     The LLVM Compiler Infrastructure                       *|
4|*                                                                            *|
5|* This file is distributed under the University of Illinois Open Source      *|
6|* License. See LICENSE.TXT for details.                                      *|
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("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
112static 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
142int llvm_calc(void) {
143
144  llvm_tokenize_stdin(handle_line);
145
146  return 0;
147}
148