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, ¶m);
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