parent
05611e1f7d
commit
e9e0247485
@ -0,0 +1,25 @@
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
option(BUILD_IR_TESTING "Build IR testing" OFF)
|
||||
|
||||
project(CarrotCompiler VERSION 0.1
|
||||
DESCRIPTION "Simple compiler targeted RV64 for SysY Language"
|
||||
LANGUAGES CXX)
|
||||
# Common build options
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0")
|
||||
# set(BUILD_IR_TESTING true)
|
||||
|
||||
# Generic includes
|
||||
set(INCLUDE_DIRECTORIES "${PROJECT_SOURCE_DIR}/include")
|
||||
include_directories(${INCLUDE_DIRECTORIES})
|
||||
|
||||
# Compiler sources
|
||||
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(runtime)
|
||||
|
||||
# Unit tests
|
||||
include(CTest)
|
||||
if(BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif(BUILD_TESTING)
|
@ -0,0 +1,111 @@
|
||||
# arguments checking
|
||||
if(NOT COMPILER)
|
||||
message(FATAL_ERROR "Require COMPILER to be defined")
|
||||
endif(NOT COMPILER)
|
||||
|
||||
if(NOT RUNTIME)
|
||||
message(FATAL_ERROR "Require RUNTIME to be defined")
|
||||
endif(NOT RUNTIME)
|
||||
|
||||
if(NOT TEST_DIR)
|
||||
message(FATAL_ERROR "Require TEST_DIR to be defined")
|
||||
endif(NOT TEST_DIR)
|
||||
|
||||
if(NOT TEST_NAME)
|
||||
message(FATAL_ERROR "Require TEST_NAME to be defined")
|
||||
endif(NOT TEST_NAME)
|
||||
|
||||
# Sources
|
||||
set(TEST_SRC "${TEST_DIR}/${TEST_NAME}.sy")
|
||||
|
||||
if(EXISTS "${TEST_DIR}/${TEST_NAME}.in")
|
||||
set(TEST_INS "${TEST_DIR}/${TEST_NAME}.in")
|
||||
else(EXISTS "${TEST_DIR}/${TEST_NAME}.in")
|
||||
set(TEST_INS "/dev/null")
|
||||
endif(EXISTS "${TEST_DIR}/${TEST_NAME}.in")
|
||||
|
||||
set(RUNTIME_ASM "${RUNTIME}/sysy.ll")
|
||||
|
||||
# Generated
|
||||
set(TEST_ASM "${TEST_NAME}.ll")
|
||||
set(TEST_BTC "${TEST_NAME}.bc")
|
||||
set(TEST_OUT "${TEST_NAME}_ir.out")
|
||||
configure_file("${TEST_DIR}/${TEST_NAME}.out" "${TEST_NAME}.ref" NEWLINE_STYLE LF)
|
||||
set(TEST_REF "${TEST_NAME}.ref")
|
||||
|
||||
# SysY to LLVM IR
|
||||
execute_process(
|
||||
COMMAND
|
||||
${COMPILER} -c ${TEST_SRC}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
OUTPUT_FILE ${TEST_ASM}
|
||||
ERROR_VARIABLE TEST_ERR
|
||||
RESULT_VARIABLE TEST_RET
|
||||
)
|
||||
|
||||
if(TEST_RET)
|
||||
message(SEND_ERROR "Failed: SysY Compiler Error in ${TEST_SRC}: ${TEST_ERR}")
|
||||
file(READ "${TEST_SRC}" TEST_SRC_CONTENT)
|
||||
message(NOTICE "Source File:\n ${TEST_SRC_CONTENT}")
|
||||
return()
|
||||
endif(TEST_RET)
|
||||
|
||||
# LLVM IR & Runtime link to BitCode
|
||||
execute_process(
|
||||
COMMAND
|
||||
llvm-link "${RUNTIME_ASM}" "${CMAKE_CURRENT_BINARY_DIR}/${TEST_ASM}"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
OUTPUT_FILE ${TEST_BTC}
|
||||
ERROR_VARIABLE TEST_ERR
|
||||
RESULT_VARIABLE TEST_RET
|
||||
)
|
||||
|
||||
if(TEST_RET)
|
||||
message(SEND_ERROR "Failed: LLVM Link Error in ${TEST_SRC}: ${TEST_ERR}")
|
||||
file(READ "${TEST_ERR}" TEST_ERR_CONTENT)
|
||||
message(NOTICE "Generated Assmebly:\n ${TEST_ERR_CONTENT}")
|
||||
return()
|
||||
endif(TEST_RET)
|
||||
|
||||
# Run BitCode with lli
|
||||
execute_process(
|
||||
COMMAND
|
||||
lli ${TEST_BTC}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
INPUT_FILE ${TEST_INS}
|
||||
OUTPUT_VARIABLE TEST_OUT_CONTENT
|
||||
ERROR_VARIABLE TEST_ERR
|
||||
RESULT_VARIABLE TEST_RET
|
||||
TIMEOUT 10
|
||||
)
|
||||
|
||||
# Append EOF LR, if not presented
|
||||
if(TEST_OUT_CONTENT)
|
||||
string(LENGTH "${TEST_OUT_CONTENT}" TEST_OUT_LEN)
|
||||
math(EXPR TEST_OUT_LAST "${TEST_OUT_LEN} - 1")
|
||||
string(SUBSTRING "${TEST_OUT_CONTENT}" ${TEST_OUT_LAST} 1 LAST_CHAR)
|
||||
|
||||
if(NOT "${LAST_CHAR}" STREQUAL "\n")
|
||||
# If it's not, append a newline to var
|
||||
set(TEST_OUT_CONTENT "${TEST_OUT_CONTENT}\n")
|
||||
endif()
|
||||
endif(TEST_OUT_CONTENT)
|
||||
|
||||
set(TEST_OUT_CONTENT "${TEST_OUT_CONTENT}${TEST_RET}\n")
|
||||
file(WRITE "${TEST_OUT}" "${TEST_OUT_CONTENT}")
|
||||
|
||||
execute_process(
|
||||
COMMAND "${CMAKE_COMMAND}" -E compare_files "${TEST_OUT}" "${TEST_REF}"
|
||||
RESULT_VARIABLE TEST_RESULT
|
||||
)
|
||||
|
||||
if(TEST_RESULT)
|
||||
# get_filename_component(TESTNAME "${TEST_ARGS}" NAME)
|
||||
# file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out")
|
||||
# file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR})
|
||||
message(SEND_ERROR "Failed: The output of ${TEST_NAME} did not match ${TEST_REF}")
|
||||
file(READ ${TEST_REF} TEST_REF_CONTENT)
|
||||
message(NOTICE "Expected Output: ${TEST_REF_CONTENT}")
|
||||
message(NOTICE "Auctual Output: ${TEST_OUT_CONTENT}")
|
||||
return()
|
||||
endif(TEST_RESULT)
|
@ -0,0 +1,110 @@
|
||||
# arguments checking
|
||||
if(NOT COMPILER)
|
||||
message(FATAL_ERROR "Require COMPILER to be defined")
|
||||
endif(NOT COMPILER)
|
||||
|
||||
if(NOT RUNTIME)
|
||||
message(FATAL_ERROR "Require RUNTIME to be defined")
|
||||
endif(NOT RUNTIME)
|
||||
|
||||
if(NOT TEST_DIR)
|
||||
message(FATAL_ERROR "Require TEST_DIR to be defined")
|
||||
endif(NOT TEST_DIR)
|
||||
|
||||
if(NOT TEST_NAME)
|
||||
message(FATAL_ERROR "Require TEST_NAME to be defined")
|
||||
endif(NOT TEST_NAME)
|
||||
|
||||
# Sources
|
||||
set(TEST_SRC "${TEST_DIR}/${TEST_NAME}.sy")
|
||||
|
||||
if(EXISTS "${TEST_DIR}/${TEST_NAME}.in")
|
||||
set(TEST_INS "${TEST_DIR}/${TEST_NAME}.in")
|
||||
else(EXISTS "${TEST_DIR}/${TEST_NAME}.in")
|
||||
set(TEST_INS "/dev/null")
|
||||
endif(EXISTS "${TEST_DIR}/${TEST_NAME}.in")
|
||||
|
||||
set(RUNTIME_LIB "${RUNTIME}/libsysy.a")
|
||||
|
||||
# Generated
|
||||
set(TEST_ASM "${TEST_NAME}.s")
|
||||
set(TEST_EXE "${TEST_NAME}")
|
||||
set(TEST_OUT "${TEST_NAME}_rv.out")
|
||||
configure_file("${TEST_DIR}/${TEST_NAME}.out" "${TEST_NAME}.ref" NEWLINE_STYLE LF)
|
||||
set(TEST_REF "${TEST_NAME}.ref")
|
||||
|
||||
# SysY to RISC-V Assembly
|
||||
execute_process(
|
||||
COMMAND
|
||||
${COMPILER} -S ${TEST_SRC} -O1
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
OUTPUT_FILE ${TEST_ASM}
|
||||
ERROR_VARIABLE TEST_ERR
|
||||
RESULT_VARIABLE TEST_RET
|
||||
)
|
||||
|
||||
if(TEST_RET)
|
||||
message(SEND_ERROR "Failed: SysY Compiler Error in ${TEST_SRC}: ${TEST_ERR}")
|
||||
file(READ "${TEST_SRC}" TEST_SRC_CONTENT)
|
||||
message(NOTICE "Source File:\n ${TEST_SRC_CONTENT}")
|
||||
return()
|
||||
endif(TEST_RET)
|
||||
|
||||
# GCC Assemble and Link
|
||||
execute_process(
|
||||
COMMAND
|
||||
riscv64-linux-gnu-gcc "${CMAKE_CURRENT_BINARY_DIR}/${TEST_ASM}" "${RUNTIME_LIB}" -march=rv64gc -static -o "${CMAKE_CURRENT_BINARY_DIR}/${TEST_EXE}"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
ERROR_VARIABLE TEST_ERR
|
||||
RESULT_VARIABLE TEST_RET
|
||||
)
|
||||
|
||||
if(TEST_RET)
|
||||
message(SEND_ERROR "Failed: GCC Assemble and Link Error in ${TEST_SRC}: ${TEST_ERR}")
|
||||
# file(READ "${TEST_ASM}" TEST_ASM_CONTENT)
|
||||
message(NOTICE "Generated Assmebly:\n ${TEST_ASM_CONTENT}")
|
||||
return()
|
||||
endif(TEST_RET)
|
||||
|
||||
# Run the executable with qemu
|
||||
execute_process(
|
||||
COMMAND
|
||||
qemu-riscv64 ${TEST_EXE} -M sifive_u -smp 5 -m 2G
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
INPUT_FILE ${TEST_INS}
|
||||
OUTPUT_VARIABLE TEST_OUT_CONTENT
|
||||
ERROR_VARIABLE TEST_ERR
|
||||
RESULT_VARIABLE TEST_RET
|
||||
TIMEOUT 60
|
||||
)
|
||||
|
||||
# Append EOF LR, if not presented
|
||||
if(TEST_OUT_CONTENT)
|
||||
string(LENGTH "${TEST_OUT_CONTENT}" TEST_OUT_LEN)
|
||||
math(EXPR TEST_OUT_LAST "${TEST_OUT_LEN} - 1")
|
||||
string(SUBSTRING "${TEST_OUT_CONTENT}" ${TEST_OUT_LAST} 1 LAST_CHAR)
|
||||
|
||||
if(NOT "${LAST_CHAR}" STREQUAL "\n")
|
||||
# If it's not, append a newline to var
|
||||
set(TEST_OUT_CONTENT "${TEST_OUT_CONTENT}\n")
|
||||
endif()
|
||||
endif(TEST_OUT_CONTENT)
|
||||
|
||||
set(TEST_OUT_CONTENT "${TEST_OUT_CONTENT}${TEST_RET}\n")
|
||||
file(WRITE "${TEST_OUT}" "${TEST_OUT_CONTENT}")
|
||||
|
||||
execute_process(
|
||||
COMMAND "${CMAKE_COMMAND}" -E compare_files "${TEST_OUT}" "${TEST_REF}"
|
||||
RESULT_VARIABLE TEST_RESULT
|
||||
)
|
||||
|
||||
if(TEST_RESULT)
|
||||
# get_filename_component(TESTNAME "${TEST_ARGS}" NAME)
|
||||
# file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out")
|
||||
# file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR})
|
||||
message(SEND_ERROR "Failed: The output of ${TEST_NAME} did not match ${TEST_REF}")
|
||||
file(READ ${TEST_REF} TEST_REF_CONTENT)
|
||||
message(NOTICE "Expected Output: ${TEST_REF_CONTENT}")
|
||||
message(NOTICE "Auctual Output: ${TEST_OUT_CONTENT}")
|
||||
return()
|
||||
endif(TEST_RESULT)
|
@ -0,0 +1 @@
|
||||
|
@ -0,0 +1,31 @@
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
|
||||
project(SysYRuntime VERSION 1.0
|
||||
DESCRIPTION "SysY Language official runtime environment"
|
||||
LANGUAGES C)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_COMPILER "riscv64-unknown-elf-gcc")
|
||||
|
||||
set(INCLUDE_DIRECTORY "${PROJECT_SOURCE_DIR}/include")
|
||||
include_directories(${INCLUDE_DIRECTORY})
|
||||
|
||||
set(SOURCE_FILES "${PROJECT_SOURCE_DIR}/src/sylib.c")
|
||||
|
||||
if(BUILD_IR_TESTING)
|
||||
add_custom_target(sysy-ir ALL
|
||||
COMMAND clang ${CMAKE_C_FLAGS}
|
||||
-I ${INCLUDE_DIRECTORY}
|
||||
-S -emit-llvm
|
||||
${SOURCE_FILES}
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/sysy.ll
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
COMMENT "Compiling SysY Runtime Library to LLVM-IR"
|
||||
SOURCES ${SOURCE_FILES})
|
||||
endif(BUILD_IR_TESTING)
|
||||
|
||||
add_library(sysy STATIC ${SOURCE_FILES})
|
||||
|
||||
# target_compile_options(sysy PUBLIC ${CMAKE_C_FLAGS} -flto)
|
||||
# target_compile_options(sysy PUBLIC ${CMAKE_C_FLAGS} -emit-llvm -S)
|
||||
target_compile_options(sysy PRIVATE ${CMAKE_C_FLAGS} --verbose)
|
@ -0,0 +1,31 @@
|
||||
#ifndef __SYLIB_H_
|
||||
#define __SYLIB_H_
|
||||
|
||||
#include<stdio.h>
|
||||
#include<stdarg.h>
|
||||
#include<sys/time.h>
|
||||
/* Input & output functions */
|
||||
int getint(),getch(),getarray(int a[]);
|
||||
float getfloat();
|
||||
int getfarray(float a[]);
|
||||
|
||||
void putint(int a),putch(int a),putarray(int n,int a[]);
|
||||
void putfloat(float a);
|
||||
void putfarray(int n, float a[]);
|
||||
|
||||
void putf(char a[], ...);
|
||||
|
||||
/* Timing function implementation */
|
||||
struct timeval _sysy_start,_sysy_end;
|
||||
#define starttime() _sysy_starttime(__LINE__)
|
||||
#define stoptime() _sysy_stoptime(__LINE__)
|
||||
#define _SYSY_N 1024
|
||||
int _sysy_l1[_SYSY_N],_sysy_l2[_SYSY_N];
|
||||
int _sysy_h[_SYSY_N], _sysy_m[_SYSY_N],_sysy_s[_SYSY_N],_sysy_us[_SYSY_N];
|
||||
int _sysy_idx;
|
||||
__attribute((constructor)) void before_main();
|
||||
__attribute((destructor)) void after_main();
|
||||
void _sysy_starttime(int lineno);
|
||||
void _sysy_stoptime(int lineno);
|
||||
|
||||
#endif
|
@ -0,0 +1,83 @@
|
||||
#include<stdio.h>
|
||||
#include<stdarg.h>
|
||||
#include<sys/time.h>
|
||||
#include"sylib.h"
|
||||
/* Input & output functions */
|
||||
int getint(){int t; scanf("%d",&t); return t; }
|
||||
int getch(){char c; scanf("%c",&c); return (int)c; }
|
||||
float getfloat(){
|
||||
float n;
|
||||
scanf("%a", &n);
|
||||
return n;
|
||||
}
|
||||
|
||||
int getarray(int a[]){
|
||||
int n;
|
||||
scanf("%d",&n);
|
||||
for(int i=0;i<n;i++)scanf("%d",&a[i]);
|
||||
return n;
|
||||
}
|
||||
|
||||
int getfarray(float a[]) {
|
||||
int n;
|
||||
scanf("%d", &n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
scanf("%a", &a[i]);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
void putint(int a){ printf("%d",a);}
|
||||
void putch(int a){ printf("%c",a); }
|
||||
void putarray(int n,int a[]){
|
||||
printf("%d:",n);
|
||||
for(int i=0;i<n;i++)printf(" %d",a[i]);
|
||||
printf("\n");
|
||||
}
|
||||
void putfloat(float a) {
|
||||
printf("%a", a);
|
||||
}
|
||||
void putfarray(int n, float a[]) {
|
||||
printf("%d:", n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
printf(" %a", a[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void putf(char a[], ...) {
|
||||
va_list args;
|
||||
va_start(args, a);
|
||||
vfprintf(stdout, a, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Timing function implementation */
|
||||
__attribute((constructor)) void before_main(){
|
||||
for(int i=0;i<_SYSY_N;i++)
|
||||
_sysy_h[i] = _sysy_m[i]= _sysy_s[i] = _sysy_us[i] =0;
|
||||
_sysy_idx=1;
|
||||
}
|
||||
__attribute((destructor)) void after_main(){
|
||||
for(int i=1;i<_sysy_idx;i++){
|
||||
fprintf(stderr,"Timer@%04d-%04d: %dH-%dM-%dS-%dus\n",\
|
||||
_sysy_l1[i],_sysy_l2[i],_sysy_h[i],_sysy_m[i],_sysy_s[i],_sysy_us[i]);
|
||||
_sysy_us[0]+= _sysy_us[i];
|
||||
_sysy_s[0] += _sysy_s[i]; _sysy_us[0] %= 1000000;
|
||||
_sysy_m[0] += _sysy_m[i]; _sysy_s[0] %= 60;
|
||||
_sysy_h[0] += _sysy_h[i]; _sysy_m[0] %= 60;
|
||||
}
|
||||
fprintf(stderr,"TOTAL: %dH-%dM-%dS-%dus\n",_sysy_h[0],_sysy_m[0],_sysy_s[0],_sysy_us[0]);
|
||||
}
|
||||
void _sysy_starttime(int lineno){
|
||||
_sysy_l1[_sysy_idx] = lineno;
|
||||
gettimeofday(&_sysy_start,NULL);
|
||||
}
|
||||
void _sysy_stoptime(int lineno){
|
||||
gettimeofday(&_sysy_end,NULL);
|
||||
_sysy_l2[_sysy_idx] = lineno;
|
||||
_sysy_us[_sysy_idx] += 1000000 * ( _sysy_end.tv_sec - _sysy_start.tv_sec ) + _sysy_end.tv_usec - _sysy_start.tv_usec;
|
||||
_sysy_s[_sysy_idx] += _sysy_us[_sysy_idx] / 1000000 ; _sysy_us[_sysy_idx] %= 1000000;
|
||||
_sysy_m[_sysy_idx] += _sysy_s[_sysy_idx] / 60 ; _sysy_s[_sysy_idx] %= 60;
|
||||
_sysy_h[_sysy_idx] += _sysy_m[_sysy_idx] / 60 ; _sysy_m[_sysy_idx] %= 60;
|
||||
_sysy_idx ++;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
|
||||
add_subdirectory(utils)
|
||||
add_subdirectory(parser)
|
||||
add_subdirectory(ir)
|
||||
add_subdirectory(opt)
|
||||
add_subdirectory(riscv)
|
||||
|
||||
set(SOURCE_FILES main.cpp)
|
||||
|
||||
add_executable(carrotcompiler ${SOURCE_FILES})
|
||||
set_target_properties(carrotcompiler PROPERTIES OUTPUT_NAME "compiler")
|
||||
|
||||
target_include_directories(carrotcompiler PRIVATE utils parser ir opt riscv)
|
||||
|
||||
target_link_libraries(carrotcompiler utils parser ir opt riscv)
|
@ -0,0 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
|
||||
set(SOURCE_FILES "ir.cpp" "genIR.cpp")
|
||||
|
||||
add_library(ir STATIC ${SOURCE_FILES})
|
||||
|
||||
target_include_directories(ir PRIVATE "${PARSER_INCLUDE}")
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,210 @@
|
||||
#pragma once
|
||||
|
||||
#include "ast.h"
|
||||
#include "ir.h"
|
||||
#include <map>
|
||||
|
||||
class Scope {
|
||||
public:
|
||||
// enter a new scope
|
||||
void enter() { symbol.push_back({}); }
|
||||
|
||||
// exit a scope
|
||||
void exit() { symbol.pop_back(); }
|
||||
|
||||
bool in_global() { return symbol.size() == 1; }
|
||||
|
||||
// push a name to scope
|
||||
// return true if successful
|
||||
// return false if this name already exits
|
||||
// but func name could be same with variable name
|
||||
bool push(std::string name, Value *val) {
|
||||
bool result;
|
||||
result = (symbol[symbol.size() - 1].insert({name, val})).second;
|
||||
return result;
|
||||
}
|
||||
|
||||
Value *find(std::string name) {
|
||||
for (auto s = symbol.rbegin(); s != symbol.rend(); s++) {
|
||||
auto iter = s->find(name);
|
||||
if (iter != s->end()) {
|
||||
return iter->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::map<std::string, Value *>> symbol;
|
||||
};
|
||||
|
||||
class GenIR : public Visitor {
|
||||
public:
|
||||
void visit(CompUnitAST &ast) override;
|
||||
void visit(DeclDefAST &ast) override;
|
||||
void visit(DeclAST &ast) override;
|
||||
void visit(DefAST &ast) override;
|
||||
void visit(InitValAST &ast) override;
|
||||
void visit(FuncDefAST &ast) override;
|
||||
void visit(FuncFParamAST &ast) override;
|
||||
void visit(BlockAST &ast) override;
|
||||
void visit(BlockItemAST &ast) override;
|
||||
void visit(StmtAST &ast) override;
|
||||
void visit(ReturnStmtAST &ast) override;
|
||||
void visit(SelectStmtAST &ast) override;
|
||||
void visit(IterationStmtAST &ast) override;
|
||||
void visit(AddExpAST &ast) override;
|
||||
void visit(LValAST &ast) override;
|
||||
void visit(MulExpAST &ast) override;
|
||||
void visit(UnaryExpAST &ast) override;
|
||||
void visit(PrimaryExpAST &ast) override;
|
||||
void visit(CallAST &ast) override;
|
||||
void visit(NumberAST &ast) override;
|
||||
void visit(RelExpAST &ast) override;
|
||||
void visit(EqExpAST &ast) override;
|
||||
void visit(LAndExpAST &ast) override;
|
||||
void visit(LOrExpAST &ast) override;
|
||||
|
||||
IRStmtBuilder *builder;
|
||||
Scope scope;
|
||||
std::unique_ptr<Module> module;
|
||||
|
||||
GenIR() {
|
||||
module = std::unique_ptr<Module>(new Module());
|
||||
builder = new IRStmtBuilder(nullptr, module.get());
|
||||
auto TyVoid = module->void_ty_;
|
||||
auto TyInt32 = module->int32_ty_;
|
||||
auto TyInt32Ptr = module->get_pointer_type(module->int32_ty_);
|
||||
auto TyFloat = module->float32_ty_;
|
||||
auto TyFloatPtr = module->get_pointer_type(module->float32_ty_);
|
||||
|
||||
auto input_type = new FunctionType(TyInt32, {});
|
||||
auto get_int = new Function(input_type, "getint", module.get());
|
||||
|
||||
input_type = new FunctionType(TyFloat, {});
|
||||
auto get_float = new Function(input_type, "getfloat", module.get());
|
||||
|
||||
input_type = new FunctionType(TyInt32, {});
|
||||
auto get_char = new Function(input_type, "getch", module.get());
|
||||
|
||||
std::vector<Type *> input_params;
|
||||
std::vector<Type *>().swap(input_params);
|
||||
input_params.push_back(TyInt32Ptr);
|
||||
input_type = new FunctionType(TyInt32, input_params);
|
||||
auto get_int_array = new Function(input_type, "getarray", module.get());
|
||||
|
||||
std::vector<Type *>().swap(input_params);
|
||||
input_params.push_back(TyFloatPtr);
|
||||
input_type = new FunctionType(TyInt32, input_params);
|
||||
auto get_float_array = new Function(input_type, "getfarray", module.get());
|
||||
|
||||
std::vector<Type *> output_params;
|
||||
std::vector<Type *>().swap(output_params);
|
||||
output_params.push_back(TyInt32);
|
||||
auto output_type = new FunctionType(TyVoid, output_params);
|
||||
auto put_int = new Function(output_type, "putint", module.get());
|
||||
|
||||
std::vector<Type *>().swap(output_params);
|
||||
output_params.push_back(TyFloat);
|
||||
output_type = new FunctionType(TyVoid, output_params);
|
||||
auto put_float = new Function(output_type, "putfloat", module.get());
|
||||
|
||||
std::vector<Type *>().swap(output_params);
|
||||
output_params.push_back(TyInt32);
|
||||
output_type = new FunctionType(TyVoid, output_params);
|
||||
auto put_char = new Function(output_type, "putch", module.get());
|
||||
|
||||
std::vector<Type *>().swap(output_params);
|
||||
output_params.push_back(TyInt32);
|
||||
output_params.push_back(TyInt32Ptr);
|
||||
output_type = new FunctionType(TyVoid, output_params);
|
||||
auto put_int_array = new Function(output_type, "putarray", module.get());
|
||||
|
||||
std::vector<Type *>().swap(output_params);
|
||||
output_params.push_back(TyInt32);
|
||||
output_params.push_back(TyFloatPtr);
|
||||
output_type = new FunctionType(TyVoid, output_params);
|
||||
auto put_float_array = new Function(output_type, "putfarray", module.get());
|
||||
|
||||
output_params.clear();
|
||||
// output_params.push_back(TyInt32);
|
||||
auto time_type = new FunctionType(TyVoid, output_params);
|
||||
auto sysy_start_time =
|
||||
new Function(time_type, "_sysy_starttime", module.get());
|
||||
auto sysy_stop_time =
|
||||
new Function(time_type, "_sysy_stoptime", module.get());
|
||||
|
||||
output_params.clear();
|
||||
output_params.push_back(TyInt32Ptr);
|
||||
output_params.push_back(TyInt32Ptr);
|
||||
output_params.push_back(TyInt32);
|
||||
output_type = new FunctionType(TyVoid, output_params);
|
||||
auto memcpy = new Function(output_type, "__aeabi_memcpy4", module.get());
|
||||
|
||||
output_params.clear();
|
||||
output_params.push_back(TyInt32Ptr);
|
||||
output_params.push_back(TyInt32);
|
||||
output_type = new FunctionType(TyVoid, output_params);
|
||||
auto memclr = new Function(output_type, "__aeabi_memclr4", module.get());
|
||||
|
||||
output_params.push_back(TyInt32);
|
||||
output_type = new FunctionType(TyVoid, output_params);
|
||||
auto memset = new Function(output_type, "__aeabi_memset4", module.get());
|
||||
|
||||
output_params.clear();
|
||||
output_type = new FunctionType(TyVoid, output_params);
|
||||
auto llvm_memset =
|
||||
new Function(output_type, "llvm.memset.p0.i32", module.get());
|
||||
|
||||
// output_params.clear();
|
||||
// output_params.push_back(TyInt32);
|
||||
// output_type = new FunctionType(TyInt32, output_params);
|
||||
// auto my_malloc = new Function(output_type, "malloc", module.get());
|
||||
|
||||
scope.enter();
|
||||
scope.push("getint", get_int);
|
||||
scope.push("getfloat", get_float);
|
||||
scope.push("getch", get_char);
|
||||
scope.push("getarray", get_int_array);
|
||||
scope.push("getfarray", get_float_array);
|
||||
scope.push("putint", put_int);
|
||||
scope.push("putfloat", put_float);
|
||||
scope.push("putch", put_char);
|
||||
scope.push("putarray", put_int_array);
|
||||
scope.push("putfarray", put_float_array);
|
||||
scope.push("starttime", sysy_start_time);
|
||||
scope.push("stoptime", sysy_stop_time);
|
||||
scope.push("memcpy", memcpy);
|
||||
scope.push("memclr", memclr);
|
||||
scope.push("memset", memset);
|
||||
scope.push("llvm.memset.p0.i32", llvm_memset);
|
||||
// scope.push("malloc",my_malloc);
|
||||
}
|
||||
std::unique_ptr<Module> getModule() { return std::move(module); }
|
||||
|
||||
void checkInitType() const;
|
||||
|
||||
static int getNextDim(vector<int> &dimensionsCnt, int up, int cnt);
|
||||
|
||||
void localInit(Value *ptr, vector<unique_ptr<InitValAST>> &list,
|
||||
vector<int> &dimensionsCnt, int up);
|
||||
|
||||
static int getNextDim(vector<int> &elementsCnts, int up);
|
||||
|
||||
ConstantArray *globalInit(vector<int> &dimensions,
|
||||
vector<ArrayType *> &arrayTys, int up,
|
||||
vector<unique_ptr<InitValAST>> &list);
|
||||
|
||||
static void mergeElements(vector<int> &dimensions,
|
||||
vector<ArrayType *> &arrayTys, int up, int dimAdd,
|
||||
vector<Constant *> &elements,
|
||||
vector<int> &elementsCnts);
|
||||
|
||||
void finalMerge(vector<int> &dimensions, vector<ArrayType *> &arrayTys,
|
||||
int up, vector<Constant *> &elements,
|
||||
vector<int> &elementsCnts) const;
|
||||
|
||||
bool checkCalType(Value **val, int *intVal, float *floatVal);
|
||||
|
||||
void checkCalType(Value **val);
|
||||
};
|
@ -0,0 +1,108 @@
|
||||
#include "CombineInstr.h"
|
||||
#include "ConstSpread.h"
|
||||
#include "LoopInvariant.h"
|
||||
#include "SimplifyJump.h"
|
||||
#include "ast.h"
|
||||
#include "backend.h"
|
||||
#include "define.h"
|
||||
#include "genIR.h"
|
||||
#include "DeleteDeadCode.h"
|
||||
#include "opt.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <unistd.h>
|
||||
|
||||
extern unique_ptr<CompUnitAST> root;
|
||||
extern int yyparse();
|
||||
extern FILE *yyin;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Assert the number of arguments
|
||||
assert(argc >= 2);
|
||||
|
||||
// TODO: advanced argument parser
|
||||
char *filename = nullptr;
|
||||
int print_ir = false;
|
||||
int print_asm = false;
|
||||
|
||||
std::string output = "-";
|
||||
|
||||
int opt;
|
||||
bool isO2 = false;
|
||||
while ((opt = getopt(argc, argv, "Sco:O::")) != -1) {
|
||||
switch (opt) {
|
||||
case 'S':
|
||||
print_asm = true;
|
||||
print_ir = false;
|
||||
break;
|
||||
case 'c':
|
||||
print_ir = true;
|
||||
print_asm = false;
|
||||
break;
|
||||
case 'o':
|
||||
output = optarg;
|
||||
break;
|
||||
case 'O':
|
||||
isO2 = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
filename = argv[optind];
|
||||
|
||||
yyin = fopen(filename, "r");
|
||||
if (yyin == nullptr) {
|
||||
std::cout << "yyin open" << filename << "failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Frontend parser
|
||||
yyparse();
|
||||
|
||||
// Generate IR from AST
|
||||
GenIR genIR;
|
||||
root->accept(genIR);
|
||||
std::unique_ptr<Module> m = genIR.getModule();
|
||||
|
||||
// Run IR optimization
|
||||
// TODO
|
||||
if (isO2) {
|
||||
std::vector<Optimization *> Opt;
|
||||
Opt.push_back(new DeadCodeDeletion(m.get()));
|
||||
Opt.push_back(new ConstSpread(m.get()));
|
||||
Opt.push_back(new CombineInstr(m.get()));
|
||||
Opt.push_back(new DomainTree(m.get()));
|
||||
Opt.push_back(new SimplifyJump(m.get()));
|
||||
Opt.push_back(new LoopInvariant(m.get()));
|
||||
Opt.push_back(new SimplifyJump(m.get()));
|
||||
for (auto x : Opt)
|
||||
x->execute();
|
||||
}
|
||||
|
||||
// Open output file
|
||||
std::ofstream fout;
|
||||
std::ostream *out;
|
||||
if (output == "-") {
|
||||
out = &std::cout;
|
||||
} else {
|
||||
fout.open(output);
|
||||
out = &fout;
|
||||
}
|
||||
|
||||
// Print IR result
|
||||
const std::string IR = m->print();
|
||||
if (print_ir) {
|
||||
*out << IR << std::endl;
|
||||
}
|
||||
|
||||
// Generate assembly file
|
||||
// TODO
|
||||
if (print_asm) {
|
||||
auto builder = new RiscvBuilder();
|
||||
const std::string RiscvCode = builder->buildRISCV(m.get());
|
||||
*out << RiscvCode << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
#include "BasicOperation.h"
|
||||
|
||||
void deleteUse(Value *opnd, Instruction *inst) {
|
||||
for (auto it = opnd->use_list_.begin(); it != opnd->use_list_.end(); ++it)
|
||||
if (it->val_ == inst) {
|
||||
opnd->use_list_.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void SolvePhi(BasicBlock *bb, BasicBlock *suc) {
|
||||
std::vector<Instruction *> uselessPhi;
|
||||
for (auto instr : suc->instr_list_) {
|
||||
if (instr->op_id_ == Instruction::PHI) {
|
||||
for (int i = 1; i < instr->num_ops_; i = i + 2)
|
||||
if (instr->get_operand(i) == bb) {
|
||||
instr->remove_operands(i - 1, i);
|
||||
break;
|
||||
}
|
||||
if (instr->parent_->pre_bbs_.size() == 1) {
|
||||
Value *only = instr->get_operand(0);
|
||||
instr->replace_all_use_with(only);
|
||||
uselessPhi.push_back(instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto instr : uselessPhi)
|
||||
suc->delete_instr(instr);
|
||||
}
|
||||
|
||||
void dfsGraph(BasicBlock *bb, std::set<BasicBlock *> &vis) {
|
||||
if (!bb)
|
||||
return;
|
||||
vis.insert(bb);
|
||||
for (auto suc : bb->succ_bbs_) {
|
||||
if (vis.find(suc) == vis.end())
|
||||
dfsGraph(suc, vis);
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteUnusedBB(Function *func) {
|
||||
std::set<BasicBlock *> vis;
|
||||
for (auto bb : func->basic_blocks_)
|
||||
if (bb->name_ == "label_entry") {
|
||||
dfsGraph(bb, vis);
|
||||
break;
|
||||
}
|
||||
for (auto bb : func->basic_blocks_)
|
||||
if (vis.find(bb) == vis.end()) {
|
||||
bb->parent_->remove_bb(bb);
|
||||
for (auto suc : bb->succ_bbs_)
|
||||
SolvePhi(bb, suc);
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
#ifndef BASICOPERATION
|
||||
#define BASICOPERATION
|
||||
#include "../ir/ir.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include "opt.h"
|
||||
|
||||
void deleteUse(Value* opnd,Instruction *inst);
|
||||
void dfsGraph(BasicBlock *bb, std::set<BasicBlock *> &vis);
|
||||
void SolvePhi(BasicBlock *bb, BasicBlock *succ_bb);
|
||||
void DeleteUnusedBB(Function *func);
|
||||
|
||||
#endif // !BASICOPERATION
|
@ -0,0 +1,6 @@
|
||||
set(SOURCE_FILES ConstSpread.cpp BasicOperation.cpp LoopInvariant.cpp CombineInstr.cpp SimplifyJump.cpp opt.cpp DeleteDeadCode.cpp)
|
||||
|
||||
add_library(opt ${SOURCE_FILES})
|
||||
|
||||
target_link_libraries(opt PRIVATE ir)
|
||||
target_include_directories(opt PRIVATE ${CMAKE_SOURCE_DIR}/src/ir)
|
@ -0,0 +1,13 @@
|
||||
#ifndef COMBINEINSTRH
|
||||
#define COMBINEINSTRH
|
||||
#include "opt.h"
|
||||
|
||||
class CombineInstr : public Optimization {
|
||||
|
||||
public:
|
||||
CombineInstr(Module *m) : Optimization(m) {}
|
||||
void execute();
|
||||
void checkBlock(BasicBlock *bb);
|
||||
};
|
||||
|
||||
#endif // !COMBINEINSTRH
|
@ -0,0 +1,354 @@
|
||||
#include "ConstSpread.h"
|
||||
|
||||
ConstantInt *ConstSpread::CalcInt(Instruction::OpID op, ConstantInt *v1,
|
||||
ConstantInt *v2) {
|
||||
int a = v1->value_, b = v2->value_;
|
||||
switch (op) {
|
||||
case Instruction::Add:
|
||||
return new ConstantInt(m->int32_ty_, a + b);
|
||||
case Instruction::Sub:
|
||||
return new ConstantInt(m->int32_ty_, a - b);
|
||||
case Instruction::Mul:
|
||||
return new ConstantInt(m->int32_ty_, a * b);
|
||||
case Instruction::SDiv:
|
||||
return new ConstantInt(m->int32_ty_, a / b);
|
||||
case Instruction::SRem:
|
||||
return new ConstantInt(m->int32_ty_, a % b);
|
||||
case Instruction::Shl:
|
||||
return new ConstantInt(m->int32_ty_, a << b);
|
||||
case Instruction::LShr:
|
||||
return new ConstantInt(m->int32_ty_, (unsigned)a >> b);
|
||||
case Instruction::AShr:
|
||||
return new ConstantInt(m->int32_ty_, a >> b);
|
||||
case Instruction::And:
|
||||
return new ConstantInt(m->int32_ty_, a & b);
|
||||
case Instruction::Or:
|
||||
return new ConstantInt(m->int32_ty_, a | b);
|
||||
case Instruction::Xor:
|
||||
return new ConstantInt(m->int32_ty_, a ^ b);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ConstantFloat *ConstSpread::CalcFloat(Instruction::OpID op, ConstantFloat *v1,
|
||||
ConstantFloat *v2) {
|
||||
float a = v1->value_, b = v2->value_;
|
||||
switch (op) {
|
||||
case Instruction::FAdd:
|
||||
return new ConstantFloat(m->float32_ty_, a + b);
|
||||
case Instruction::FSub:
|
||||
return new ConstantFloat(m->float32_ty_, a - b);
|
||||
case Instruction::FMul:
|
||||
return new ConstantFloat(m->float32_ty_, a * b);
|
||||
case Instruction::FDiv:
|
||||
return new ConstantFloat(m->float32_ty_, a / b);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ConstantInt *ConstSpread::CalcICMP(ICmpInst::ICmpOp op, ConstantInt *v1,
|
||||
ConstantInt *v2) {
|
||||
int lhs = v1->value_;
|
||||
int rhs = v2->value_;
|
||||
switch (op) {
|
||||
case ICmpInst::ICMP_EQ:
|
||||
return new ConstantInt(m->int1_ty_, lhs == rhs);
|
||||
case ICmpInst::ICMP_NE:
|
||||
return new ConstantInt(m->int1_ty_, lhs != rhs);
|
||||
case ICmpInst::ICMP_SGT:
|
||||
return new ConstantInt(m->int1_ty_, lhs > rhs);
|
||||
case ICmpInst::ICMP_SGE:
|
||||
return new ConstantInt(m->int1_ty_, lhs >= rhs);
|
||||
case ICmpInst::ICMP_SLE:
|
||||
return new ConstantInt(m->int1_ty_, lhs <= rhs);
|
||||
case ICmpInst::ICMP_SLT:
|
||||
return new ConstantInt(m->int1_ty_, lhs < rhs);
|
||||
case ICmpInst::ICMP_UGE:
|
||||
return new ConstantInt(m->int1_ty_, (unsigned)lhs >= (unsigned)rhs);
|
||||
case ICmpInst::ICMP_ULE:
|
||||
return new ConstantInt(m->int1_ty_, (unsigned)lhs <= (unsigned)rhs);
|
||||
case ICmpInst::ICMP_ULT:
|
||||
return new ConstantInt(m->int1_ty_, (unsigned)lhs < (unsigned)rhs);
|
||||
case ICmpInst::ICMP_UGT:
|
||||
return new ConstantInt(m->int1_ty_, (unsigned)lhs > (unsigned)rhs);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
ConstantInt *ConstSpread::CalcFCMP(FCmpInst::FCmpOp op, ConstantFloat *v1,
|
||||
ConstantFloat *v2) {
|
||||
float lhs = v1->value_;
|
||||
float rhs = v2->value_;
|
||||
switch (op) {
|
||||
case FCmpInst::FCMP_UEQ:
|
||||
return new ConstantInt(m->int1_ty_, lhs == rhs);
|
||||
case FCmpInst::FCMP_UNE:
|
||||
return new ConstantInt(m->int1_ty_, lhs != rhs);
|
||||
case FCmpInst::FCMP_UGT:
|
||||
return new ConstantInt(m->int1_ty_, lhs > rhs);
|
||||
case FCmpInst::FCMP_UGE:
|
||||
return new ConstantInt(m->int1_ty_, lhs >= rhs);
|
||||
case FCmpInst::FCMP_ULE:
|
||||
return new ConstantInt(m->int1_ty_, lhs <= rhs);
|
||||
case FCmpInst::FCMP_ULT:
|
||||
return new ConstantInt(m->int1_ty_, lhs < rhs);
|
||||
case FCmpInst::FCMP_FALSE:
|
||||
return new ConstantInt(m->int1_ty_, 0);
|
||||
case FCmpInst::FCMP_TRUE:
|
||||
return new ConstantInt(m->int1_ty_, 1);
|
||||
case FCmpInst::FCMP_OEQ:
|
||||
return new ConstantInt(m->int1_ty_, lhs == rhs);
|
||||
case FCmpInst::FCMP_ONE:
|
||||
return new ConstantInt(m->int1_ty_, lhs != rhs);
|
||||
case FCmpInst::FCMP_OGE:
|
||||
return new ConstantInt(m->int1_ty_, lhs >= rhs);
|
||||
case FCmpInst::FCMP_OGT:
|
||||
return new ConstantInt(m->int1_ty_, lhs > rhs);
|
||||
case FCmpInst::FCMP_OLE:
|
||||
return new ConstantInt(m->int1_ty_, lhs <= rhs);
|
||||
case FCmpInst::FCMP_OLT:
|
||||
return new ConstantInt(m->int1_ty_, lhs < rhs);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ConstSpread::execute() {
|
||||
assert(m != nullptr);
|
||||
for (Function *foo : m->function_list_) {
|
||||
if (foo->basic_blocks_.size()) {
|
||||
bool change = true;
|
||||
while (change) {
|
||||
change = false;
|
||||
change |= SpreadingConst(foo);
|
||||
change |= BranchProcess(foo);
|
||||
DeleteUnusedBB(foo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ConstSpread::SpreadingConst(Function *func) {
|
||||
uselessInstr.clear();
|
||||
for (auto bb : func->basic_blocks_) {
|
||||
ConstIntMap.clear();
|
||||
ConstFloatMap.clear();
|
||||
for (auto instr : bb->instr_list_) {
|
||||
ConstantInt *testConstInta = nullptr, *testConstIntb = nullptr;
|
||||
ConstantFloat *testConstFloata = nullptr, *testConstFloatb = nullptr;
|
||||
switch (instr->op_id_) {
|
||||
case Instruction::Add:
|
||||
case Instruction::Sub:
|
||||
case Instruction::Mul:
|
||||
case Instruction::SDiv:
|
||||
case Instruction::UDiv:
|
||||
case Instruction::SRem:
|
||||
case Instruction::URem:
|
||||
case Instruction::And:
|
||||
case Instruction::Or:
|
||||
case Instruction::Xor:
|
||||
case Instruction::Shl:
|
||||
case Instruction::AShr:
|
||||
case Instruction::LShr:
|
||||
testConstInta = dynamic_cast<ConstantInt *>(instr->get_operand(0));
|
||||
testConstIntb = dynamic_cast<ConstantInt *>(instr->get_operand(1));
|
||||
if (testConstInta && testConstIntb) {
|
||||
auto intRes =
|
||||
this->CalcInt(instr->op_id_, testConstInta, testConstIntb);
|
||||
if (intRes) {
|
||||
instr->replace_all_use_with(intRes);
|
||||
uselessInstr[instr] = bb;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Instruction::ICmp:
|
||||
testConstInta = dynamic_cast<ConstantInt *>(instr->get_operand(0));
|
||||
testConstIntb = dynamic_cast<ConstantInt *>(instr->get_operand(1));
|
||||
if (testConstInta && testConstIntb) {
|
||||
auto res = this->CalcICMP(dynamic_cast<ICmpInst *>(instr)->icmp_op_,
|
||||
testConstInta, testConstIntb);
|
||||
if (res) {
|
||||
instr->replace_all_use_with(res);
|
||||
uselessInstr[instr] = bb;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Instruction::FCmp:
|
||||
testConstFloata = dynamic_cast<ConstantFloat *>(instr->get_operand(0));
|
||||
testConstFloatb = dynamic_cast<ConstantFloat *>(instr->get_operand(1));
|
||||
if (testConstFloata && testConstFloatb) {
|
||||
auto res = this->CalcFCMP(dynamic_cast<FCmpInst *>(instr)->fcmp_op_,
|
||||
testConstFloata, testConstFloatb);
|
||||
if (res) {
|
||||
instr->replace_all_use_with(res);
|
||||
uselessInstr[instr] = bb;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Instruction::FAdd:
|
||||
case Instruction::FSub:
|
||||
case Instruction::FMul:
|
||||
case Instruction::FDiv:
|
||||
testConstFloata = dynamic_cast<ConstantFloat *>(instr->get_operand(0));
|
||||
testConstFloatb = dynamic_cast<ConstantFloat *>(instr->get_operand(1));
|
||||
if (testConstFloata && testConstFloatb) {
|
||||
auto floaRes =
|
||||
this->CalcFloat(instr->op_id_, testConstFloata, testConstFloatb);
|
||||
if (floaRes) {
|
||||
instr->replace_all_use_with(floaRes);
|
||||
uselessInstr[instr] = bb;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Instruction::FNeg:
|
||||
testConstFloata = dynamic_cast<ConstantFloat *>(instr->get_operand(0));
|
||||
if (testConstFloata) {
|
||||
instr->replace_all_use_with(
|
||||
new ConstantFloat(m->float32_ty_, -testConstFloata->value_));
|
||||
uselessInstr[instr] = bb;
|
||||
}
|
||||
break;
|
||||
case Instruction::FPtoSI:
|
||||
testConstFloata = dynamic_cast<ConstantFloat *>(instr->get_operand(0));
|
||||
if (testConstFloata) {
|
||||
instr->replace_all_use_with(
|
||||
new ConstantInt(m->int32_ty_, testConstFloata->value_));
|
||||
uselessInstr[instr] = bb;
|
||||
}
|
||||
break;
|
||||
case Instruction::SItoFP:
|
||||
testConstInta = dynamic_cast<ConstantInt *>(instr->get_operand(0));
|
||||
if (testConstInta) {
|
||||
instr->replace_all_use_with(
|
||||
new ConstantFloat(m->float32_ty_, testConstInta->value_));
|
||||
uselessInstr[instr] = bb;
|
||||
}
|
||||
break;
|
||||
case Instruction::ZExt:
|
||||
testConstInta = dynamic_cast<ConstantInt *>(instr->get_operand(0));
|
||||
if (testConstInta) {
|
||||
instr->replace_all_use_with(
|
||||
new ConstantInt(m->int32_ty_, testConstInta->value_));
|
||||
uselessInstr[instr] = bb;
|
||||
}
|
||||
break;
|
||||
case Instruction::Call:
|
||||
ConstIntMap.clear();
|
||||
ConstFloatMap.clear();
|
||||
case Instruction::Load: {
|
||||
auto globalVar = dynamic_cast<GlobalVariable *>(instr->get_operand(0));
|
||||
if (globalVar) {
|
||||
auto iterInt = ConstIntMap.find(globalVar);
|
||||
auto iterFloat = ConstFloatMap.find(globalVar);
|
||||
if (iterInt != ConstIntMap.end()) {
|
||||
instr->replace_all_use_with(iterInt->second);
|
||||
uselessInstr[instr] = bb;
|
||||
} else if (iterFloat != ConstFloatMap.end()) {
|
||||
instr->replace_all_use_with(iterFloat->second);
|
||||
uselessInstr[instr] = bb;
|
||||
}
|
||||
} else if (dynamic_cast<AllocaInst *>(instr->get_operand(0))) {
|
||||
auto pos = dynamic_cast<AllocaInst *>(instr->get_operand(0));
|
||||
if (pos->alloca_ty_->tid_ == Type::IntegerTyID) {
|
||||
auto iterInt = ConstIntMap.find(pos);
|
||||
if (iterInt != ConstIntMap.end()) {
|
||||
instr->replace_all_use_with(iterInt->second);
|
||||
uselessInstr[instr] = bb;
|
||||
}
|
||||
} else if (pos->alloca_ty_->tid_ == Type::FloatTyID) {
|
||||
auto iterFloat = ConstFloatMap.find(pos);
|
||||
if (iterFloat != ConstFloatMap.end()) {
|
||||
instr->replace_all_use_with(iterFloat->second);
|
||||
uselessInstr[instr] = bb;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Instruction::Store: {
|
||||
// std::cout << "EVER STORE\n";
|
||||
auto storePos = instr->get_operand(1);
|
||||
auto storeValInt = dynamic_cast<ConstantInt *>(instr->get_operand(0));
|
||||
auto storeValFloat =
|
||||
dynamic_cast<ConstantFloat *>(instr->get_operand(0));
|
||||
if (storeValInt) {
|
||||
auto iter1 = ConstIntMap.find(storePos);
|
||||
if (iter1 != ConstIntMap.end()) {
|
||||
if (iter1->second->value_ == storeValInt->value_)
|
||||
uselessInstr[instr] = bb;
|
||||
else
|
||||
iter1->second = storeValInt;
|
||||
} else
|
||||
ConstIntMap[storePos] = storeValInt;
|
||||
} else if (storeValFloat) {
|
||||
auto iter = ConstFloatMap.find(storePos);
|
||||
if (iter != ConstFloatMap.end()) {
|
||||
if (iter->second->value_ == storeValInt->value_)
|
||||
uselessInstr[instr] = bb;
|
||||
else
|
||||
iter->second = storeValFloat;
|
||||
} else
|
||||
ConstFloatMap[storePos] = storeValFloat;
|
||||
} else {
|
||||
// 非常量存储,则该地址数据不再是常量
|
||||
auto iterInt = ConstIntMap.find(storePos);
|
||||
auto iterFloat = ConstFloatMap.find(storePos);
|
||||
if (iterInt != ConstIntMap.end())
|
||||
ConstIntMap.erase(iterInt);
|
||||
if (iterFloat != ConstFloatMap.end())
|
||||
ConstFloatMap.erase(iterFloat);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!uselessInstr.empty()) {
|
||||
for (auto [instr, bb] : uselessInstr)
|
||||
bb->delete_instr(instr);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConstSpread::BranchProcess(Function *func) {
|
||||
bool change = false;
|
||||
for (auto bb : func->basic_blocks_) {
|
||||
auto br = bb->get_terminator();
|
||||
if (!br)
|
||||
continue;
|
||||
if (br->op_id_ == Instruction::Br &&
|
||||
dynamic_cast<BranchInst *>(br)->num_ops_ == 3) {
|
||||
auto cond = dynamic_cast<ConstantInt *>(br->get_operand(0));
|
||||
auto truebb = br->get_operand(1);
|
||||
auto falsebb = br->get_operand(2);
|
||||
if (!cond)
|
||||
continue;
|
||||
change = true;
|
||||
if (cond->value_ == 0) {
|
||||
bb->delete_instr(br);
|
||||
for (auto succ_bb : bb->succ_bbs_) {
|
||||
succ_bb->remove_pre_basic_block(bb);
|
||||
if (succ_bb != falsebb) {
|
||||
SolvePhi(bb, succ_bb);
|
||||
}
|
||||
}
|
||||
bb->succ_bbs_.clear();
|
||||
new BranchInst(dynamic_cast<BasicBlock *>(falsebb), bb);
|
||||
} else {
|
||||
bb->delete_instr(br);
|
||||
for (auto succ_bb : bb->succ_bbs_) {
|
||||
succ_bb->remove_pre_basic_block(bb);
|
||||
if (succ_bb != truebb) {
|
||||
SolvePhi(bb, succ_bb);
|
||||
}
|
||||
}
|
||||
bb->succ_bbs_.clear();
|
||||
new BranchInst(dynamic_cast<BasicBlock *>(truebb), bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
return change;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
#ifndef CONSTSPREAD
|
||||
#define CONSTSPREAD
|
||||
#include "../ir/ir.h"
|
||||
#include "BasicOperation.h"
|
||||
#include "opt.h"
|
||||
|
||||
class ConstSpread : public Optimization {
|
||||
public:
|
||||
ConstSpread(Module *m_) : Optimization(m_) {}
|
||||
void execute();
|
||||
ConstantInt *CalcInt(Instruction::OpID op, ConstantInt *v1, ConstantInt *v2);
|
||||
ConstantFloat *CalcFloat(Instruction::OpID op, ConstantFloat *v1,
|
||||
ConstantFloat *v2);
|
||||
ConstantInt *CalcICMP(ICmpInst::ICmpOp op, ConstantInt *v1, ConstantInt *v2);
|
||||
ConstantInt *CalcFCMP(FCmpInst::FCmpOp op, ConstantFloat *v1, ConstantFloat *v2);
|
||||
bool SpreadingConst(Function *func);
|
||||
bool BranchProcess(Function *func);
|
||||
std::map<Value *, ConstantInt *> ConstIntMap;
|
||||
std::map<Value *, ConstantFloat *> ConstFloatMap;
|
||||
std::map<Instruction *, BasicBlock *> uselessInstr;
|
||||
};
|
||||
|
||||
#endif // !CONSTSPREAD
|
@ -0,0 +1,180 @@
|
||||
#include "DeleteDeadCode.h"
|
||||
#include "ConstSpread.h"
|
||||
|
||||
std::set<std::string> OptFunc = {"getint", "getfloat",
|
||||
"getch", "getarray",
|
||||
"getfarray", "putint",
|
||||
"putfloat", "putch",
|
||||
"putarray", "putfarray",
|
||||
"_sysy_starttime", "_sysy_stoptime",
|
||||
"memcpy", "memclr",
|
||||
"memset", "llvm.memset.p0.i32",
|
||||
"__aeabi_memcpy4", "__aeabi_memclr4",
|
||||
"__aeabi_memset4"};
|
||||
|
||||
void DeadCodeDeletion::initFuncPtrArg() {
|
||||
for (auto foo : m->function_list_) {
|
||||
if (foo->basic_blocks_.empty())
|
||||
continue;
|
||||
for (auto arg : foo->arguments_)
|
||||
if (arg->type_->tid_ == Type::PointerTyID) {
|
||||
if (!funcPtrArgs.count(foo))
|
||||
funcPtrArgs[foo] = {};
|
||||
funcPtrArgs[foo].insert(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
void DeadCodeDeletion::Init(Function *foo) {
|
||||
storePos.clear();
|
||||
for (auto bb : foo->basic_blocks_) {
|
||||
for (auto ins : bb->instr_list_) {
|
||||
if (ins->op_id_ == Instruction::GetElementPtr) {
|
||||
} else if (ins->op_id_ == Instruction::Store) {
|
||||
if (!storePos.count(ins->get_operand(1))) {
|
||||
storePos.insert({ins->get_operand(1), {}});
|
||||
}
|
||||
storePos[ins->get_operand(1)].push_back(ins);
|
||||
if (dynamic_cast<GlobalVariable *>(ins->get_operand(1)))
|
||||
OptFunc.insert(foo->name_);
|
||||
if (dynamic_cast<GetElementPtrInst *>(ins->get_operand(1)))
|
||||
OptFunc.insert(foo->name_);
|
||||
if (funcPtrArgs[foo].count(ins->get_operand(1)))
|
||||
OptFunc.insert(foo->name_);
|
||||
} else if (ins->op_id_ == Instruction::Call) {
|
||||
auto f = ins->get_operand(ins->operands_.size() - 1);
|
||||
if (OptFunc.count(f->name_))
|
||||
OptFunc.insert(foo->name_);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bool DeadCodeDeletion::checkOpt(Function *foo, Instruction *ins) {
|
||||
if (ins->op_id_ == Instruction::Ret) {
|
||||
exitBlock = ins->parent_;
|
||||
return true;
|
||||
} else if (ins->op_id_ == Instruction::Call) {
|
||||
auto f = ins->get_operand(ins->operands_.size() - 1);
|
||||
return OptFunc.count(f->name_);
|
||||
} else if (ins->op_id_ == Instruction::Store) {
|
||||
if (dynamic_cast<GlobalVariable *>(ins->get_operand(1)))
|
||||
return true;
|
||||
if (dynamic_cast<GetElementPtrInst *>(ins->get_operand(1)))
|
||||
return true;
|
||||
if (funcPtrArgs[foo].count(ins->get_operand(1)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeadCodeDeletion::findInstr(Function *foo) {
|
||||
std::list<Value *> workList;
|
||||
for (auto bb : foo->basic_blocks_) {
|
||||
for (auto ins : bb->instr_list_) {
|
||||
if (checkOpt(foo, ins)) {
|
||||
uselessInstr.insert(ins);
|
||||
workList.push_back(ins);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!workList.empty()) {
|
||||
auto ins = dynamic_cast<Instruction *>(workList.back());
|
||||
workList.pop_back();
|
||||
if (ins == nullptr) {
|
||||
continue;
|
||||
}
|
||||
for (auto operand : ins->operands_) {
|
||||
auto temp = dynamic_cast<Instruction *>(operand);
|
||||
if (!temp)
|
||||
continue;
|
||||
if (uselessInstr.insert(temp).second) {
|
||||
workList.push_back(temp);
|
||||
}
|
||||
}
|
||||
if (ins->op_id_ == Instruction::PHI) {
|
||||
for (int i = 1; i < ins->operands_.size(); i += 2) {
|
||||
auto bb = dynamic_cast<BasicBlock *>(ins->get_operand(i));
|
||||
auto br = bb->get_terminator();
|
||||
if (uselessInstr.insert(br).second) {
|
||||
workList.push_back(br);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (storePos.count(ins)) {
|
||||
for (auto curInstr : storePos[ins]) {
|
||||
if (uselessInstr.insert(dynamic_cast<Instruction *>(curInstr)).second) {
|
||||
workList.push_back(curInstr);
|
||||
}
|
||||
}
|
||||
storePos.erase(ins);
|
||||
}
|
||||
if (uselessBlock.insert(ins->parent_).second) {
|
||||
for (auto RFrontier : ins->parent_->rdom_frontier_) {
|
||||
auto t = RFrontier->get_terminator();
|
||||
if (uselessInstr.insert(t).second) {
|
||||
workList.push_back(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void DeadCodeDeletion::deleteInstr(Function *foo) {
|
||||
int deleteCnt = 0, changeCnt = 0;
|
||||
for (auto bb : foo->basic_blocks_) {
|
||||
std::vector<Instruction *> ins2Del;
|
||||
for (auto ins : bb->instr_list_) {
|
||||
if (!uselessInstr.count(ins)) {
|
||||
if (ins->op_id_ != Instruction::Br) {
|
||||
ins2Del.push_back(ins);
|
||||
} else {
|
||||
if (ins->operands_.size() == 3) {
|
||||
changeCnt++;
|
||||
auto trueBB = dynamic_cast<BasicBlock *>(ins->get_operand(1));
|
||||
auto falseBB = dynamic_cast<BasicBlock *>(ins->get_operand(2));
|
||||
trueBB->remove_pre_basic_block(bb);
|
||||
falseBB->remove_pre_basic_block(bb);
|
||||
bb->remove_succ_basic_block(trueBB);
|
||||
bb->remove_succ_basic_block(falseBB);
|
||||
BasicBlock *temp = exitBlock;
|
||||
std::vector<BasicBlock *> rdoms(bb->rdoms_.begin(),
|
||||
bb->rdoms_.end());
|
||||
std::sort(rdoms.begin(), rdoms.end(),
|
||||
[=](BasicBlock *x, BasicBlock *y) -> bool {
|
||||
return x->rdoms_.count(y);
|
||||
});
|
||||
for (auto rdbb : rdoms) {
|
||||
if (rdbb != bb && uselessBlock.count(rdbb)) {
|
||||
temp = rdbb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ins->remove_operands(0, 2);
|
||||
ins->num_ops_ = 1;
|
||||
ins->operands_.resize(1);
|
||||
ins->use_pos_.resize(1);
|
||||
ins->set_operand(0, temp);
|
||||
bb->add_succ_basic_block(temp);
|
||||
temp->add_pre_basic_block(bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
deleteCnt += ins2Del.size();
|
||||
for (auto ins : ins2Del) {
|
||||
bb->delete_instr(ins);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeadCodeDeletion::execute() {
|
||||
ReverseDomainTree reverseDomainTree(m);
|
||||
reverseDomainTree.execute();
|
||||
initFuncPtrArg();
|
||||
for (auto foo : m->function_list_)
|
||||
if (!foo->basic_blocks_.empty()) {
|
||||
Init(foo);
|
||||
findInstr(foo);
|
||||
deleteInstr(foo);
|
||||
DeleteUnusedBB(foo);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
#ifndef DELETEDEADCODEH
|
||||
#define DELETEDEADCODEH
|
||||
|
||||
#include "opt.h"
|
||||
|
||||
extern std::set<std::string> sysLibFunc;
|
||||
|
||||
class DeadCodeDeletion : public Optimization {
|
||||
std::map<Function *, std::set<Value *>> funcPtrArgs;
|
||||
std::map<Value *, std::vector<Value *>> storePos;
|
||||
BasicBlock *exitBlock;
|
||||
std::set<Instruction *> uselessInstr;
|
||||
std::set<BasicBlock *> uselessBlock;
|
||||
|
||||
public:
|
||||
DeadCodeDeletion(Module *m) : Optimization(m), exitBlock(nullptr) {}
|
||||
void execute();
|
||||
void initFuncPtrArg();
|
||||
void Init(Function *foo);
|
||||
bool checkOpt(Function *foo, Instruction *instr);
|
||||
void findInstr(Function *foo);
|
||||
void deleteInstr(Function *foo);
|
||||
};
|
||||
|
||||
#endif // !DELETEDEADCODEH
|
@ -0,0 +1,31 @@
|
||||
#ifndef LOOPH
|
||||
#define LOOPH
|
||||
|
||||
#include "BasicOperation.h"
|
||||
|
||||
struct node {
|
||||
BasicBlock *bb;
|
||||
std::set<node *> pre;
|
||||
std::set<node *> suc;
|
||||
int dfn, low;
|
||||
bool inStack;
|
||||
node() = default;
|
||||
node(BasicBlock *bb_, int dfn_, int low_, bool inStack_)
|
||||
: bb(bb_), dfn(dfn_), low(low_), inStack(inStack_) {}
|
||||
};
|
||||
|
||||
class LoopInvariant : public Optimization {
|
||||
int ind;
|
||||
std::stack<node *> tarjanStack;
|
||||
std::stack<std::set<BasicBlock *> *> loopStack;
|
||||
std::map<std::set<BasicBlock *> *, BasicBlock *> entryPos;
|
||||
|
||||
public:
|
||||
LoopInvariant(Module *m) : Optimization(m) {}
|
||||
void execute();
|
||||
void searchLoop();
|
||||
bool searchSCC(std::set<node *> &basicBlock, std::set<std::set<node *> *> &SCCs);
|
||||
void tarjan(node *pos, std::set<std::set<node *> *> &SCCs);
|
||||
};
|
||||
|
||||
#endif // !LOOPH
|
@ -0,0 +1,120 @@
|
||||
#include "SimplifyJump.h"
|
||||
|
||||
void SimplifyJump::execute() {
|
||||
for (auto foo : m->function_list_)
|
||||
if (foo->basic_blocks_.empty()) {
|
||||
deleteUnReachableBlock(foo);
|
||||
mergePreBlock(foo);
|
||||
deleteUselessPhi(foo);
|
||||
deleteUselessJump(foo);
|
||||
}
|
||||
}
|
||||
|
||||
void SimplifyJump::deleteUselessBlock(Function *foo,
|
||||
std::vector<BasicBlock *> &uselessBlock) {
|
||||
for (auto bb : uselessBlock)
|
||||
foo->remove_bb(bb);
|
||||
}
|
||||
|
||||
bool SimplifyJump::checkUselessJump(BasicBlock *bb) {
|
||||
auto JumpPos = bb->get_terminator()->get_operand(0);
|
||||
for (auto preBB : bb->pre_bbs_) {
|
||||
auto br = preBB->get_terminator();
|
||||
if (br->operands_.size() == 1)
|
||||
continue;
|
||||
auto trueBB = br->get_operand(1);
|
||||
auto falseBB = br->get_operand(2);
|
||||
if (trueBB == JumpPos || falseBB == JumpPos)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SimplifyJump::deleteUnReachableBlock(Function *foo) {
|
||||
std::vector<BasicBlock *> uselessBlock;
|
||||
for (int i = 2; i < foo->basic_blocks_.size(); i++) {
|
||||
auto curbb = foo->basic_blocks_[i];
|
||||
if (curbb->pre_bbs_.empty()) {
|
||||
uselessBlock.push_back(curbb);
|
||||
// 发现无用块后需要提前进行phi合流处理
|
||||
for (auto use : curbb->use_list_) {
|
||||
auto instr = dynamic_cast<PhiInst *>(use.val_);
|
||||
if (instr != nullptr)
|
||||
instr->remove_operands(use.arg_no_ - 1, use.arg_no_);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SimplifyJump::mergePreBlock(Function *foo) {
|
||||
std::vector<BasicBlock *> uselessBlock;
|
||||
for (int i = 2; i < foo->basic_blocks_.size(); i++) {
|
||||
auto bb = foo->basic_blocks_[i];
|
||||
if (bb->pre_bbs_.size() == 1) {
|
||||
auto preBlock = *bb->pre_bbs_.begin();
|
||||
auto preBr = preBlock->get_terminator();
|
||||
if (preBlock->succ_bbs_.size() != 1)
|
||||
continue;
|
||||
preBlock->delete_instr(preBr);
|
||||
for (auto instr : bb->instr_list_) {
|
||||
preBlock->add_instruction(instr);
|
||||
bb->remove_instr(instr);
|
||||
}
|
||||
preBlock->remove_succ_basic_block(bb);
|
||||
for (auto suc : bb->succ_bbs_) {
|
||||
preBlock->add_succ_basic_block(suc);
|
||||
suc->remove_pre_basic_block(bb);
|
||||
suc->add_pre_basic_block(preBlock);
|
||||
}
|
||||
bb->replace_all_use_with(preBlock);
|
||||
uselessBlock.push_back(bb);
|
||||
}
|
||||
}
|
||||
deleteUselessBlock(foo, uselessBlock);
|
||||
}
|
||||
|
||||
void SimplifyJump::deleteUselessPhi(Function *foo) {
|
||||
for (auto bb : foo->basic_blocks_)
|
||||
if (bb->pre_bbs_.size() == 1)
|
||||
for (auto instr : bb->instr_list_)
|
||||
if (instr->is_phi()) {
|
||||
instr->replace_all_use_with(instr->get_operand(0));
|
||||
bb->delete_instr(instr);
|
||||
}
|
||||
}
|
||||
|
||||
void SimplifyJump::deleteUselessJump(Function *foo) {
|
||||
std::vector<BasicBlock *> uselessBlock;
|
||||
for (int i = 2; i < foo->basic_blocks_.size(); i++) {
|
||||
BasicBlock *curbb = foo->basic_blocks_[i];
|
||||
if (curbb->instr_list_.size() != 1)
|
||||
continue;
|
||||
auto branchInstr = curbb->get_terminator();
|
||||
if (branchInstr->operands_.size() != 1 || branchInstr->is_ret())
|
||||
continue;
|
||||
if (!checkUselessJump(curbb))
|
||||
continue;
|
||||
uselessBlock.push_back(curbb);
|
||||
auto JumpTarget = dynamic_cast<BasicBlock *>(branchInstr->get_operand(0));
|
||||
for (auto instr : JumpTarget->instr_list_)
|
||||
if (instr->is_phi()) {
|
||||
for (int i = 1; i < instr->operands_.size(); i += 2) {
|
||||
if (instr->get_operand(i) == curbb) {
|
||||
auto val = instr->get_operand(i - 1);
|
||||
instr->remove_operands(i - 1, i);
|
||||
for (auto preBB : curbb->pre_bbs_) {
|
||||
instr->add_operand(val);
|
||||
instr->add_operand(preBB);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
curbb->replace_all_use_with(JumpTarget);
|
||||
for (auto preBB : curbb->pre_bbs_) {
|
||||
preBB->add_succ_basic_block(JumpTarget);
|
||||
JumpTarget->add_pre_basic_block(preBB);
|
||||
}
|
||||
}
|
||||
deleteUselessBlock(foo, uselessBlock);
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
#ifndef SIMPLIFYJUMPH
|
||||
#define SIMPLIFYJUMPH
|
||||
#include "opt.h"
|
||||
|
||||
class SimplifyJump : public Optimization {
|
||||
|
||||
public:
|
||||
SimplifyJump(Module *m) : Optimization(m) {}
|
||||
void execute();
|
||||
void deleteUselessBlock(Function *foo,
|
||||
std::vector<BasicBlock *> &uselessBlock);
|
||||
bool checkUselessJump(BasicBlock *bb);
|
||||
void deleteUselessPhi(Function *foo);
|
||||
void deleteUselessJump(Function *foo);
|
||||
void mergePreBlock(Function *foo);
|
||||
void deleteUnReachableBlock(Function *foo);
|
||||
};
|
||||
|
||||
#endif // !SIMPLIFYJUMPH
|
@ -0,0 +1,206 @@
|
||||
#include "opt.h"
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
void DomainTree::execute() {
|
||||
for (auto foo : m->function_list_)
|
||||
if (!foo->basic_blocks_.empty()) {
|
||||
getBlockDom(foo);
|
||||
getBlockDomFront(foo);
|
||||
}
|
||||
}
|
||||
|
||||
bool DomainTree::isLoopEdge(BasicBlock *a, BasicBlock *b) {
|
||||
return TraverseInd[a] > TraverseInd[b];
|
||||
}
|
||||
|
||||
std::vector<BasicBlock *> DomainTree::postTraverse(BasicBlock *bb) {
|
||||
std::set<BasicBlock *> vis;
|
||||
std::vector<BasicBlock *> ans;
|
||||
std::function<void(BasicBlock *)> dfs = [&](BasicBlock *place) {
|
||||
vis.insert(place);
|
||||
for (auto child : place->succ_bbs_)
|
||||
if (vis.find(child) == vis.end())
|
||||
dfs(child);
|
||||
ans.push_back(place);
|
||||
};
|
||||
dfs(bb);
|
||||
return ans;
|
||||
}
|
||||
|
||||
void DomainTree::getReversePostTraverse(Function *f) {
|
||||
doms.clear();
|
||||
reversePostTraverse.clear();
|
||||
TraverseInd.clear();
|
||||
auto entryBlock = *f->basic_blocks_.begin();
|
||||
auto seq = postTraverse(entryBlock);
|
||||
std::reverse(reversePostTraverse.begin(), reversePostTraverse.end());
|
||||
for (int i = 0; i < seq.size(); i++)
|
||||
TraverseInd[seq[i]] = i;
|
||||
reversePostTraverse = seq;
|
||||
}
|
||||
|
||||
void DomainTree::getBlockDom(Function *f) {
|
||||
getReversePostTraverse(f);
|
||||
auto root = *f->basic_blocks_.begin();
|
||||
auto root_id = TraverseInd[root];
|
||||
doms.resize(root_id + 1, nullptr);
|
||||
doms.back() = root;
|
||||
bool change = true;
|
||||
while (change) {
|
||||
change = false;
|
||||
for (auto bb : reversePostTraverse)
|
||||
if (bb != root) {
|
||||
auto preds = bb->pre_bbs_;
|
||||
BasicBlock *curDom = nullptr;
|
||||
for (auto pred_bb : preds)
|
||||
if (doms[TraverseInd[pred_bb]] != nullptr) {
|
||||
curDom = pred_bb;
|
||||
break;
|
||||
}
|
||||
for (auto pred_bb : preds)
|
||||
if (doms[TraverseInd[pred_bb]] != nullptr)
|
||||
curDom = intersect(pred_bb, curDom);
|
||||
if (doms[TraverseInd[bb]] != curDom) {
|
||||
doms[TraverseInd[bb]] = curDom;
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto bb : reversePostTraverse)
|
||||
bb->idom_ = doms[TraverseInd[bb]];
|
||||
}
|
||||
|
||||
void DomainTree::getBlockDomFront(Function *foo) {
|
||||
for (auto b : foo->basic_blocks_) {
|
||||
auto b_pred = b->pre_bbs_;
|
||||
if (b_pred.size() >= 2) {
|
||||
for (auto pred : b_pred) {
|
||||
auto runner = pred;
|
||||
while (runner != doms[TraverseInd[b]]) {
|
||||
runner->dom_frontier_.insert(b);
|
||||
runner = doms[TraverseInd[runner]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasicBlock *DomainTree::intersect(BasicBlock *b1, BasicBlock *b2) {
|
||||
auto head1 = b1;
|
||||
auto head2 = b2;
|
||||
while (head1 != head2) {
|
||||
while (TraverseInd[head1] < TraverseInd[head2])
|
||||
head1 = doms[TraverseInd[head1]];
|
||||
while (TraverseInd[head2] < TraverseInd[head1])
|
||||
head2 = doms[TraverseInd[head2]];
|
||||
}
|
||||
return head1;
|
||||
}
|
||||
|
||||
void ReverseDomainTree::execute() {
|
||||
for (auto f : m->function_list_)
|
||||
if (!f->basic_blocks_.empty()) {
|
||||
for (auto bb : f->basic_blocks_) {
|
||||
bb->rdoms_.clear();
|
||||
bb->rdom_frontier_.clear();
|
||||
}
|
||||
getBlockDomR(f);
|
||||
getBlockDomFrontR(f);
|
||||
getBlockRdoms(f);
|
||||
}
|
||||
}
|
||||
|
||||
void ReverseDomainTree::getPostTraverse(BasicBlock *bb,
|
||||
std::set<BasicBlock *> &visited) {
|
||||
visited.insert(bb);
|
||||
for (auto parent : bb->pre_bbs_)
|
||||
if (visited.find(parent) == visited.end())
|
||||
getPostTraverse(parent, visited);
|
||||
reverseTraverseInd[bb] = reverseTraverse.size();
|
||||
reverseTraverse.push_back(bb);
|
||||
}
|
||||
|
||||
void ReverseDomainTree::getReversePostTraverse(Function *f) {
|
||||
reverseDomainBlock.clear();
|
||||
reverseTraverse.clear();
|
||||
reverseTraverseInd.clear();
|
||||
for (auto bb : f->basic_blocks_) {
|
||||
auto terminate_instr = bb->get_terminator();
|
||||
if (terminate_instr->op_id_ == Instruction::Ret) {
|
||||
exitBlock = bb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(exitBlock != nullptr);
|
||||
std::set<BasicBlock *> visited = {};
|
||||
getPostTraverse(exitBlock, visited);
|
||||
reverse(reverseTraverse.begin(), reverseTraverse.end());
|
||||
}
|
||||
|
||||
void ReverseDomainTree::getBlockDomR(Function *f) {
|
||||
getReversePostTraverse(f);
|
||||
auto root = exitBlock;
|
||||
auto root_id = reverseTraverseInd[root];
|
||||
for (int i = 0; i < root_id; i++)
|
||||
reverseDomainBlock.push_back(nullptr);
|
||||
reverseDomainBlock.push_back(root);
|
||||
bool change = true;
|
||||
while (change) {
|
||||
change = false;
|
||||
for (auto bb : reverseTraverse) {
|
||||
if (bb != root) {
|
||||
BasicBlock *new_irdom = nullptr;
|
||||
for (auto rpred_bb : bb->succ_bbs_)
|
||||
if (reverseDomainBlock[reverseTraverseInd[rpred_bb]] != nullptr) {
|
||||
new_irdom = rpred_bb;
|
||||
break;
|
||||
}
|
||||
for (auto rpred_bb : bb->succ_bbs_)
|
||||
if (reverseDomainBlock[reverseTraverseInd[rpred_bb]] != nullptr)
|
||||
new_irdom = intersect(rpred_bb, new_irdom);
|
||||
if (reverseDomainBlock[reverseTraverseInd[bb]] != new_irdom) {
|
||||
reverseDomainBlock[reverseTraverseInd[bb]] = new_irdom;
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void ReverseDomainTree::getBlockRdoms(Function *f) {
|
||||
for (auto bb : f->basic_blocks_) {
|
||||
if (bb == exitBlock)
|
||||
continue;
|
||||
auto current = bb;
|
||||
while (current != exitBlock) {
|
||||
bb->rdoms_.insert(current);
|
||||
current = reverseDomainBlock[reverseTraverseInd[current]];
|
||||
}
|
||||
}
|
||||
}
|
||||
void ReverseDomainTree::getBlockDomFrontR(Function *f) {
|
||||
for (auto bb_iter = f->basic_blocks_.rbegin();
|
||||
bb_iter != f->basic_blocks_.rend(); bb_iter++) {
|
||||
auto bb = *bb_iter;
|
||||
if (bb->succ_bbs_.size() >= 2) {
|
||||
for (auto rpred : bb->succ_bbs_) {
|
||||
auto runner = rpred;
|
||||
while (runner != reverseDomainBlock[reverseTraverseInd[bb]]) {
|
||||
runner->rdom_frontier_.insert(bb);
|
||||
runner = reverseDomainBlock[reverseTraverseInd[runner]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BasicBlock *ReverseDomainTree::intersect(BasicBlock *b1, BasicBlock *b2) {
|
||||
auto head1 = b1;
|
||||
auto head2 = b2;
|
||||
while (head1 != head2) {
|
||||
while (reverseTraverseInd[head1] < reverseTraverseInd[head2])
|
||||
head1 = reverseDomainBlock[reverseTraverseInd[head1]];
|
||||
while (reverseTraverseInd[head2] < reverseTraverseInd[head1])
|
||||
head2 = reverseDomainBlock[reverseTraverseInd[head2]];
|
||||
}
|
||||
return head1;
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
// Currently a dummy file
|
||||
#ifndef OPTH
|
||||
#define OPTH
|
||||
|
||||
#include "ir.h"
|
||||
|
||||
class Optimization {
|
||||
public:
|
||||
Module *m;
|
||||
explicit Optimization(Module *m_) : m(m_) {}
|
||||
virtual void execute() = 0;
|
||||
};
|
||||
|
||||
class DomainTree : public Optimization {
|
||||
std::vector<BasicBlock *> reversePostTraverse;
|
||||
std::map<BasicBlock *, int> TraverseInd;
|
||||
std::vector<BasicBlock *> doms;
|
||||
|
||||
public:
|
||||
DomainTree(Module *m) : Optimization(m) {}
|
||||
void execute();
|
||||
void getReversePostTraverse(Function *foo);
|
||||
std::vector<BasicBlock *> postTraverse(BasicBlock *bb);
|
||||
void getBlockDom(Function *foo);
|
||||
void getBlockDomFront(Function *foo);
|
||||
BasicBlock *intersect(BasicBlock *b1, BasicBlock *b2);
|
||||
bool isLoopEdge(BasicBlock *a, BasicBlock *b);
|
||||
};
|
||||
|
||||
class ReverseDomainTree : public Optimization {
|
||||
std::map<BasicBlock *, int> reverseTraverseInd;
|
||||
std::vector<BasicBlock *> reverseDomainBlock;
|
||||
std::vector<BasicBlock *> reverseTraverse;
|
||||
BasicBlock *exitBlock;
|
||||
|
||||
public:
|
||||
ReverseDomainTree(Module *m) : Optimization(m), exitBlock(nullptr) {}
|
||||
void execute();
|
||||
BasicBlock *intersect(BasicBlock *b1, BasicBlock *b2);
|
||||
void getReversePostTraverse(Function *foo);
|
||||
void getBlockDomR(Function *foo);
|
||||
void getBlockRdoms(Function *foo);
|
||||
void getBlockDomFrontR(Function *foo);
|
||||
void getPostTraverse(BasicBlock *bb, std::set<BasicBlock *> &visited);
|
||||
};
|
||||
#endif // !OPTH
|
@ -0,0 +1,22 @@
|
||||
# Require Flex & Bison as generator
|
||||
# find_package(FLEX 2.5.4 REQUIRED)
|
||||
# find_package(BISON 2.4.1 REQUIRED)
|
||||
|
||||
set(PARSER_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
# set(PARSER_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
set(LEXER_CPP "${PARSER_DIR}/tokens.cpp")
|
||||
set(LEXER_DEF "${PARSER_DIR}/tokens.hpp")
|
||||
set(PARSER_CPP "${PARSER_DIR}/parser.cpp")
|
||||
set(PARSER_DEF "${PARSER_DIR}/parser.hpp")
|
||||
|
||||
# Generate tokenizer & parser via Flex & Bison
|
||||
# flex_target(LEXER "tokens.l" "${LEXER_CPP}" DEFINES_FILE "${LEXER_DEF}")
|
||||
# bison_target(PARSER "parser.y" "${PARSER_CPP}" DEFINES_FILE "${PARSER_DEF}")
|
||||
# add_flex_bison_dependency(LEXER PARSER)
|
||||
|
||||
set(SOURCE_FILES "${LEXER_CPP}" "${PARSER_CPP}" "ast.cpp")
|
||||
set(PARSER_INCLUDE ${PARSER_DIR} ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE)
|
||||
|
||||
add_library(parser STATIC ${SOURCE_FILES})
|
||||
target_include_directories(parser PRIVATE "${PARSER_INCLUDE}")
|
@ -0,0 +1,49 @@
|
||||
#include "ast.h"
|
||||
|
||||
void CompUnitAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void DeclDefAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void DefAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void DeclAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void InitValAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void FuncDefAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void FuncFParamAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void BlockAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void StmtAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void ReturnStmtAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void SelectStmtAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void IterationStmtAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void AddExpAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void MulExpAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void UnaryExpAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void PrimaryExpAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void NumberAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void CallAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void LValAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void RelExpAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void EqExpAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void LAndExpAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void LOrExpAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
||||
|
||||
void BlockItemAST::accept(Visitor &visitor) { visitor.visit(*this); }
|
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
enum STYPE { SEMI, ASS, EXP, CONT, BRE, RET, BLK, SEL, ITER };
|
||||
|
||||
enum UOP { UOP_ADD, UOP_MINUS, UOP_NOT };
|
||||
|
||||
enum AOP { AOP_ADD, AOP_MINUS };
|
||||
|
||||
enum MOP { MOP_MUL, MOP_DIV, MOP_MOD };
|
||||
|
||||
enum ROP { ROP_GTE, ROP_LTE, ROP_GT, ROP_LT };
|
||||
|
||||
enum EOP { EOP_EQ, EOP_NEQ };
|
||||
|
||||
enum TYPE { TYPE_VOID, TYPE_INT, TYPE_FLOAT };
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,170 @@
|
||||
/* A Bison parser, made by GNU Bison 3.8.2. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
|
||||
especially those whose name start with YY_ or yy_. They are
|
||||
private implementation details that can be changed or removed. */
|
||||
|
||||
#ifndef YY_YY_HOME_SEAS0_CODES_COMPILER_CARROTCOMPILER_SRC_PARSER_PARSER_HPP_INCLUDED
|
||||
# define YY_YY_HOME_SEAS0_CODES_COMPILER_CARROTCOMPILER_SRC_PARSER_PARSER_HPP_INCLUDED
|
||||
/* Debug traces. */
|
||||
#ifndef YYDEBUG
|
||||
# define YYDEBUG 0
|
||||
#endif
|
||||
#if YYDEBUG
|
||||
extern int yydebug;
|
||||
#endif
|
||||
|
||||
/* Token kinds. */
|
||||
#ifndef YYTOKENTYPE
|
||||
# define YYTOKENTYPE
|
||||
enum yytokentype
|
||||
{
|
||||
YYEMPTY = -2,
|
||||
YYEOF = 0, /* "end of file" */
|
||||
YYerror = 256, /* error */
|
||||
YYUNDEF = 257, /* "invalid token" */
|
||||
INT = 258, /* INT */
|
||||
FLOAT = 259, /* FLOAT */
|
||||
ID = 260, /* ID */
|
||||
GTE = 261, /* GTE */
|
||||
LTE = 262, /* LTE */
|
||||
GT = 263, /* GT */
|
||||
LT = 264, /* LT */
|
||||
EQ = 265, /* EQ */
|
||||
NEQ = 266, /* NEQ */
|
||||
INTTYPE = 267, /* INTTYPE */
|
||||
FLOATTYPE = 268, /* FLOATTYPE */
|
||||
VOID = 269, /* VOID */
|
||||
CONST = 270, /* CONST */
|
||||
RETURN = 271, /* RETURN */
|
||||
IF = 272, /* IF */
|
||||
ELSE = 273, /* ELSE */
|
||||
WHILE = 274, /* WHILE */
|
||||
BREAK = 275, /* BREAK */
|
||||
CONTINUE = 276, /* CONTINUE */
|
||||
LP = 277, /* LP */
|
||||
RP = 278, /* RP */
|
||||
LB = 279, /* LB */
|
||||
RB = 280, /* RB */
|
||||
LC = 281, /* LC */
|
||||
RC = 282, /* RC */
|
||||
COMMA = 283, /* COMMA */
|
||||
SEMICOLON = 284, /* SEMICOLON */
|
||||
NOT = 285, /* NOT */
|
||||
ASSIGN = 286, /* ASSIGN */
|
||||
MINUS = 287, /* MINUS */
|
||||
ADD = 288, /* ADD */
|
||||
MUL = 289, /* MUL */
|
||||
DIV = 290, /* DIV */
|
||||
MOD = 291, /* MOD */
|
||||
AND = 292, /* AND */
|
||||
OR = 293, /* OR */
|
||||
LOWER_THEN_ELSE = 294 /* LOWER_THEN_ELSE */
|
||||
};
|
||||
typedef enum yytokentype yytoken_kind_t;
|
||||
#endif
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
union YYSTYPE
|
||||
{
|
||||
#line 20 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y"
|
||||
|
||||
CompUnitAST* compUnit;
|
||||
DeclDefAST* declDef;
|
||||
DeclAST* decl;
|
||||
DefListAST* defList;
|
||||
DefAST* def;
|
||||
ArraysAST* arrays;
|
||||
InitValListAST* initValList;
|
||||
InitValAST* initVal;
|
||||
FuncDefAST* funcDef;
|
||||
FuncFParamListAST* FuncFParamList;
|
||||
FuncFParamAST* funcFParam;
|
||||
BlockAST* block;
|
||||
BlockItemListAST* blockItemList;
|
||||
BlockItemAST* blockItem;
|
||||
StmtAST* stmt;
|
||||
ReturnStmtAST* returnStmt;
|
||||
SelectStmtAST* selectStmt;
|
||||
IterationStmtAST* iterationStmt;
|
||||
LValAST* lVal;
|
||||
PrimaryExpAST* primaryExp;
|
||||
NumberAST* number;
|
||||
UnaryExpAST* unaryExp;
|
||||
CallAST* call;
|
||||
FuncCParamListAST* funcCParamList;
|
||||
MulExpAST* mulExp;
|
||||
AddExpAST* addExp;
|
||||
RelExpAST* relExp;
|
||||
EqExpAST* eqExp;
|
||||
LAndExpAST* lAndExp;
|
||||
LOrExpAST* lOrExp;
|
||||
|
||||
TYPE ty;
|
||||
UOP op;
|
||||
string* token;
|
||||
int int_val;
|
||||
float float_val;
|
||||
|
||||
#line 142 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.hpp"
|
||||
|
||||
};
|
||||
typedef union YYSTYPE YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
/* Location type. */
|
||||
#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
|
||||
typedef struct YYLTYPE YYLTYPE;
|
||||
struct YYLTYPE
|
||||
{
|
||||
int first_line;
|
||||
int first_column;
|
||||
int last_line;
|
||||
int last_column;
|
||||
};
|
||||
# define YYLTYPE_IS_DECLARED 1
|
||||
# define YYLTYPE_IS_TRIVIAL 1
|
||||
#endif
|
||||
|
||||
|
||||
extern YYSTYPE yylval;
|
||||
extern YYLTYPE yylloc;
|
||||
|
||||
int yyparse (void);
|
||||
|
||||
|
||||
#endif /* !YY_YY_HOME_SEAS0_CODES_COMPILER_CARROTCOMPILER_SRC_PARSER_PARSER_HPP_INCLUDED */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,477 @@
|
||||
#ifndef yyHEADER_H
|
||||
#define yyHEADER_H 1
|
||||
#define yyIN_HEADER 1
|
||||
|
||||
#line 5 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.hpp"
|
||||
|
||||
#line 7 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.hpp"
|
||||
|
||||
#define YY_INT_ALIGNED short int
|
||||
|
||||
/* A lexical scanner generated by flex */
|
||||
|
||||
#define FLEX_SCANNER
|
||||
#define YY_FLEX_MAJOR_VERSION 2
|
||||
#define YY_FLEX_MINOR_VERSION 6
|
||||
#define YY_FLEX_SUBMINOR_VERSION 4
|
||||
#if YY_FLEX_SUBMINOR_VERSION > 0
|
||||
#define FLEX_BETA
|
||||
#endif
|
||||
|
||||
/* First, we deal with platform-specific or compiler-specific issues. */
|
||||
|
||||
/* begin standard C headers. */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* end standard C headers. */
|
||||
|
||||
/* flex integer type definitions */
|
||||
|
||||
#ifndef FLEXINT_H
|
||||
#define FLEXINT_H
|
||||
|
||||
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
|
||||
|
||||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
|
||||
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
|
||||
* if you want the limit (max/min) macros for int types.
|
||||
*/
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
#define __STDC_LIMIT_MACROS 1
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
typedef int8_t flex_int8_t;
|
||||
typedef uint8_t flex_uint8_t;
|
||||
typedef int16_t flex_int16_t;
|
||||
typedef uint16_t flex_uint16_t;
|
||||
typedef int32_t flex_int32_t;
|
||||
typedef uint32_t flex_uint32_t;
|
||||
#else
|
||||
typedef signed char flex_int8_t;
|
||||
typedef short int flex_int16_t;
|
||||
typedef int flex_int32_t;
|
||||
typedef unsigned char flex_uint8_t;
|
||||
typedef unsigned short int flex_uint16_t;
|
||||
typedef unsigned int flex_uint32_t;
|
||||
|
||||
/* Limits of integral types. */
|
||||
#ifndef INT8_MIN
|
||||
#define INT8_MIN (-128)
|
||||
#endif
|
||||
#ifndef INT16_MIN
|
||||
#define INT16_MIN (-32767-1)
|
||||
#endif
|
||||
#ifndef INT32_MIN
|
||||
#define INT32_MIN (-2147483647-1)
|
||||
#endif
|
||||
#ifndef INT8_MAX
|
||||
#define INT8_MAX (127)
|
||||
#endif
|
||||
#ifndef INT16_MAX
|
||||
#define INT16_MAX (32767)
|
||||
#endif
|
||||
#ifndef INT32_MAX
|
||||
#define INT32_MAX (2147483647)
|
||||
#endif
|
||||
#ifndef UINT8_MAX
|
||||
#define UINT8_MAX (255U)
|
||||
#endif
|
||||
#ifndef UINT16_MAX
|
||||
#define UINT16_MAX (65535U)
|
||||
#endif
|
||||
#ifndef UINT32_MAX
|
||||
#define UINT32_MAX (4294967295U)
|
||||
#endif
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX (~(size_t)0)
|
||||
#endif
|
||||
|
||||
#endif /* ! C99 */
|
||||
|
||||
#endif /* ! FLEXINT_H */
|
||||
|
||||
/* begin standard C++ headers. */
|
||||
|
||||
/* TODO: this is always defined, so inline it */
|
||||
#define yyconst const
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||
#define yynoreturn __attribute__((__noreturn__))
|
||||
#else
|
||||
#define yynoreturn
|
||||
#endif
|
||||
|
||||
/* Size of default input buffer. */
|
||||
#ifndef YY_BUF_SIZE
|
||||
#ifdef __ia64__
|
||||
/* On IA-64, the buffer size is 16k, not 8k.
|
||||
* Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
|
||||
* Ditto for the __ia64__ case accordingly.
|
||||
*/
|
||||
#define YY_BUF_SIZE 32768
|
||||
#else
|
||||
#define YY_BUF_SIZE 16384
|
||||
#endif /* __ia64__ */
|
||||
#endif
|
||||
|
||||
#ifndef YY_TYPEDEF_YY_BUFFER_STATE
|
||||
#define YY_TYPEDEF_YY_BUFFER_STATE
|
||||
typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
||||
#endif
|
||||
|
||||
#ifndef YY_TYPEDEF_YY_SIZE_T
|
||||
#define YY_TYPEDEF_YY_SIZE_T
|
||||
typedef size_t yy_size_t;
|
||||
#endif
|
||||
|
||||
extern int yyleng;
|
||||
|
||||
extern FILE *yyin, *yyout;
|
||||
|
||||
#ifndef YY_STRUCT_YY_BUFFER_STATE
|
||||
#define YY_STRUCT_YY_BUFFER_STATE
|
||||
struct yy_buffer_state
|
||||
{
|
||||
FILE *yy_input_file;
|
||||
|
||||
char *yy_ch_buf; /* input buffer */
|
||||
char *yy_buf_pos; /* current position in input buffer */
|
||||
|
||||
/* Size of input buffer in bytes, not including room for EOB
|
||||
* characters.
|
||||
*/
|
||||
int yy_buf_size;
|
||||
|
||||
/* Number of characters read into yy_ch_buf, not including EOB
|
||||
* characters.
|
||||
*/
|
||||
int yy_n_chars;
|
||||
|
||||
/* Whether we "own" the buffer - i.e., we know we created it,
|
||||
* and can realloc() it to grow it, and should free() it to
|
||||
* delete it.
|
||||
*/
|
||||
int yy_is_our_buffer;
|
||||
|
||||
/* Whether this is an "interactive" input source; if so, and
|
||||
* if we're using stdio for input, then we want to use getc()
|
||||
* instead of fread(), to make sure we stop fetching input after
|
||||
* each newline.
|
||||
*/
|
||||
int yy_is_interactive;
|
||||
|
||||
/* Whether we're considered to be at the beginning of a line.
|
||||
* If so, '^' rules will be active on the next match, otherwise
|
||||
* not.
|
||||
*/
|
||||
int yy_at_bol;
|
||||
|
||||
int yy_bs_lineno; /**< The line count. */
|
||||
int yy_bs_column; /**< The column count. */
|
||||
|
||||
/* Whether to try to fill the input buffer when we reach the
|
||||
* end of it.
|
||||
*/
|
||||
int yy_fill_buffer;
|
||||
|
||||
int yy_buffer_status;
|
||||
|
||||
};
|
||||
#endif /* !YY_STRUCT_YY_BUFFER_STATE */
|
||||
|
||||
void yyrestart ( FILE *input_file );
|
||||
void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer );
|
||||
YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size );
|
||||
void yy_delete_buffer ( YY_BUFFER_STATE b );
|
||||
void yy_flush_buffer ( YY_BUFFER_STATE b );
|
||||
void yypush_buffer_state ( YY_BUFFER_STATE new_buffer );
|
||||
void yypop_buffer_state ( void );
|
||||
|
||||
YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size );
|
||||
YY_BUFFER_STATE yy_scan_string ( const char *yy_str );
|
||||
YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len );
|
||||
|
||||
void *yyalloc ( yy_size_t );
|
||||
void *yyrealloc ( void *, yy_size_t );
|
||||
void yyfree ( void * );
|
||||
|
||||
/* Begin user sect3 */
|
||||
|
||||
#define yywrap() (/*CONSTCOND*/1)
|
||||
#define YY_SKIP_YYWRAP
|
||||
|
||||
extern int yylineno;
|
||||
|
||||
extern char *yytext;
|
||||
#ifdef yytext_ptr
|
||||
#undef yytext_ptr
|
||||
#endif
|
||||
#define yytext_ptr yytext
|
||||
|
||||
#ifdef YY_HEADER_EXPORT_START_CONDITIONS
|
||||
#define INITIAL 0
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef YY_NO_UNISTD_H
|
||||
/* Special case for "unistd.h", since it is non-ANSI. We include it way
|
||||
* down here because we want the user's section 1 to have been scanned first.
|
||||
* The user has a chance to override it with an option.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef YY_EXTRA_TYPE
|
||||
#define YY_EXTRA_TYPE void *
|
||||
#endif
|
||||
|
||||
/* Accessor methods to globals.
|
||||
These are made visible to non-reentrant scanners for convenience. */
|
||||
|
||||
int yylex_destroy ( void );
|
||||
|
||||
int yyget_debug ( void );
|
||||
|
||||
void yyset_debug ( int debug_flag );
|
||||
|
||||
YY_EXTRA_TYPE yyget_extra ( void );
|
||||
|
||||
void yyset_extra ( YY_EXTRA_TYPE user_defined );
|
||||
|
||||
FILE *yyget_in ( void );
|
||||
|
||||
void yyset_in ( FILE * _in_str );
|
||||
|
||||
FILE *yyget_out ( void );
|
||||
|
||||
void yyset_out ( FILE * _out_str );
|
||||
|
||||
int yyget_leng ( void );
|
||||
|
||||
char *yyget_text ( void );
|
||||
|
||||
int yyget_lineno ( void );
|
||||
|
||||
void yyset_lineno ( int _line_number );
|
||||
|
||||
/* Macros after this point can all be overridden by user definitions in
|
||||
* section 1.
|
||||
*/
|
||||
|
||||
#ifndef YY_SKIP_YYWRAP
|
||||
#ifdef __cplusplus
|
||||
extern "C" int yywrap ( void );
|
||||
#else
|
||||
extern int yywrap ( void );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef yytext_ptr
|
||||
static void yy_flex_strncpy ( char *, const char *, int );
|
||||
#endif
|
||||
|
||||
#ifdef YY_NEED_STRLEN
|
||||
static int yy_flex_strlen ( const char * );
|
||||
#endif
|
||||
|
||||
#ifndef YY_NO_INPUT
|
||||
|
||||
#endif
|
||||
|
||||
/* Amount of stuff to slurp up with each read. */
|
||||
#ifndef YY_READ_BUF_SIZE
|
||||
#ifdef __ia64__
|
||||
/* On IA-64, the buffer size is 16k, not 8k */
|
||||
#define YY_READ_BUF_SIZE 16384
|
||||
#else
|
||||
#define YY_READ_BUF_SIZE 8192
|
||||
#endif /* __ia64__ */
|
||||
#endif
|
||||
|
||||
/* Number of entries by which start-condition stack grows. */
|
||||
#ifndef YY_START_STACK_INCR
|
||||
#define YY_START_STACK_INCR 25
|
||||
#endif
|
||||
|
||||
/* Default declaration of generated scanner - a define so the user can
|
||||
* easily add parameters.
|
||||
*/
|
||||
#ifndef YY_DECL
|
||||
#define YY_DECL_IS_OURS 1
|
||||
|
||||
extern int yylex (void);
|
||||
|
||||
#define YY_DECL int yylex (void)
|
||||
#endif /* !YY_DECL */
|
||||
|
||||
/* yy_get_previous_state - get the state just before the EOB char was reached */
|
||||
|
||||
#undef YY_NEW_FILE
|
||||
#undef YY_FLUSH_BUFFER
|
||||
#undef yy_set_bol
|
||||
#undef yy_new_buffer
|
||||
#undef yy_set_interactive
|
||||
#undef YY_DO_BEFORE_ACTION
|
||||
|
||||
#ifdef YY_DECL_IS_OURS
|
||||
#undef YY_DECL_IS_OURS
|
||||
#undef YY_DECL
|
||||
#endif
|
||||
|
||||
#ifndef yy_create_buffer_ALREADY_DEFINED
|
||||
#undef yy_create_buffer
|
||||
#endif
|
||||
#ifndef yy_delete_buffer_ALREADY_DEFINED
|
||||
#undef yy_delete_buffer
|
||||
#endif
|
||||
#ifndef yy_scan_buffer_ALREADY_DEFINED
|
||||
#undef yy_scan_buffer
|
||||
#endif
|
||||
#ifndef yy_scan_string_ALREADY_DEFINED
|
||||
#undef yy_scan_string
|
||||
#endif
|
||||
#ifndef yy_scan_bytes_ALREADY_DEFINED
|
||||
#undef yy_scan_bytes
|
||||
#endif
|
||||
#ifndef yy_init_buffer_ALREADY_DEFINED
|
||||
#undef yy_init_buffer
|
||||
#endif
|
||||
#ifndef yy_flush_buffer_ALREADY_DEFINED
|
||||
#undef yy_flush_buffer
|
||||
#endif
|
||||
#ifndef yy_load_buffer_state_ALREADY_DEFINED
|
||||
#undef yy_load_buffer_state
|
||||
#endif
|
||||
#ifndef yy_switch_to_buffer_ALREADY_DEFINED
|
||||
#undef yy_switch_to_buffer
|
||||
#endif
|
||||
#ifndef yypush_buffer_state_ALREADY_DEFINED
|
||||
#undef yypush_buffer_state
|
||||
#endif
|
||||
#ifndef yypop_buffer_state_ALREADY_DEFINED
|
||||
#undef yypop_buffer_state
|
||||
#endif
|
||||
#ifndef yyensure_buffer_stack_ALREADY_DEFINED
|
||||
#undef yyensure_buffer_stack
|
||||
#endif
|
||||
#ifndef yylex_ALREADY_DEFINED
|
||||
#undef yylex
|
||||
#endif
|
||||
#ifndef yyrestart_ALREADY_DEFINED
|
||||
#undef yyrestart
|
||||
#endif
|
||||
#ifndef yylex_init_ALREADY_DEFINED
|
||||
#undef yylex_init
|
||||
#endif
|
||||
#ifndef yylex_init_extra_ALREADY_DEFINED
|
||||
#undef yylex_init_extra
|
||||
#endif
|
||||
#ifndef yylex_destroy_ALREADY_DEFINED
|
||||
#undef yylex_destroy
|
||||
#endif
|
||||
#ifndef yyget_debug_ALREADY_DEFINED
|
||||
#undef yyget_debug
|
||||
#endif
|
||||
#ifndef yyset_debug_ALREADY_DEFINED
|
||||
#undef yyset_debug
|
||||
#endif
|
||||
#ifndef yyget_extra_ALREADY_DEFINED
|
||||
#undef yyget_extra
|
||||
#endif
|
||||
#ifndef yyset_extra_ALREADY_DEFINED
|
||||
#undef yyset_extra
|
||||
#endif
|
||||
#ifndef yyget_in_ALREADY_DEFINED
|
||||
#undef yyget_in
|
||||
#endif
|
||||
#ifndef yyset_in_ALREADY_DEFINED
|
||||
#undef yyset_in
|
||||
#endif
|
||||
#ifndef yyget_out_ALREADY_DEFINED
|
||||
#undef yyget_out
|
||||
#endif
|
||||
#ifndef yyset_out_ALREADY_DEFINED
|
||||
#undef yyset_out
|
||||
#endif
|
||||
#ifndef yyget_leng_ALREADY_DEFINED
|
||||
#undef yyget_leng
|
||||
#endif
|
||||
#ifndef yyget_text_ALREADY_DEFINED
|
||||
#undef yyget_text
|
||||
#endif
|
||||
#ifndef yyget_lineno_ALREADY_DEFINED
|
||||
#undef yyget_lineno
|
||||
#endif
|
||||
#ifndef yyset_lineno_ALREADY_DEFINED
|
||||
#undef yyset_lineno
|
||||
#endif
|
||||
#ifndef yyget_column_ALREADY_DEFINED
|
||||
#undef yyget_column
|
||||
#endif
|
||||
#ifndef yyset_column_ALREADY_DEFINED
|
||||
#undef yyset_column
|
||||
#endif
|
||||
#ifndef yywrap_ALREADY_DEFINED
|
||||
#undef yywrap
|
||||
#endif
|
||||
#ifndef yyget_lval_ALREADY_DEFINED
|
||||
#undef yyget_lval
|
||||
#endif
|
||||
#ifndef yyset_lval_ALREADY_DEFINED
|
||||
#undef yyset_lval
|
||||
#endif
|
||||
#ifndef yyget_lloc_ALREADY_DEFINED
|
||||
#undef yyget_lloc
|
||||
#endif
|
||||
#ifndef yyset_lloc_ALREADY_DEFINED
|
||||
#undef yyset_lloc
|
||||
#endif
|
||||
#ifndef yyalloc_ALREADY_DEFINED
|
||||
#undef yyalloc
|
||||
#endif
|
||||
#ifndef yyrealloc_ALREADY_DEFINED
|
||||
#undef yyrealloc
|
||||
#endif
|
||||
#ifndef yyfree_ALREADY_DEFINED
|
||||
#undef yyfree
|
||||
#endif
|
||||
#ifndef yytext_ALREADY_DEFINED
|
||||
#undef yytext
|
||||
#endif
|
||||
#ifndef yyleng_ALREADY_DEFINED
|
||||
#undef yyleng
|
||||
#endif
|
||||
#ifndef yyin_ALREADY_DEFINED
|
||||
#undef yyin
|
||||
#endif
|
||||
#ifndef yyout_ALREADY_DEFINED
|
||||
#undef yyout
|
||||
#endif
|
||||
#ifndef yy_flex_debug_ALREADY_DEFINED
|
||||
#undef yy_flex_debug
|
||||
#endif
|
||||
#ifndef yylineno_ALREADY_DEFINED
|
||||
#undef yylineno
|
||||
#endif
|
||||
#ifndef yytables_fload_ALREADY_DEFINED
|
||||
#undef yytables_fload
|
||||
#endif
|
||||
#ifndef yytables_destroy_ALREADY_DEFINED
|
||||
#undef yytables_destroy
|
||||
#endif
|
||||
#ifndef yyTABLES_NAME_ALREADY_DEFINED
|
||||
#undef yyTABLES_NAME
|
||||
#endif
|
||||
|
||||
#line 95 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l"
|
||||
|
||||
|
||||
#line 475 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.hpp"
|
||||
#undef yyIN_HEADER
|
||||
#endif /* yyHEADER_H */
|
@ -0,0 +1,95 @@
|
||||
%option noyywrap
|
||||
|
||||
%{
|
||||
#include <string>
|
||||
#include "ast.h"
|
||||
#include "parser.hpp"
|
||||
//extern "C" int yywrap() {}
|
||||
int yycolumn=1;
|
||||
#define YY_USER_ACTION yylloc.first_line=yylloc.last_line=yylineno; \
|
||||
yylloc.first_column=yycolumn; yylloc.last_column=yycolumn+yyleng-1; yycolumn+=yyleng;
|
||||
%}
|
||||
|
||||
%option yylineno
|
||||
|
||||
ID [a-z_A-Z][a-z_A-Z0-9]*
|
||||
|
||||
INT_LIT ([1-9][0-9]*|0[0-7]*|(0x|0X)[0-9a-fA-F]+)
|
||||
|
||||
/* TODO: Float rules is direct copied from C
|
||||
* maybe shrinking down is needed?
|
||||
*/
|
||||
FLOAT_SUFFIX [fFlL]
|
||||
|
||||
DEC_EXP ([Ee][-+]?[0-9]+)
|
||||
DEC_FLOAT_LIT_HAVE_POINT_HAVE_RIGHT ([0-9]*\.[0-9]+{DEC_EXP}?{FLOAT_SUFFIX}?)
|
||||
DEC_FLOAT_LIT_HAVE_POINT_NO_RIGHT ([0-9]+\.{DEC_EXP}?{FLOAT_SUFFIX}?)
|
||||
DEC_FLOAT_LIT_NO_POINT ([0-9]+{DEC_EXP}{FLOAT_SUFFIX}?)
|
||||
DEC_FLOAT_LIT ({DEC_FLOAT_LIT_HAVE_POINT_HAVE_RIGHT}|{DEC_FLOAT_LIT_HAVE_POINT_NO_RIGHT}|{DEC_FLOAT_LIT_NO_POINT})
|
||||
|
||||
HEX_EXP ([Pp][-+]?[0-9]+)
|
||||
HEX_FLOAT_LIT_HAVE_POINT_HAVE_RIGHT ((0[xX])[a-fA-F0-9]*\.[a-fA-F0-9]+{HEX_EXP}{FLOAT_SUFFIX}?)
|
||||
HEX_FLOAT_LIT_HAVE_POINT_NO_RIGHT ((0[xX])[a-fA-F0-9]+\.{HEX_EXP}{FLOAT_SUFFIX}?)
|
||||
HEX_FLOAT_LIT_NO_POINT ((0[xX])[a-fA-F0-9]+{HEX_EXP}{FLOAT_SUFFIX}?)
|
||||
HEX_FLOAT_LIT ({HEX_FLOAT_LIT_HAVE_POINT_HAVE_RIGHT}|{HEX_FLOAT_LIT_HAVE_POINT_NO_RIGHT}|{HEX_FLOAT_LIT_NO_POINT})
|
||||
|
||||
FLOAT_LIT ({DEC_FLOAT_LIT}|{HEX_FLOAT_LIT})
|
||||
/* EXP ([Ee][-+]?[0-9]+) */
|
||||
/* FLOAT (([0-9]*\.[0-9]+|[0-9]+\.){EXP}?[fF]?)|[0-9]+{EXP}[fF]? */
|
||||
|
||||
SingleLineComment "//".*
|
||||
MultilineComment "/*"([^\*]|(\*)*[^\*/])*(\*)*"*/"
|
||||
|
||||
/* Invalid ([0-9]+[A-Za-z]+[0-9]*|0[0-9]*[8-9]+[0-9]*) */
|
||||
%%
|
||||
|
||||
{INT_LIT} {yylval.int_val = strtol(yytext, nullptr, 0); return INT;}
|
||||
{FLOAT_LIT} {yylval.float_val = strtof(yytext, nullptr); return FLOAT;}
|
||||
|
||||
"int" {return INTTYPE;}
|
||||
"float" {return FLOATTYPE;}
|
||||
"void" {return VOID;}
|
||||
"const" {return CONST;}
|
||||
"return" {return RETURN;}
|
||||
"if" {return IF;}
|
||||
"else" {return ELSE;}
|
||||
"while" {return WHILE;}
|
||||
"break" {return BREAK;}
|
||||
"continue" {return CONTINUE;}
|
||||
|
||||
{ID} {yylval.token = new string(yytext); return ID;}
|
||||
|
||||
">=" {return GTE;}
|
||||
"<=" {return LTE;}
|
||||
">" {return GT;}
|
||||
"<" {return LT;}
|
||||
"==" {return EQ;}
|
||||
"!=" {return NEQ;}
|
||||
|
||||
"(" {return LP;}
|
||||
")" {return RP;}
|
||||
"[" {return LB;}
|
||||
"]" {return RB;}
|
||||
"{" {return LC;}
|
||||
"}" {return RC;}
|
||||
"," {return COMMA;}
|
||||
";" {return SEMICOLON;}
|
||||
|
||||
"!" {return NOT;}
|
||||
"=" {return ASSIGN;}
|
||||
"-" {return MINUS;}
|
||||
"+" {return ADD;}
|
||||
"*" {return MUL;}
|
||||
"/" {return DIV;}
|
||||
"%" {return MOD;}
|
||||
"&&" {return AND;}
|
||||
"||" {return OR;}
|
||||
|
||||
[\n] {yycolumn=1;}
|
||||
[ \r\t] {/* Ignore useless whitespaces */}
|
||||
|
||||
{SingleLineComment} {/* Ignore Comments */}
|
||||
{MultilineComment} {/* Ignore Comments */}
|
||||
|
||||
. {printf("Error type A :Mysterious character \"%s\"\n\t at Line %d\n", yytext, yylineno);}
|
||||
%%
|
@ -0,0 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
|
||||
set(SOURCE_FILES "riscv.cpp" instruction.cpp optimize.cpp backend.cpp regalloc.cpp)
|
||||
|
||||
add_library(riscv STATIC ${SOURCE_FILES})
|
||||
|
||||
target_link_libraries(riscv PRIVATE ir)
|
||||
target_include_directories(riscv PRIVATE ${CMAKE_SOURCE_DIR}/src/ir)
|
@ -0,0 +1,3 @@
|
||||
#include "optimize.h"
|
||||
|
||||
void OptimizeBlock() {}
|
@ -0,0 +1,11 @@
|
||||
#ifndef OPTIMIZEH
|
||||
#define OPTIMIZEH
|
||||
|
||||
#include "riscv.h"
|
||||
#include "ir.h"
|
||||
|
||||
// 进行数据流的优化
|
||||
// 在此之前先分配各寄存器
|
||||
// 可选
|
||||
void OptimizeBlock();
|
||||
#endif // !OPTIMIZEH
|
@ -0,0 +1,380 @@
|
||||
#include "regalloc.h"
|
||||
#include "instruction.h"
|
||||
#include "riscv.h"
|
||||
|
||||
int IntRegID = 32, FloatRegID = 32; // 测试阶段使用
|
||||
|
||||
Register *NamefindReg(std::string reg) {
|
||||
if (reg.size() > 4)
|
||||
return nullptr;
|
||||
|
||||
Register *reg_to_ret = new Register(Register::Int, 0);
|
||||
|
||||
// Check if int registers
|
||||
for (int i = 0; i < 32; i++) {
|
||||
reg_to_ret->rid_ = i;
|
||||
if (reg_to_ret->print() == reg)
|
||||
return reg_to_ret;
|
||||
}
|
||||
|
||||
// Else then float registers
|
||||
reg_to_ret->regtype_ = reg_to_ret->Float;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
reg_to_ret->rid_ = i;
|
||||
if (reg_to_ret->print() == reg)
|
||||
return reg_to_ret;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RiscvOperand *getRegOperand(std::string reg) {
|
||||
for (auto regope : regPool) {
|
||||
if (regope->print() == reg)
|
||||
return regope;
|
||||
}
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RiscvOperand *getRegOperand(Register::RegType op_ty_, int id) {
|
||||
Register *reg = new Register(op_ty_, id);
|
||||
for (auto regope : regPool) {
|
||||
if (regope->print() == reg->print()) {
|
||||
delete reg;
|
||||
return regope;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Type *getStoreTypeFromRegType(RiscvOperand *riscvReg) {
|
||||
return riscvReg->getType() == RiscvOperand::OpTy::FloatReg
|
||||
? new Type(Type::TypeID::FloatTyID)
|
||||
: new Type(Type::TypeID::IntegerTyID);
|
||||
}
|
||||
|
||||
RiscvOperand *RegAlloca::findReg(Value *val, RiscvBasicBlock *bb,
|
||||
RiscvInstr *instr, int inReg, int load,
|
||||
RiscvOperand *specified, bool direct) {
|
||||
safeFindTimeStamp++;
|
||||
val = this->DSU_for_Variable.query(val);
|
||||
bool isGVar = dynamic_cast<GlobalVariable *>(val) != nullptr;
|
||||
bool isAlloca = dynamic_cast<AllocaInst *>(val) != nullptr;
|
||||
bool isPointer = val->type_->tid_ == val->type_->PointerTyID;
|
||||
|
||||
// If there is no register allocated for value then get a new one
|
||||
if (specified != nullptr)
|
||||
setPositionReg(val, specified, bb, instr);
|
||||
else if (curReg.find(val) == curReg.end() || isAlloca ||
|
||||
val->is_constant()) { // Alloca and constant value is always unsafe.
|
||||
bool found = false;
|
||||
RiscvOperand *cur = nullptr;
|
||||
IntRegID = 32;
|
||||
FloatRegID = 32;
|
||||
while (!found) {
|
||||
if (val->type_->tid_ != Type::FloatTyID) {
|
||||
++IntRegID;
|
||||
if (IntRegID > 27)
|
||||
IntRegID = 18;
|
||||
|
||||
cur = getRegOperand(Register::Int, IntRegID);
|
||||
} else {
|
||||
++FloatRegID;
|
||||
if (FloatRegID > 27)
|
||||
FloatRegID = 18;
|
||||
cur = getRegOperand(Register::Float, FloatRegID);
|
||||
}
|
||||
if (regFindTimeStamp.find(cur) == regFindTimeStamp.end() ||
|
||||
safeFindTimeStamp - regFindTimeStamp[cur] > SAFE_FIND_LIMIT) {
|
||||
setPositionReg(val, cur, bb, instr);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
regFindTimeStamp[curReg[val]] = safeFindTimeStamp;
|
||||
return curReg[val];
|
||||
}
|
||||
|
||||
// ! Though all registers are considered unsafe, there is no way
|
||||
// ! to writeback registers properly in findReg() for now.
|
||||
// ! Therefore unsafe part below is not being executed for now.
|
||||
// ! Maybe should consider using writeback() instead.
|
||||
// For now, all registers are considered unsafe thus registers should always
|
||||
// load from memory before using and save to memory after using.
|
||||
auto mem_addr = findMem(val, bb, instr, 1); // Value's direct memory address
|
||||
auto current_reg = curReg[val]; // Value's current register
|
||||
auto load_type = val->type_;
|
||||
|
||||
regFindTimeStamp[current_reg] = safeFindTimeStamp; // Update time stamp
|
||||
if (load) {
|
||||
// Load before usage.
|
||||
if (mem_addr != nullptr) {
|
||||
bb->addInstrBefore(
|
||||
new LoadRiscvInst(load_type, current_reg, mem_addr, bb), instr);
|
||||
} else if (val->is_constant()) {
|
||||
// If value is a int constant, create a LI instruction.
|
||||
auto cval = dynamic_cast<ConstantInt *>(val);
|
||||
if (cval != nullptr)
|
||||
bb->addInstrBefore(new MoveRiscvInst(current_reg, cval->value_, bb),
|
||||
instr);
|
||||
else if (dynamic_cast<ConstantFloat *>(val) != nullptr)
|
||||
bb->addInstrBefore(
|
||||
new MoveRiscvInst(current_reg, this->findMem(val), bb), instr);
|
||||
else {
|
||||
std::cerr << "[Warning] Trying to find a register for unknown type of "
|
||||
"constant value which is not implemented for now."
|
||||
<< std::endl;
|
||||
}
|
||||
} else if (isAlloca) {
|
||||
bb->addInstrBefore(
|
||||
new BinaryRiscvInst(
|
||||
BinaryRiscvInst::ADDI, getRegOperand("fp"),
|
||||
new RiscvConst(static_cast<RiscvIntPhiReg *>(pos[val])->shift_),
|
||||
current_reg, bb),
|
||||
instr);
|
||||
// std::cerr << "[Debug] Get a alloca position <" << val->print() << ", "
|
||||
// << static_cast<RiscvIntPhiReg *>(pos[val])->print()
|
||||
// << "> into the register <" << current_reg->print() << ">"
|
||||
// << std::endl;
|
||||
} else {
|
||||
std::cerr << "[Error] Unknown error in findReg()." << std::endl;
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
return current_reg;
|
||||
}
|
||||
|
||||
RiscvOperand *RegAlloca::findMem(Value *val, RiscvBasicBlock *bb,
|
||||
RiscvInstr *instr, bool direct) {
|
||||
val = this->DSU_for_Variable.query(val);
|
||||
if (pos.count(val) == 0 && !val->is_constant()) {
|
||||
std::cerr << "[Warning] Value " << std::hex << val << " (" << val->name_
|
||||
<< ")'s memory map not found." << std::endl;
|
||||
}
|
||||
bool isGVar = dynamic_cast<GlobalVariable *>(val) != nullptr;
|
||||
bool isPointer = val->type_->tid_ == val->type_->PointerTyID;
|
||||
bool isAlloca = dynamic_cast<AllocaInst *>(val) != nullptr;
|
||||
// All float constant considered as global variables for now.
|
||||
isGVar = isGVar || dynamic_cast<ConstantFloat *>(val) != nullptr;
|
||||
// Always loading global variable's address into t5 when execute findMem().
|
||||
if (isGVar) {
|
||||
if (bb == nullptr) {
|
||||
std::cerr << "[Warning] Trying to add global var addressing "
|
||||
"instruction, but basic block pointer is null."
|
||||
<< std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
bb->addInstrBefore(
|
||||
new LoadAddressRiscvInstr(getRegOperand("t5"), pos[val]->print(), bb),
|
||||
instr);
|
||||
return new RiscvIntPhiReg("t5");
|
||||
}
|
||||
// If not loading pointer's address directly, then use indirect addressing.
|
||||
// Ignore alloca due to the instruction only being dealt by findReg()
|
||||
if (isPointer && !isAlloca && !direct) {
|
||||
if (bb == nullptr) {
|
||||
std::cerr << "[Warning] Trying to add indirect pointer addressing "
|
||||
"instruction, but basic block pointer is null."
|
||||
<< std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bb->addInstrBefore(new LoadRiscvInst(new Type(Type::PointerTyID),
|
||||
getRegOperand("t4"), pos[val], bb),
|
||||
instr);
|
||||
return new RiscvIntPhiReg("t4");
|
||||
}
|
||||
// Cannot access to alloca's memory directly.
|
||||
else if (direct && isAlloca)
|
||||
return nullptr;
|
||||
|
||||
if (pos.find(val) == pos.end())
|
||||
return nullptr;
|
||||
|
||||
return pos[val];
|
||||
}
|
||||
|
||||
RiscvOperand *RegAlloca::findMem(Value *val) {
|
||||
return findMem(val, nullptr, nullptr, true);
|
||||
}
|
||||
|
||||
RiscvOperand *RegAlloca::findNonuse(Type *ty, RiscvBasicBlock *bb,
|
||||
RiscvInstr *instr) {
|
||||
if (ty->tid_ == Type::IntegerTyID || ty->tid_ == Type::PointerTyID) {
|
||||
++IntRegID;
|
||||
if (IntRegID > 27)
|
||||
IntRegID = 18;
|
||||
return getRegOperand(Register::Int, IntRegID);
|
||||
} else {
|
||||
++FloatRegID;
|
||||
if (FloatRegID > 27)
|
||||
FloatRegID = 18;
|
||||
return getRegOperand(Register::Float, FloatRegID);
|
||||
}
|
||||
}
|
||||
|
||||
void RegAlloca::setPosition(Value *val, RiscvOperand *riscvVal) {
|
||||
val = this->DSU_for_Variable.query(val);
|
||||
if (pos.find(val) != pos.end()) {
|
||||
// std::cerr << "[Warning] Trying overwriting memory address map of value "
|
||||
// << std::hex << val << " (" << val->name_ << ") ["
|
||||
// << riscvVal->print() << " -> " << pos[val]->print() << "]"
|
||||
// << std::endl;
|
||||
// std::terminate();
|
||||
}
|
||||
|
||||
// std::cerr << "[Debug] [RegAlloca] Map value <" << val->print()
|
||||
// << "> to operand <" << riscvVal->print() << ">" << std::endl;
|
||||
|
||||
pos[val] = riscvVal;
|
||||
}
|
||||
|
||||
RiscvOperand *RegAlloca::findSpecificReg(Value *val, std::string RegName,
|
||||
RiscvBasicBlock *bb, RiscvInstr *instr,
|
||||
bool direct) {
|
||||
val = this->DSU_for_Variable.query(val);
|
||||
RiscvOperand *retOperand = getRegOperand(RegName);
|
||||
|
||||
return findReg(val, bb, instr, 0, 1, retOperand, direct);
|
||||
}
|
||||
|
||||
void RegAlloca::setPositionReg(Value *val, RiscvOperand *riscvReg,
|
||||
RiscvBasicBlock *bb, RiscvInstr *instr) {
|
||||
val = this->DSU_for_Variable.query(val);
|
||||
Value *old_val = getRegPosition(riscvReg);
|
||||
RiscvOperand *old_reg = getPositionReg(val);
|
||||
if (old_val != nullptr && old_val != val)
|
||||
writeback(riscvReg, bb, instr);
|
||||
if (old_reg != nullptr && old_reg != riscvReg)
|
||||
writeback(old_reg, bb, instr);
|
||||
setPositionReg(val, riscvReg);
|
||||
}
|
||||
|
||||
void RegAlloca::setPositionReg(Value *val, RiscvOperand *riscvReg) {
|
||||
val = this->DSU_for_Variable.query(val);
|
||||
if (riscvReg->isRegister() == false) {
|
||||
std::cerr << "[Fatal error] Trying to map value " << std::hex << val
|
||||
<< " to not a register operand." << std::endl;
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
// std::cerr << "[Debug] Map register <" << riscvReg->print() << "> to value <"
|
||||
// << val->print() << ">\n";
|
||||
|
||||
curReg[val] = riscvReg;
|
||||
regPos[riscvReg] = val;
|
||||
regUsed.insert(riscvReg);
|
||||
}
|
||||
|
||||
RiscvInstr *RegAlloca::writeback(RiscvOperand *riscvReg, RiscvBasicBlock *bb,
|
||||
RiscvInstr *instr) {
|
||||
Value *value = getRegPosition(riscvReg);
|
||||
if (value == nullptr)
|
||||
return nullptr; // Value not found in map
|
||||
|
||||
value = this->DSU_for_Variable.query(value);
|
||||
|
||||
// std::cerr << "[Debug] [RegAlloca] Writeback register <" << riscvReg->print()
|
||||
// << "> to value <" << value->print() << ">.\n";
|
||||
|
||||
// Erase map info
|
||||
regPos.erase(riscvReg);
|
||||
regFindTimeStamp.erase(riscvReg);
|
||||
curReg.erase(value);
|
||||
|
||||
RiscvOperand *mem_addr = findMem(value);
|
||||
|
||||
if (mem_addr == nullptr) {
|
||||
// std::cerr << "[Debug] [RegAlloca] Writeback ignore alloca pointer direct "
|
||||
// "access and immvalue.\n";
|
||||
return nullptr; // Maybe an immediate value or dicrect accessing alloca
|
||||
}
|
||||
|
||||
auto store_type = value->type_;
|
||||
auto store_instr = new StoreRiscvInst(value->type_, riscvReg, mem_addr, bb);
|
||||
|
||||
// Write store instruction
|
||||
if (instr != nullptr)
|
||||
bb->addInstrBefore(store_instr, instr);
|
||||
else
|
||||
bb->addInstrBack(store_instr);
|
||||
|
||||
return store_instr;
|
||||
}
|
||||
|
||||
RegAlloca::RegAlloca() {
|
||||
// 初始化寄存器对象池。
|
||||
if (regPool.size() == 0) {
|
||||
for (int i = 0; i < 32; i++)
|
||||
regPool.push_back(new RiscvIntReg(new Register(Register::Int, i)));
|
||||
for (int i = 0; i < 32; i++)
|
||||
regPool.push_back(new RiscvFloatReg(new Register(Register::Float, i)));
|
||||
}
|
||||
|
||||
// fp 的保护单独进行处理
|
||||
regUsed.insert(getRegOperand("ra"));
|
||||
savedRegister.push_back(getRegOperand("ra")); // 保护 ra
|
||||
// 保护 s1-s11
|
||||
for (int i = 1; i <= 11; i++)
|
||||
savedRegister.push_back(getRegOperand("s" + std::to_string(i)));
|
||||
// 保护 fs0-fs11
|
||||
for (int i = 0; i <= 11; i++)
|
||||
savedRegister.push_back(getRegOperand("fs" + std::to_string(i)));
|
||||
}
|
||||
|
||||
RiscvInstr *RegAlloca::writeback(Value *val, RiscvBasicBlock *bb,
|
||||
RiscvInstr *instr) {
|
||||
auto reg = getPositionReg(val);
|
||||
return writeback(reg, bb, instr);
|
||||
}
|
||||
|
||||
Value *RegAlloca::getRegPosition(RiscvOperand *reg) {
|
||||
if (regPos.find(reg) == regPos.end())
|
||||
return nullptr;
|
||||
return this->DSU_for_Variable.query(regPos[reg]);
|
||||
}
|
||||
|
||||
RiscvOperand *RegAlloca::getPositionReg(Value *val) {
|
||||
val = this->DSU_for_Variable.query(val);
|
||||
if (curReg.find(val) == curReg.end())
|
||||
return nullptr;
|
||||
return curReg[val];
|
||||
}
|
||||
|
||||
RiscvOperand *RegAlloca::findPtr(Value *val, RiscvBasicBlock *bb,
|
||||
RiscvInstr *instr) {
|
||||
val = this->DSU_for_Variable.query(val);
|
||||
if (ptrPos.find(val) == ptrPos.end()) {
|
||||
std::cerr << "[Fatal Error] Value's pointer position not found."
|
||||
<< std::endl;
|
||||
std::terminate();
|
||||
}
|
||||
return ptrPos[val];
|
||||
}
|
||||
|
||||
void RegAlloca::writeback_all(RiscvBasicBlock *bb, RiscvInstr *instr) {
|
||||
std::vector<RiscvOperand *> regs_to_writeback;
|
||||
for (auto p : regPos)
|
||||
regs_to_writeback.push_back(p.first);
|
||||
for (auto r : regs_to_writeback)
|
||||
writeback(r, bb, instr);
|
||||
}
|
||||
|
||||
void RegAlloca::setPointerPos(Value *val, RiscvOperand *PointerMem) {
|
||||
val = this->DSU_for_Variable.query(val);
|
||||
assert(val->type_->tid_ == Type::TypeID::PointerTyID ||
|
||||
val->type_->tid_ == Type::TypeID::ArrayTyID);
|
||||
// std::cerr << "SET POINTER: " << val->name_ << "!" << PointerMem->print()
|
||||
// << "\n";
|
||||
this->ptrPos[val] = PointerMem;
|
||||
}
|
||||
|
||||
void RegAlloca::clear() {
|
||||
curReg.clear();
|
||||
regPos.clear();
|
||||
safeFindTimeStamp = 0;
|
||||
regFindTimeStamp.clear();
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
set(SOURCE_FILES utils.cpp)
|
||||
|
||||
add_library(utils ${SOURCE_FILES})
|
@ -0,0 +1 @@
|
||||
// Currently a dummy file
|
@ -0,0 +1,2 @@
|
||||
4010
|
||||
++++++++[->++++++++<]>+++++++++.<+++++[->-----<]>---------.<++++++++[->++++++++<]>++++++.<++++++++[->--------<]>-------------.<+++++++[->+++++++<]>++.<+++++[->+++++<]>+++++++++.+++++.-----.--------.----.<++++[->++++<]>.<++++[->----<]>--------.<++++++++[->--------<]>-.<++++++[->++++++<]>++++.<+++++[->+++++<]>.<++++[->++++<]>+.+++.<+++[->---<]>----.+.<++++++++[->--------<]>---------.<++++++++[->++++++++<]>++++++.<+++[->+++<]>+++.---.--.<++++++++[->--------<]>-------------.<+++++++++[->+++++++++<]>+++.<+++[->---<]>---.---.<++++++++[->--------<]>-----.<++++++[->++++++<]>+.<+++++[->+++++<]>+++.<++++[->++++<]>++.+.<+++++++++[->---------<]>---.<++++++[->++++++<]>++++++.<++++++[->++++++<]>+++++++.-------.-----.++++++.+++.<+++++++++[->---------<]>-.<++++++[->++++++<]>++++.<+++++[->+++++<]>++++++++.--.+.<++++++++[->--------<]>--------.<+++++++[->+++++++<]>++.<++++[->++++<]>.+++++.+++++++..---.<++++++++[->--------<]>.<+++[->---<]>---.<++++++++[->++++++++<]>+.<+++[->+++<]>++++.<+++[->---<]>-.<++++++++[->--------<]>----.<++++++[->++++++<]>+++++.<+++++[->-----<]>---------.<++++++++[->++++++++<]>++++++.<++++++++[->--------<]>-------------.<++++++++[->++++++++<]>++++++++++++++.+.+++++.<+++++++++[->---------<]>---.<++++++++[->++++++++<]>+++++++++.+++++.++++++.<+++[->---<]>------.<+++[->+++<]>++++.<+++[->---<]>----.<+++[->+++<]>+++++.+.<+++[->---<]>------.-.<++++++++[->--------<]>----.<++++++++[->++++++++<]>+++++++++.+++++.<++++++++[->--------<]>--------------.<++++++++[->++++++++<]>+++++++++++++++.+++.<+++[->---<]>-----.+++++.+++++.<+++[->---<]>----.<++++[->++++<]>+.+++++++.<+++++++++[->---------<]>--------.<++++++++[->++++++++<]>++++++++.<+++[->+++<]>++++.--------.<+++[->---<]>---.<+++[->+++<]>++++.+++++.<++++++++[->--------<]>-----.<+++[->---<]>-----.<++++++[->++++++<]>+++++.<+++++[->+++++<]>++++.<++++++++[->--------<]>------.<+++++++++[->+++++++++<]>+++.<+++[->---<]>---.---.<+++[->+++<]>++++.<+++[->---<]>----.<++++++++[->--------<]>-----.<+++++++++[->+++++++++<]>++++++.<++++[->----<]>--.<+++[->+++<]>++++.<+++[->---<]>----.<++++++++[->--------<]>-----.<++++++++[->++++++++<]>+.<+++[->+++<]>++++.<++++++++[->--------<]>--------------.<++++++++[->++++++++<]>+.<+++[->+++<]>++.---.----.+++++++++.<++++++++[->--------<]>--.<+++[->---<]>---.<++++++++[->++++++++<]>+.<++++++++[->--------<]>-.<+++++++++[->+++++++++<]>+++.<+++[->---<]>--.++++.--------.<++++++++[->--------<]>-----.<+++++++++[->+++++++++<]>+++.--.<++++[->----<]>-.<++++[->++++<]>+++++.<++++[->----<]>-.+++++++..-------.<+++[->+++<]>++++.<++++++++[->--------<]>------.<+++[->---<]>---.<++++++++[->++++++++<]>+.<+++[->+++<]>++++.<++++++++[->--------<]>--------------.<++++++++[->++++++++<]>+++++++++++++++.+++++.<+++[->---<]>---.---.<+++[->+++<]>++++.+++++.--------.+++.------.--------.+.<+++[->+++<]>++++.<+++++++++[->---------<]>-.<++++++++[->++++++++<]>+++++++++++++++.+++.<+++++++++[->---------<]>-.<++++++++[->++++++++<]>+.<++++++++[->--------<]>-.<+++++++++[->+++++++++<]>++.++.-----.<+++[->---<]>--.<+++[->+++<]>++++.<+++[->---<]>-.---.<+++[->+++<]>++++.---.<++++++++[->--------<]>---------------.<++++++++[->++++++++<]>+.<+++[->+++<]>+++.++.-.-------.<++++++++[->--------<]>-------.<+++++++++[->+++++++++<]>++++++++.<+++[->---<]>-.++++++.<++++++++[->--------<]>---------.<+++[->---<]>---.<++++++++[->++++++++<]>++++++++++++++++.----.-------.----.<++++[->++++<]>++.<+++[->---<]>-----.<++++++++[->--------<]>-----.<++++++++[->++++++++<]>+++.<+++[->+++<]>+++.--.--------.<++++++++[->--------<]>-----.<+++++++++[->+++++++++<]>+++.-----.<++++++++[->--------<]>---------------.<++++++++[->++++++++<]>+++++++++++++.--------..<+++[->+++<]>++++++.<+++++++++[->---------<]>---.<++++++++[->++++++++<]>+++++++++++++.--------.<++++++++[->--------<]>----.-.<+++++++[->+++++++<]>+++.<++++[->++++<]>++++.-------.<++++[->++++<]>+++.<++++++++[->--------<]>-------------.<++++++++[->++++++++<]>++++++++++++.<+++++++++[->---------<]>--.<++++++++[->++++++++<]>+.<+++[->+++<]>++..<+++++++[->-------<]>-------------.<+++++[->-----<]>--------.---.<
|
@ -0,0 +1,2 @@
|
||||
I'm Suzumiya Haruhi from the East Junior High School, and I'm not interested in ordinary humans. If there were an alien, a time traveller, an otherworlder or a superhero among you, please come to meet me! That's all.
|
||||
0
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
a brainfuck interpreter
|
||||
reference: https://gist.github.com/maxcountryman/1699708
|
||||
*/
|
||||
|
||||
// tape, input buffer, and read/write pointer
|
||||
const int TAPE_LEN = 65536, BUFFER_LEN = 32768;
|
||||
int tape[TAPE_LEN], program[BUFFER_LEN], ptr = 0;
|
||||
|
||||
// read the input program
|
||||
void read_program() {
|
||||
int i = 0, len = getint();
|
||||
while (i < len) {
|
||||
program[i] = getch();
|
||||
i = i + 1;
|
||||
}
|
||||
program[i] = 0;
|
||||
}
|
||||
|
||||
// interpret the input program
|
||||
void interpret(int input[]) {
|
||||
int cur_char, loop, i = 0;
|
||||
while (input[i]) {
|
||||
cur_char = input[i];
|
||||
if (cur_char == 62) {
|
||||
// '>'
|
||||
ptr = ptr + 1;
|
||||
}
|
||||
else if (cur_char == 60) {
|
||||
// '<'
|
||||
ptr = ptr - 1;
|
||||
}
|
||||
else if (cur_char == 43) {
|
||||
// '+'
|
||||
tape[ptr] = tape[ptr] + 1;
|
||||
}
|
||||
else if (cur_char == 45) {
|
||||
// '-'
|
||||
tape[ptr] = tape[ptr] - 1;
|
||||
}
|
||||
else if (cur_char == 46) {
|
||||
// '.'
|
||||
putch(tape[ptr]);
|
||||
}
|
||||
else if (cur_char == 44) {
|
||||
// ','
|
||||
tape[ptr] = getch();
|
||||
}
|
||||
else if (cur_char == 93 && tape[ptr]) {
|
||||
// ']'
|
||||
loop = 1;
|
||||
while (loop > 0) {
|
||||
i = i - 1;
|
||||
cur_char = input[i];
|
||||
if (cur_char == 91) {
|
||||
// '['
|
||||
loop = loop - 1;
|
||||
}
|
||||
else if (cur_char == 93) {
|
||||
// ']'
|
||||
loop = loop + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
read_program();
|
||||
interpret(program);
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
6 9
|
||||
1 2 1
|
||||
2 3 9
|
||||
1 3 12
|
||||
2 4 3
|
||||
4 3 4
|
||||
3 5 5
|
||||
4 5 13
|
||||
5 6 4
|
||||
4 6 15
|
@ -0,0 +1,2 @@
|
||||
0 1 8 4 13 17
|
||||
0
|
@ -0,0 +1,82 @@
|
||||
const int INF = 65535;
|
||||
int e[16][16];
|
||||
int book[16];
|
||||
int dis[16];
|
||||
int n, m;
|
||||
int v1, v2, w;
|
||||
|
||||
void Dijkstra()
|
||||
{
|
||||
int i, j;
|
||||
|
||||
i = 1;
|
||||
while (i <= n) {
|
||||
dis[i] = e[1][i];
|
||||
book[i] = 0;
|
||||
i = i + 1;
|
||||
}
|
||||
book[1] = 1;
|
||||
|
||||
i = 1;
|
||||
while (i <= n - 1) {
|
||||
int min_num = INF;
|
||||
int min_index = 0;
|
||||
int k = 1;
|
||||
while (k <= n) {
|
||||
if (min_num > dis[k] && book[k] == 0) {
|
||||
min_num = dis[k];
|
||||
min_index = k;
|
||||
}
|
||||
k = k + 1;
|
||||
}
|
||||
book[min_index] = 1;
|
||||
int j = 1;
|
||||
while (j <= n) {
|
||||
if (e[min_index][j] < INF) {
|
||||
if (dis[j] > dis[min_index] + e[min_index][j]) {
|
||||
dis[j] = dis[min_index] + e[min_index][j];
|
||||
}
|
||||
}
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
n = getint();
|
||||
m = getint();
|
||||
|
||||
i = 1;
|
||||
while (i <= n) {
|
||||
int j = 1;
|
||||
while (j <= n) {
|
||||
if (i == j)
|
||||
e[i][j] = 0;
|
||||
else
|
||||
e[i][j] = INF;
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 1;
|
||||
while (i <= m) {
|
||||
int u = getint(), v = getint();
|
||||
e[u][v] = getint();
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
Dijkstra();
|
||||
|
||||
i = 1;
|
||||
while (i <= n) {
|
||||
putint(dis[i]);
|
||||
putch(32);
|
||||
i = i + 1;
|
||||
}
|
||||
putch(10);
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
6
|
||||
|
||||
233 95 179 178 105
|
||||
115 190 92 216 21
|
||||
48 252 184 148 36
|
||||
252 20 92 99 18
|
||||
61 245 40 190 16
|
||||
|
||||
61 197 150 246 225
|
||||
27 99 197 227 206
|
||||
130 134 172 149 52
|
||||
147 246 171 52 84
|
||||
174 42 90 23 42
|
||||
|
||||
130 207 209 104 168
|
||||
139 248 84 142 225
|
||||
127 242 45 62 7
|
||||
102 191 119 168 190
|
||||
14 249 239 188 118
|
||||
|
||||
159 29 212 96 189
|
||||
159 220 97 71 180
|
||||
202 131 217 165 138
|
||||
94 98 86 68 140
|
||||
132 92 247 99 110
|
||||
|
||||
228 10 119 127 21
|
||||
247 8 230 81 251
|
||||
216 213 24 114 68
|
||||
83 188 240 196 231
|
||||
90 206 224 49 28
|
||||
|
||||
158 252 95 171 239
|
||||
90 66 22 221 10
|
||||
177 32 38 24 93
|
||||
227 55 4 59 211
|
||||
80 92 38 238 42
|
@ -0,0 +1,7 @@
|
||||
dog
|
||||
cat
|
||||
dog
|
||||
dog
|
||||
cat
|
||||
cat
|
||||
0
|
@ -0,0 +1,50 @@
|
||||
|
||||
int relu_reg(int a)
|
||||
{
|
||||
if (a > 0x7F) return 0x7F;
|
||||
if (a < 0) return 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
int model(int a[][5])
|
||||
{
|
||||
if (+ relu_reg( + a[0][0] * 85 + a[0][1] * 23 + a[0][2] * -82 + a[0][3] * -103 + a[0][4] * -123 + a[1][0] * 64 + a[1][1] * -120 + a[1][2] * 50 + a[1][3] * -59 + a[1][4] * 47 + a[2][0] * -111 + a[2][1] * -67 + a[2][2] * -106 + a[2][3] * -75 + a[2][4] * -102 + a[3][0] * 34 + a[3][1] * -39 + a[3][2] * 65 + a[3][3] * 47 + a[3][4] * 113 + a[4][0] * 110 + a[4][1] * 47 + a[4][2] * -4 + a[4][3] * 80 + a[4][4] * 46) * 39
|
||||
+ relu_reg( + a[0][0] * -106 + a[0][1] * 126 + a[0][2] * -18 + a[0][3] * -31 + a[0][4] * -8 + a[1][0] * 47 + a[1][1] * -4 + a[1][2] * 67 + a[1][3] * -94 + a[1][4] * -121 + a[2][0] * 7 + a[2][1] * -21 + a[2][2] * -60 + a[2][3] * -43 + a[2][4] * 105 + a[3][0] * -42 + a[3][1] * 87 + a[3][2] * 29 + a[3][3] * -106 + a[3][4] * -31 + a[4][0] * -110 + a[4][1] * -100 + a[4][2] * -22 + a[4][3] * -75 + a[4][4] * -125) * 77
|
||||
+ relu_reg( + a[0][0] * 26 + a[0][1] * 76 + a[0][2] * -70 + a[0][3] * 29 + a[0][4] * -95 + a[1][0] * 96 + a[1][1] * 52 + a[1][2] * -68 + a[1][3] * -5 + a[1][4] * 34 + a[2][0] * -34 + a[2][1] * 102 + a[2][2] * 6 + a[2][3] * -38 + a[2][4] * 27 + a[3][0] * 110 + a[3][1] * 116 + a[3][2] * 39 + a[3][3] * -63 + a[3][4] * -99 + a[4][0] * 65 + a[4][1] * 120 + a[4][2] * -39 + a[4][3] * -6 + a[4][4] * 94) * 127
|
||||
+ relu_reg( + a[0][0] * -23 + a[0][1] * -63 + a[0][2] * 49 + a[0][3] * 50 + a[0][4] * 72 + a[1][0] * 85 + a[1][1] * -30 + a[1][2] * 12 + a[1][3] * 125 + a[1][4] * -117 + a[2][0] * -65 + a[2][1] * -67 + a[2][2] * 125 + a[2][3] * 110 + a[2][4] * -31 + a[3][0] * -123 + a[3][1] * 83 + a[3][2] * 122 + a[3][3] * 11 + a[3][4] * -23 + a[4][0] * -47 + a[4][1] * -32 + a[4][2] * -117 + a[4][3] * 95 + a[4][4] * 118) * -106
|
||||
+ relu_reg( + a[0][0] * 8 + a[0][1] * 82 + a[0][2] * -104 + a[0][3] * 101 + a[0][4] * -116 + a[1][0] * -63 + a[1][1] * -16 + a[1][2] * -70 + a[1][3] * 125 + a[1][4] * 75 + a[2][0] * 66 + a[2][1] * -96 + a[2][2] * -101 + a[2][3] * -114 + a[2][4] * 59 + a[3][0] * 12 + a[3][1] * 5 + a[3][2] * -95 + a[3][3] * 116 + a[3][4] * -93 + a[4][0] * 15 + a[4][1] * 79 + a[4][2] * 3 + a[4][3] * 49 + a[4][4] * -124) * -3
|
||||
+ relu_reg( + a[0][0] * 81 + a[0][1] * 68 + a[0][2] * -102 + a[0][3] * -74 + a[0][4] * 121 + a[1][0] * -15 + a[1][1] * 55 + a[1][2] * 101 + a[1][3] * -13 + a[1][4] * -62 + a[2][0] * 64 + a[2][1] * 114 + a[2][2] * 38 + a[2][3] * -21 + a[2][4] * 112 + a[3][0] * 114 + a[3][1] * 112 + a[3][2] * -10 + a[3][3] * -16 + a[3][4] * -50 + a[4][0] * -112 + a[4][1] * -116 + a[4][2] * -54 + a[4][3] * 82 + a[4][4] * -72) * 32
|
||||
+ relu_reg( + a[0][0] * 15 + a[0][1] * -77 + a[0][2] * 66 + a[0][3] * -90 + a[0][4] * -6 + a[1][0] * -30 + a[1][1] * -8 + a[1][2] * 81 + a[1][3] * 2 + a[1][4] * -110 + a[2][0] * -95 + a[2][1] * 59 + a[2][2] * 52 + a[2][3] * 15 + a[2][4] * 55 + a[3][0] * -33 + a[3][1] * 14 + a[3][2] * 58 + a[3][3] * 67 + a[3][4] * 86 + a[4][0] * -79 + a[4][1] * 48 + a[4][2] * -13 + a[4][3] * -15 + a[4][4] * 66) * -95
|
||||
+ relu_reg( + a[0][0] * 33 + a[0][1] * 82 + a[0][2] * 67 + a[0][3] * 30 + a[0][4] * -2 + a[1][0] * 65 + a[1][1] * 120 + a[1][2] * -13 + a[1][3] * 18 + a[1][4] * 5 + a[2][0] * 104 + a[2][1] * -119 + a[2][2] * -7 + a[2][3] * 71 + a[2][4] * 107 + a[3][0] * 24 + a[3][1] * 82 + a[3][2] * -96 + a[3][3] * -104 + a[3][4] * -121 + a[4][0] * 65 + a[4][1] * 97 + a[4][2] * 83 + a[4][3] * 46 + a[4][4] * -84) * -50
|
||||
+ relu_reg( + a[0][0] * -29 + a[0][1] * 7 + a[0][2] * -70 + a[0][3] * 38 + a[0][4] * -90 + a[1][0] * -15 + a[1][1] * -32 + a[1][2] * 37 + a[1][3] * 36 + a[1][4] * -62 + a[2][0] * -125 + a[2][1] * -46 + a[2][2] * -70 + a[2][3] * 37 + a[2][4] * -73 + a[3][0] * -34 + a[3][1] * -87 + a[3][2] * -75 + a[3][3] * 71 + a[3][4] * -77 + a[4][0] * 53 + a[4][1] * 37 + a[4][2] * -103 + a[4][3] * -13 + a[4][4] * -114) * -23
|
||||
+ relu_reg( + a[0][0] * 67 + a[0][1] * 42 + a[0][2] * 41 + a[0][3] * -123 + a[0][4] * -92 + a[1][0] * 10 + a[1][1] * -77 + a[1][2] * 75 + a[1][3] * 96 + a[1][4] * -51 + a[2][0] * 109 + a[2][1] * -74 + a[2][2] * -7 + a[2][3] * -122 + a[2][4] * 67 + a[3][0] * 47 + a[3][1] * 22 + a[3][2] * -68 + a[3][3] * 38 + a[3][4] * 29 + a[4][0] * 115 + a[4][1] * -121 + a[4][2] * 36 + a[4][3] * -49 + a[4][4] * 85) * 46
|
||||
> 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int N = getint();
|
||||
int a[5][5];
|
||||
while (N > 0) {
|
||||
int i = 0;
|
||||
while (i < 5) {
|
||||
int j = 0;
|
||||
while (j < 5) {
|
||||
a[i][j] = getint();
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
if (model(a)) {
|
||||
// cat
|
||||
putch(99); putch(97); putch(116); putch(10);
|
||||
} else {
|
||||
// dog
|
||||
putch(100); putch(111); putch(103); putch(10);
|
||||
}
|
||||
N = N - 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
4
|
||||
4
|
||||
7
|
||||
3
|
||||
9
|
@ -0,0 +1,5 @@
|
||||
1 2, 1 3, 2 3, 1 2, 3 1, 3 2, 1 2, 1 3, 2 3, 2 1, 3 1, 2 3, 1 2, 1 3, 2 3,
|
||||
1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3,
|
||||
1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3,
|
||||
1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3,
|
||||
0
|
@ -0,0 +1,27 @@
|
||||
|
||||
void move(int x, int y)
|
||||
{
|
||||
putint(x); putch(32); putint(y); putch(44); putch(32);
|
||||
}
|
||||
|
||||
void hanoi(int n, int one, int two, int three)
|
||||
{
|
||||
if (n == 1)
|
||||
move(one, three);
|
||||
else {
|
||||
hanoi(n - 1, one, three, two);
|
||||
move(one, three);
|
||||
hanoi(n - 1, two, one, three);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int n = getint();
|
||||
while (n > 0) {
|
||||
hanoi(getint(), 1, 2, 3);
|
||||
putch(10);
|
||||
n = n - 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
5
|
||||
4006571
|
||||
|
||||
9900
|
||||
1504379
|
||||
|
||||
|
||||
758219
|
||||
99336677
|
||||
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
4006571
|
||||
9900
|
||||
1504379
|
||||
758219
|
||||
99336677
|
||||
0
|
@ -0,0 +1,52 @@
|
||||
const int ascii_0 = 48;
|
||||
|
||||
int my_getint()
|
||||
{
|
||||
int sum = 0, c;
|
||||
|
||||
while (1) {
|
||||
c = getch() - ascii_0;
|
||||
if (c < 0 || c > 9) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
sum = c;
|
||||
|
||||
while (1) {
|
||||
c = getch() - ascii_0;
|
||||
if (c >= 0 && c <= 9) {
|
||||
sum = sum * 10 + c;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
void my_putint(int a)
|
||||
{
|
||||
int b[16], i = 0;
|
||||
while (a > 0) {
|
||||
b[i] = a % 10 + ascii_0;
|
||||
a = a / 10;
|
||||
i = i + 1;
|
||||
}
|
||||
while (i > 0) {
|
||||
i = i - 1;
|
||||
putch(b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int n = my_getint();
|
||||
while (n > 0) {
|
||||
int m = my_getint();
|
||||
my_putint(m); putch(10);
|
||||
n = n - 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
# Define test files
|
||||
set(FUNCTIONAL_TESTS_DIR
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/case/functional")
|
||||
set(HIDDEN_FUNCTIONAL_TESTS_DIR
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/case/hidden_functional")
|
||||
set(PERFORMANCE_TESTS_DIR
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/case/performance")
|
||||
set(FINAL_PERFORMANCE_TESTS_DIR
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/case/final_performance")
|
||||
|
||||
# set(BUILD_PERFORMANCE_TESTS true)
|
||||
# set(BUILD_IR_TESTING true)
|
||||
|
||||
# Define test function
|
||||
function(add_test_dir testdir)
|
||||
file(GLOB files "${testdir}/*.sy")
|
||||
|
||||
foreach(file ${files})
|
||||
get_filename_component(testfile "${file}" NAME_WE)
|
||||
get_filename_component(testcate "${testdir}" NAME)
|
||||
set(testname "${testcate}_${testfile}")
|
||||
if(BUILD_IR_TESTING)
|
||||
add_test(NAME "${testname}_llir"
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D "COMPILER=${CMAKE_BINARY_DIR}/compiler"
|
||||
-D "RUNTIME=${CMAKE_BINARY_DIR}/runtime"
|
||||
-D "TEST_DIR=${testdir}"
|
||||
-D "TEST_NAME=${testfile}"
|
||||
-P ${CMAKE_SOURCE_DIR}/cmake/LLVMIRTest.cmake)
|
||||
endif(BUILD_IR_TESTING)
|
||||
add_test(NAME "${testname}_asm"
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D "COMPILER=${CMAKE_BINARY_DIR}/compiler"
|
||||
-D "RUNTIME=${CMAKE_BINARY_DIR}/runtime"
|
||||
-D "TEST_DIR=${testdir}"
|
||||
-D "TEST_NAME=${testfile}"
|
||||
-P ${CMAKE_SOURCE_DIR}/cmake/RISCVTest.cmake)
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# Functional tests
|
||||
add_test_dir("${FUNCTIONAL_TESTS_DIR}")
|
||||
|
||||
# Hidden functional tests
|
||||
add_test_dir("${HIDDEN_FUNCTIONAL_TESTS_DIR}")
|
||||
|
||||
if(BUILD_PERFORMANCE_TESTS)
|
||||
# Performance tests
|
||||
add_test_dir("${PERFORMANCE_TESTS_DIR}")
|
||||
|
||||
# Final performance tests
|
||||
add_test_dir("${FINAL_PERFORMANCE_TESTS_DIR}")
|
||||
endif(BUILD_PERFORMANCE_TESTS)
|
Loading…
Reference in new issue