xref: /openbsd-src/gnu/llvm/llvm/tools/llvm-c-test/calc.c (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
109467b48Spatrick /*===-- calc.c - tool for testing libLLVM and llvm-c API ------------------===*\
209467b48Spatrick |*                                                                            *|
309467b48Spatrick |* Part of the LLVM Project, under the Apache License v2.0 with LLVM          *|
409467b48Spatrick |* Exceptions.                                                                *|
509467b48Spatrick |* See https://llvm.org/LICENSE.txt for license information.                  *|
609467b48Spatrick |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception                    *|
709467b48Spatrick |*                                                                            *|
809467b48Spatrick |*===----------------------------------------------------------------------===*|
909467b48Spatrick |*                                                                            *|
1009467b48Spatrick |* This file implements the --calc command in llvm-c-test. --calc reads lines *|
1109467b48Spatrick |* from stdin, parses them as a name and an expression in reverse polish      *|
1209467b48Spatrick |* notation and prints a module with a function with the expression.          *|
1309467b48Spatrick |*                                                                            *|
1409467b48Spatrick \*===----------------------------------------------------------------------===*/
1509467b48Spatrick 
1609467b48Spatrick #include "llvm-c-test.h"
1709467b48Spatrick #include <stdio.h>
1809467b48Spatrick #include <stdlib.h>
1909467b48Spatrick #include <string.h>
2009467b48Spatrick #include <assert.h>
2109467b48Spatrick 
2209467b48Spatrick typedef LLVMValueRef (*binop_func_t)(LLVMBuilderRef, LLVMValueRef LHS,
2309467b48Spatrick                                      LLVMValueRef RHS, const char *Name);
2409467b48Spatrick 
op_to_opcode(char op)2509467b48Spatrick static LLVMOpcode op_to_opcode(char op) {
2609467b48Spatrick   switch (op) {
2709467b48Spatrick   case '+': return LLVMAdd;
2809467b48Spatrick   case '-': return LLVMSub;
2909467b48Spatrick   case '*': return LLVMMul;
3009467b48Spatrick   case '/': return LLVMSDiv;
3109467b48Spatrick   case '&': return LLVMAnd;
3209467b48Spatrick   case '|': return LLVMOr;
3309467b48Spatrick   case '^': return LLVMXor;
3409467b48Spatrick   }
3509467b48Spatrick   assert(0 && "unknown operation");
3609467b48Spatrick   return 0;
3709467b48Spatrick }
3809467b48Spatrick 
3909467b48Spatrick #define MAX_DEPTH 32
4009467b48Spatrick 
build_from_tokens(char ** tokens,int ntokens,LLVMBuilderRef builder,LLVMValueRef param)4109467b48Spatrick static LLVMValueRef build_from_tokens(char **tokens, int ntokens,
4209467b48Spatrick                                       LLVMBuilderRef builder,
4309467b48Spatrick                                       LLVMValueRef param) {
4409467b48Spatrick   LLVMValueRef stack[MAX_DEPTH];
4509467b48Spatrick   int depth = 0;
4609467b48Spatrick   int i;
4709467b48Spatrick 
4809467b48Spatrick   for (i = 0; i < ntokens; i++) {
4909467b48Spatrick     char tok = tokens[i][0];
5009467b48Spatrick     switch (tok) {
5109467b48Spatrick     case '+':
5209467b48Spatrick     case '-':
5309467b48Spatrick     case '*':
5409467b48Spatrick     case '/':
5509467b48Spatrick     case '&':
5609467b48Spatrick     case '|':
5709467b48Spatrick     case '^':
5809467b48Spatrick       if (depth < 2) {
5909467b48Spatrick         printf("stack underflow\n");
6009467b48Spatrick         return NULL;
6109467b48Spatrick       }
6209467b48Spatrick 
6309467b48Spatrick       stack[depth - 2] = LLVMBuildBinOp(builder, op_to_opcode(tok),
6409467b48Spatrick                                         stack[depth - 1], stack[depth - 2], "");
6509467b48Spatrick       depth--;
6609467b48Spatrick 
6709467b48Spatrick       break;
6809467b48Spatrick 
6909467b48Spatrick     case '@': {
7009467b48Spatrick       LLVMValueRef off;
7109467b48Spatrick 
7209467b48Spatrick       if (depth < 1) {
7309467b48Spatrick         printf("stack underflow\n");
7409467b48Spatrick         return NULL;
7509467b48Spatrick       }
7609467b48Spatrick 
77*d415bd75Srobert       LLVMTypeRef ty = LLVMInt64Type();
78*d415bd75Srobert       off = LLVMBuildGEP2(builder, ty, param, &stack[depth - 1], 1, "");
79*d415bd75Srobert       stack[depth - 1] = LLVMBuildLoad2(builder, ty, off, "");
8009467b48Spatrick 
8109467b48Spatrick       break;
8209467b48Spatrick     }
8309467b48Spatrick 
8409467b48Spatrick     default: {
8509467b48Spatrick       char *end;
8609467b48Spatrick       long val = strtol(tokens[i], &end, 0);
8709467b48Spatrick       if (end[0] != '\0') {
8809467b48Spatrick         printf("error parsing number\n");
8909467b48Spatrick         return NULL;
9009467b48Spatrick       }
9109467b48Spatrick 
9209467b48Spatrick       if (depth >= MAX_DEPTH) {
9309467b48Spatrick         printf("stack overflow\n");
9409467b48Spatrick         return NULL;
9509467b48Spatrick       }
9609467b48Spatrick 
9709467b48Spatrick       stack[depth++] = LLVMConstInt(LLVMInt64Type(), val, 1);
9809467b48Spatrick       break;
9909467b48Spatrick     }
10009467b48Spatrick     }
10109467b48Spatrick   }
10209467b48Spatrick 
10309467b48Spatrick   if (depth < 1) {
10409467b48Spatrick     printf("stack underflow at return\n");
10509467b48Spatrick     return NULL;
10609467b48Spatrick   }
10709467b48Spatrick 
10809467b48Spatrick   LLVMBuildRet(builder, stack[depth - 1]);
10909467b48Spatrick 
11009467b48Spatrick   return stack[depth - 1];
11109467b48Spatrick }
11209467b48Spatrick 
handle_line(char ** tokens,int ntokens)11309467b48Spatrick static void handle_line(char **tokens, int ntokens) {
11409467b48Spatrick   char *name = tokens[0];
11509467b48Spatrick   LLVMValueRef param;
11609467b48Spatrick   LLVMValueRef res;
11709467b48Spatrick 
11809467b48Spatrick   LLVMModuleRef M = LLVMModuleCreateWithName(name);
11909467b48Spatrick 
12009467b48Spatrick   LLVMTypeRef I64ty = LLVMInt64Type();
12109467b48Spatrick   LLVMTypeRef I64Ptrty = LLVMPointerType(I64ty, 0);
12209467b48Spatrick   LLVMTypeRef Fty = LLVMFunctionType(I64ty, &I64Ptrty, 1, 0);
12309467b48Spatrick 
12409467b48Spatrick   LLVMValueRef F = LLVMAddFunction(M, name, Fty);
12509467b48Spatrick   LLVMBuilderRef builder = LLVMCreateBuilder();
12609467b48Spatrick   LLVMPositionBuilderAtEnd(builder, LLVMAppendBasicBlock(F, "entry"));
12709467b48Spatrick 
12809467b48Spatrick   LLVMGetParams(F, &param);
12909467b48Spatrick   LLVMSetValueName(param, "in");
13009467b48Spatrick 
13109467b48Spatrick   res = build_from_tokens(tokens + 1, ntokens - 1, builder, param);
13209467b48Spatrick   if (res) {
13309467b48Spatrick     char *irstr = LLVMPrintModuleToString(M);
13409467b48Spatrick     puts(irstr);
13509467b48Spatrick     LLVMDisposeMessage(irstr);
13609467b48Spatrick   }
13709467b48Spatrick 
13809467b48Spatrick   LLVMDisposeBuilder(builder);
13909467b48Spatrick 
14009467b48Spatrick   LLVMDisposeModule(M);
14109467b48Spatrick }
14209467b48Spatrick 
llvm_calc(void)14309467b48Spatrick int llvm_calc(void) {
14409467b48Spatrick 
14509467b48Spatrick   llvm_tokenize_stdin(handle_line);
14609467b48Spatrick 
14709467b48Spatrick   return 0;
14809467b48Spatrick }
149