149 lines · c
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 3240 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 LLVMTypeRef ty = LLVMInt64Type();78 off = LLVMBuildGEP2(builder, ty, param, &stack[depth - 1], 1, "");79 stack[depth - 1] = LLVMBuildLoad2(builder, ty, off, "");80 81 break;82 }83 84 default: {85 char *end;86 long val = strtol(tokens[i], &end, 0);87 if (end[0] != '\0') {88 printf("error parsing number\n");89 return NULL;90 }91 92 if (depth >= MAX_DEPTH) {93 printf("stack overflow\n");94 return NULL;95 }96 97 stack[depth++] = LLVMConstInt(LLVMInt64Type(), val, 1);98 break;99 }100 }101 }102 103 if (depth < 1) {104 printf("stack underflow at return\n");105 return NULL;106 }107 108 LLVMBuildRet(builder, 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(name);119 120 LLVMTypeRef I64ty = LLVMInt64Type();121 LLVMTypeRef I64Ptrty = LLVMPointerType(I64ty, 0);122 LLVMTypeRef Fty = LLVMFunctionType(I64ty, &I64Ptrty, 1, 0);123 124 LLVMValueRef F = LLVMAddFunction(M, name, Fty);125 LLVMBuilderRef builder = LLVMCreateBuilder();126 LLVMPositionBuilderAtEnd(builder, LLVMAppendBasicBlock(F, "entry"));127 128 LLVMGetParams(F, ¶m);129 LLVMSetValueName(param, "in");130 131 res = build_from_tokens(tokens + 1, ntokens - 1, builder, param);132 if (res) {133 char *irstr = LLVMPrintModuleToString(M);134 puts(irstr);135 LLVMDisposeMessage(irstr);136 }137 138 LLVMDisposeBuilder(builder);139 140 LLVMDisposeModule(M);141}142 143int llvm_calc(void) {144 145 llvm_tokenize_stdin(handle_line);146 147 return 0;148}149