Add multiple of the pointer target size
This commit is contained in:
parent
8b654ed138
commit
5e9b4259ca
@ -9,15 +9,15 @@ find_package(Boost CONFIG COMPONENTS process program_options REQUIRED)
|
|||||||
find_package(FLEX REQUIRED)
|
find_package(FLEX REQUIRED)
|
||||||
find_package(BISON REQUIRED)
|
find_package(BISON REQUIRED)
|
||||||
|
|
||||||
FLEX_TARGET(lexer source/lexer.ll ${CMAKE_CURRENT_BINARY_DIR}/lexer.cc)
|
FLEX_TARGET(lexer boot/lexer.ll ${CMAKE_CURRENT_BINARY_DIR}/lexer.cc)
|
||||||
BISON_TARGET(parser source/parser.yy ${CMAKE_CURRENT_BINARY_DIR}/parser.cc)
|
BISON_TARGET(parser boot/parser.yy ${CMAKE_CURRENT_BINARY_DIR}/parser.cc)
|
||||||
add_flex_bison_dependency(lexer parser)
|
add_flex_bison_dependency(lexer parser)
|
||||||
|
|
||||||
add_library(elna-frontend
|
add_library(elna-frontend
|
||||||
source/ast.cc include/elna/source/ast.h
|
boot/ast.cc include/elna/boot/ast.h
|
||||||
source/types.cc include/elna/source/types.h
|
include/elna/boot/symbol.h
|
||||||
source/driver.cc include/elna/source/driver.h
|
boot/driver.cc include/elna/boot/driver.h
|
||||||
source/result.cc include/elna/source/result.h
|
boot/result.cc include/elna/boot/result.h
|
||||||
${BISON_parser_OUTPUTS} ${FLEX_lexer_OUTPUTS}
|
${BISON_parser_OUTPUTS} ${FLEX_lexer_OUTPUTS}
|
||||||
)
|
)
|
||||||
target_include_directories(elna-frontend PRIVATE ${CMAKE_CURRENT_BINARY_DIR} include)
|
target_include_directories(elna-frontend PRIVATE ${CMAKE_CURRENT_BINARY_DIR} include)
|
||||||
@ -25,7 +25,7 @@ target_compile_options(elna-frontend PRIVATE
|
|||||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions -fno-rtti>
|
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions -fno-rtti>
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(elna cli/main.cc)
|
add_executable(elna tools/main.cc)
|
||||||
target_link_libraries(elna PRIVATE elna-frontend)
|
target_link_libraries(elna PRIVATE elna-frontend)
|
||||||
target_include_directories(elna PRIVATE ${CMAKE_CURRENT_BINARY_DIR} include ${Boost_INCLUDE_DIR})
|
target_include_directories(elna PRIVATE ${CMAKE_CURRENT_BINARY_DIR} include ${Boost_INCLUDE_DIR})
|
||||||
target_link_libraries(elna LINK_PUBLIC ${Boost_LIBRARIES})
|
target_link_libraries(elna LINK_PUBLIC ${Boost_LIBRARIES})
|
||||||
|
30
Rakefile
30
Rakefile
@ -1,3 +1,16 @@
|
|||||||
|
require 'pathname'
|
||||||
|
require 'rake/clean'
|
||||||
|
require_relative 'rakelib/shared'
|
||||||
|
|
||||||
|
CLOBBER.include TMP
|
||||||
|
|
||||||
|
task :default do
|
||||||
|
sh 'make -C build'
|
||||||
|
sh './build/bin/elna'
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'Build the bootstrap compiler'
|
||||||
|
task :boot do
|
||||||
# MacOS:
|
# MacOS:
|
||||||
# ---
|
# ---
|
||||||
# CC=gcc-14 CXX=g++-14 \
|
# CC=gcc-14 CXX=g++-14 \
|
||||||
@ -8,8 +21,17 @@
|
|||||||
# --enable-languages=c,c++,elna \
|
# --enable-languages=c,c++,elna \
|
||||||
# --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX15.2.sdk \
|
# --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX15.2.sdk \
|
||||||
# --prefix=$(realpath ../gcc-install)
|
# --prefix=$(realpath ../gcc-install)
|
||||||
|
end
|
||||||
task :default do
|
|
||||||
sh 'make -C build'
|
desc 'Build cross toolchain'
|
||||||
sh './build/bin/elna'
|
task :cross, [:target] do |_, args|
|
||||||
|
args.with_defaults target: 'riscv32-unknown-linux-gnu'
|
||||||
|
|
||||||
|
Rake::Task['cross:binutils'].invoke args[:target]
|
||||||
|
Rake::Task['cross:gcc1'].invoke args[:target]
|
||||||
|
Rake::Task['cross:headers'].invoke args[:target]
|
||||||
|
Rake::Task['cross:kernel'].invoke args[:target]
|
||||||
|
Rake::Task['cross:glibc'].invoke args[:target]
|
||||||
|
Rake::Task['cross:gcc2'].invoke args[:target]
|
||||||
|
Rake::Task['cross:init'].invoke args[:target]
|
||||||
end
|
end
|
||||||
|
@ -74,15 +74,7 @@ namespace gcc
|
|||||||
{
|
{
|
||||||
auto body_type = build_type(expression->body());
|
auto body_type = build_type(expression->body());
|
||||||
|
|
||||||
this->current_expression = build1(CONVERT_EXPR, this->symbol_map->lookup("Word"), TYPE_SIZE_UNIT(body_type));
|
this->current_expression = build1(CONVERT_EXPR, this->symbol_map->lookup("Word"), size_in_bytes(body_type));
|
||||||
}
|
|
||||||
|
|
||||||
bool generic_visitor::is_integral_type(tree type)
|
|
||||||
{
|
|
||||||
gcc_assert(TYPE_P(type));
|
|
||||||
|
|
||||||
return type == this->symbol_map->lookup("Int")
|
|
||||||
|| type == this->symbol_map->lookup("Word");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool generic_visitor::is_numeric_type(tree type)
|
bool generic_visitor::is_numeric_type(tree type)
|
||||||
@ -333,7 +325,9 @@ namespace gcc
|
|||||||
|
|
||||||
location_t expression_location = get_location(&expression->position());
|
location_t expression_location = get_location(&expression->position());
|
||||||
|
|
||||||
if (is_pointer_type(left_type) && is_integral_type(right_type))
|
if ((is_pointer_type(left_type) || is_pointer_type(right_type))
|
||||||
|
&& (expression->operation() == boot::binary_operator::sum
|
||||||
|
|| expression->operation() == boot::binary_operator::subtraction))
|
||||||
{
|
{
|
||||||
this->current_expression = do_pointer_arithmetic(expression->operation(), left, right);
|
this->current_expression = do_pointer_arithmetic(expression->operation(), left, right);
|
||||||
if (this->current_expression == error_mark_node)
|
if (this->current_expression == error_mark_node)
|
||||||
@ -342,6 +336,10 @@ namespace gcc
|
|||||||
"invalid operation %s on a pointer and an integral type",
|
"invalid operation %s on a pointer and an integral type",
|
||||||
boot::print_binary_operator(expression->operation()));
|
boot::print_binary_operator(expression->operation()));
|
||||||
}
|
}
|
||||||
|
else if (TREE_TYPE(this->current_expression) == ssizetype)
|
||||||
|
{
|
||||||
|
this->current_expression = fold_convert(this->symbol_map->lookup("Int"), this->current_expression);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (left_type != right_type && !are_compatible_pointers(left, right))
|
if (left_type != right_type && !are_compatible_pointers(left, right))
|
||||||
|
@ -23,6 +23,12 @@ namespace gcc
|
|||||||
return TREE_CODE(type) == POINTER_TYPE;
|
return TREE_CODE(type) == POINTER_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_integral_type(tree type)
|
||||||
|
{
|
||||||
|
gcc_assert(TYPE_P(type));
|
||||||
|
return TREE_CODE(type) == INTEGER_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
bool are_compatible_pointers(tree lhs, tree rhs)
|
bool are_compatible_pointers(tree lhs, tree rhs)
|
||||||
{
|
{
|
||||||
return (lhs == null_pointer_node || rhs == null_pointer_node)
|
return (lhs == null_pointer_node || rhs == null_pointer_node)
|
||||||
@ -87,19 +93,52 @@ namespace gcc
|
|||||||
|
|
||||||
tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right)
|
tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right)
|
||||||
{
|
{
|
||||||
tree result = error_mark_node;
|
|
||||||
tree convert_expression = fold_convert(sizetype, right);
|
|
||||||
|
|
||||||
if (binary_operator == boot::binary_operator::sum)
|
if (binary_operator == boot::binary_operator::sum)
|
||||||
{
|
{
|
||||||
result = fold_build2(POINTER_PLUS_EXPR, TREE_TYPE(left), left, convert_expression);
|
tree pointer{ NULL_TREE };
|
||||||
|
tree offset{ NULL_TREE };
|
||||||
|
|
||||||
|
if (is_pointer_type(TREE_TYPE(left)) && is_integral_type(TREE_TYPE(right)))
|
||||||
|
{
|
||||||
|
pointer = left;
|
||||||
|
offset = right;
|
||||||
|
}
|
||||||
|
else if (is_integral_type(TREE_TYPE(left)) && is_pointer_type(TREE_TYPE(right)))
|
||||||
|
{
|
||||||
|
pointer = right;
|
||||||
|
offset = left;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return error_mark_node;
|
||||||
|
}
|
||||||
|
tree size_exp = fold_convert(TREE_TYPE(offset), size_in_bytes(TREE_TYPE(TREE_TYPE(pointer))));
|
||||||
|
|
||||||
|
offset = fold_build2(MULT_EXPR, TREE_TYPE(offset), offset, size_exp);
|
||||||
|
offset = fold_convert(sizetype, offset);
|
||||||
|
|
||||||
|
return fold_build2(POINTER_PLUS_EXPR, TREE_TYPE(pointer), pointer, offset);
|
||||||
}
|
}
|
||||||
else if (binary_operator == boot::binary_operator::subtraction)
|
else if (binary_operator == boot::binary_operator::subtraction)
|
||||||
{
|
{
|
||||||
|
if (is_pointer_type(TREE_TYPE(left)) && is_integral_type(TREE_TYPE(right)))
|
||||||
|
{
|
||||||
|
tree pointer_type = TREE_TYPE(left);
|
||||||
|
tree offset_type = TREE_TYPE(right);
|
||||||
|
tree size_exp = fold_convert(offset_type, size_in_bytes(TREE_TYPE(pointer_type)));
|
||||||
|
|
||||||
|
tree convert_expression = fold_build2(MULT_EXPR, offset_type, right, size_exp);
|
||||||
|
convert_expression = fold_convert(sizetype, convert_expression);
|
||||||
|
|
||||||
convert_expression = fold_build1(NEGATE_EXPR, sizetype, convert_expression);
|
convert_expression = fold_build1(NEGATE_EXPR, sizetype, convert_expression);
|
||||||
result = fold_build2(POINTER_PLUS_EXPR, TREE_TYPE(left), left, convert_expression);
|
return fold_build2(POINTER_PLUS_EXPR, pointer_type, left, convert_expression);
|
||||||
|
} else if (is_pointer_type(TREE_TYPE(left)) && is_pointer_type(TREE_TYPE(right))
|
||||||
|
&& TREE_TYPE(left) == TREE_TYPE(right))
|
||||||
|
{
|
||||||
|
return fold_build2(POINTER_DIFF_EXPR, ssizetype, left, right);
|
||||||
}
|
}
|
||||||
return result;
|
}
|
||||||
|
return error_mark_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
tree build_binary_operation(bool condition, boot::binary_expression *expression,
|
tree build_binary_operation(bool condition, boot::binary_expression *expression,
|
||||||
|
@ -33,7 +33,6 @@ namespace gcc
|
|||||||
|
|
||||||
void make_if_branch(boot::conditional_statements& branch, tree goto_endif);
|
void make_if_branch(boot::conditional_statements& branch, tree goto_endif);
|
||||||
|
|
||||||
bool is_integral_type(tree type);
|
|
||||||
bool is_numeric_type(tree type);
|
bool is_numeric_type(tree type);
|
||||||
|
|
||||||
tree build_arithmetic_operation(boot::binary_expression *expression,
|
tree build_arithmetic_operation(boot::binary_expression *expression,
|
||||||
|
@ -24,6 +24,7 @@ namespace gcc
|
|||||||
{
|
{
|
||||||
void init_ttree();
|
void init_ttree();
|
||||||
bool is_pointer_type(tree type);
|
bool is_pointer_type(tree type);
|
||||||
|
bool is_integral_type(tree type);
|
||||||
bool are_compatible_pointers(tree lhs, tree rhs);
|
bool are_compatible_pointers(tree lhs, tree rhs);
|
||||||
|
|
||||||
class tree_chain_base
|
class tree_chain_base
|
||||||
|
@ -2,87 +2,16 @@
|
|||||||
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||||
# obtain one at https://mozilla.org/MPL/2.0/. -}
|
# obtain one at https://mozilla.org/MPL/2.0/. -}
|
||||||
|
|
||||||
require 'pathname'
|
|
||||||
require 'uri'
|
require 'uri'
|
||||||
require 'net/http'
|
require 'net/http'
|
||||||
require 'rake/clean'
|
|
||||||
require 'open3'
|
require 'open3'
|
||||||
require 'etc'
|
require 'etc'
|
||||||
require_relative 'shared'
|
require_relative 'shared'
|
||||||
|
|
||||||
GCC_VERSION = "14.2.0"
|
|
||||||
BINUTILS_VERSION = '2.43.1'
|
BINUTILS_VERSION = '2.43.1'
|
||||||
GLIBC_VERSION = '2.40'
|
GLIBC_VERSION = '2.40'
|
||||||
KERNEL_VERSION = '5.15.166'
|
KERNEL_VERSION = '5.15.166'
|
||||||
|
|
||||||
CLOBBER.include TMP
|
|
||||||
|
|
||||||
class BuildTarget
|
|
||||||
attr_accessor(:build, :gcc, :target, :tmp)
|
|
||||||
|
|
||||||
def gxx
|
|
||||||
@gcc.gsub 'c', '+'
|
|
||||||
end
|
|
||||||
|
|
||||||
def sysroot
|
|
||||||
tmp + 'sysroot'
|
|
||||||
end
|
|
||||||
|
|
||||||
def rootfs
|
|
||||||
tmp + 'rootfs'
|
|
||||||
end
|
|
||||||
|
|
||||||
def tools
|
|
||||||
tmp + 'tools'
|
|
||||||
end
|
|
||||||
|
|
||||||
def configuration
|
|
||||||
case target
|
|
||||||
when /^riscv[[:digit:]]+-/
|
|
||||||
[
|
|
||||||
'--with-arch=rv32imafdc',
|
|
||||||
'--with-abi=ilp32d',
|
|
||||||
'--with-tune=rocket',
|
|
||||||
'--with-isa-spec=20191213'
|
|
||||||
]
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def gcc_verbose(gcc_binary)
|
|
||||||
read, write = IO.pipe
|
|
||||||
sh({'LANG' => 'C'}, gcc_binary, '--verbose', err: write)
|
|
||||||
write.close
|
|
||||||
output = read.read
|
|
||||||
read.close
|
|
||||||
output
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_build_target(gcc_version, task)
|
|
||||||
gcc_binary = 'gcc'
|
|
||||||
output = gcc_verbose gcc_binary
|
|
||||||
|
|
||||||
if output.start_with? 'Apple clang'
|
|
||||||
gcc_binary = "gcc-#{gcc_version.split('.').first}"
|
|
||||||
output = gcc_verbose gcc_binary
|
|
||||||
end
|
|
||||||
result = output
|
|
||||||
.lines
|
|
||||||
.each_with_object(BuildTarget.new) do |line, accumulator|
|
|
||||||
if line.start_with? 'Target: '
|
|
||||||
accumulator.build = line.split(' ').last.strip
|
|
||||||
elsif line.start_with? 'COLLECT_GCC'
|
|
||||||
accumulator.gcc = line.split('=').last.strip
|
|
||||||
end
|
|
||||||
end
|
|
||||||
result.tmp = TMP
|
|
||||||
task.with_defaults target: 'riscv32-unknown-linux-gnu'
|
|
||||||
result.target = task[:target]
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
def download_and_unarchive(url, target)
|
def download_and_unarchive(url, target)
|
||||||
case File.extname url.path
|
case File.extname url.path
|
||||||
when '.bz2'
|
when '.bz2'
|
||||||
@ -126,7 +55,7 @@ end
|
|||||||
namespace :cross do
|
namespace :cross do
|
||||||
desc 'Build cross binutils'
|
desc 'Build cross binutils'
|
||||||
task :binutils, [:target] do |_, args|
|
task :binutils, [:target] do |_, args|
|
||||||
options = find_build_target GCC_VERSION, args
|
options = find_build_target GCC_VERSION, args[:target]
|
||||||
options.tools.mkpath
|
options.tools.mkpath
|
||||||
source_directory = download_and_unarchive(
|
source_directory = download_and_unarchive(
|
||||||
URI.parse("https://ftp.gnu.org/gnu/binutils/binutils-#{BINUTILS_VERSION}.tar.xz"),
|
URI.parse("https://ftp.gnu.org/gnu/binutils/binutils-#{BINUTILS_VERSION}.tar.xz"),
|
||||||
@ -157,7 +86,7 @@ namespace :cross do
|
|||||||
|
|
||||||
desc 'Build stage 1 GCC'
|
desc 'Build stage 1 GCC'
|
||||||
task :gcc1, [:target] do |_, args|
|
task :gcc1, [:target] do |_, args|
|
||||||
options = find_build_target GCC_VERSION, args
|
options = find_build_target GCC_VERSION, args[:target]
|
||||||
options.tools.mkpath
|
options.tools.mkpath
|
||||||
source_directory = download_and_unarchive(
|
source_directory = download_and_unarchive(
|
||||||
URI.parse("https://gcc.gnu.org/pub/gcc/releases/gcc-#{GCC_VERSION}/gcc-#{GCC_VERSION}.tar.xz"),
|
URI.parse("https://gcc.gnu.org/pub/gcc/releases/gcc-#{GCC_VERSION}/gcc-#{GCC_VERSION}.tar.xz"),
|
||||||
@ -208,7 +137,7 @@ namespace :cross do
|
|||||||
|
|
||||||
desc 'Copy glibc headers'
|
desc 'Copy glibc headers'
|
||||||
task :headers, [:target] do |_, args|
|
task :headers, [:target] do |_, args|
|
||||||
options = find_build_target GCC_VERSION, args
|
options = find_build_target GCC_VERSION, args[:target]
|
||||||
options.tools.mkpath
|
options.tools.mkpath
|
||||||
|
|
||||||
source_directory = download_and_unarchive(
|
source_directory = download_and_unarchive(
|
||||||
@ -222,7 +151,7 @@ namespace :cross do
|
|||||||
|
|
||||||
desc 'Build linux kernel'
|
desc 'Build linux kernel'
|
||||||
task :kernel, [:target] do |_, args|
|
task :kernel, [:target] do |_, args|
|
||||||
options = find_build_target GCC_VERSION, args
|
options = find_build_target GCC_VERSION, args[:target]
|
||||||
options.tools.mkpath
|
options.tools.mkpath
|
||||||
|
|
||||||
cwd = download_and_unarchive(
|
cwd = download_and_unarchive(
|
||||||
@ -247,7 +176,7 @@ namespace :cross do
|
|||||||
|
|
||||||
desc 'Build glibc'
|
desc 'Build glibc'
|
||||||
task :glibc, [:target] do |_, args|
|
task :glibc, [:target] do |_, args|
|
||||||
options = find_build_target GCC_VERSION, args
|
options = find_build_target GCC_VERSION, args[:target]
|
||||||
source_directory = options.tools + "glibc-#{GLIBC_VERSION}"
|
source_directory = options.tools + "glibc-#{GLIBC_VERSION}"
|
||||||
configure_options = [
|
configure_options = [
|
||||||
'--prefix=/usr',
|
'--prefix=/usr',
|
||||||
@ -278,7 +207,7 @@ namespace :cross do
|
|||||||
|
|
||||||
desc 'Build stage 2 GCC'
|
desc 'Build stage 2 GCC'
|
||||||
task :gcc2, [:target] do |_, args|
|
task :gcc2, [:target] do |_, args|
|
||||||
options = find_build_target GCC_VERSION, args
|
options = find_build_target GCC_VERSION, args[:target]
|
||||||
source_directory = options.tools + "gcc-#{GCC_VERSION}"
|
source_directory = options.tools + "gcc-#{GCC_VERSION}"
|
||||||
cwd = options.tools + 'build-gcc'
|
cwd = options.tools + 'build-gcc'
|
||||||
|
|
||||||
@ -317,7 +246,7 @@ namespace :cross do
|
|||||||
end
|
end
|
||||||
|
|
||||||
task :init, [:target] do |_, args|
|
task :init, [:target] do |_, args|
|
||||||
options = find_build_target GCC_VERSION, args
|
options = find_build_target GCC_VERSION, args[:target]
|
||||||
env = {
|
env = {
|
||||||
'PATH' => "#{options.rootfs.realpath + 'bin'}:#{ENV['PATH']}"
|
'PATH' => "#{options.rootfs.realpath + 'bin'}:#{ENV['PATH']}"
|
||||||
}
|
}
|
||||||
@ -327,15 +256,3 @@ namespace :cross do
|
|||||||
'tools/init.c'
|
'tools/init.c'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc 'Build cross toolchain'
|
|
||||||
task :cross, [:target] => [
|
|
||||||
'cross:binutils',
|
|
||||||
'cross:gcc1',
|
|
||||||
'cross:headers',
|
|
||||||
'cross:kernel',
|
|
||||||
'cross:glibc',
|
|
||||||
'cross:gcc2',
|
|
||||||
'cross:init'
|
|
||||||
] do
|
|
||||||
end
|
|
||||||
|
@ -2,4 +2,71 @@
|
|||||||
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||||
# obtain one at https://mozilla.org/MPL/2.0/. -}
|
# obtain one at https://mozilla.org/MPL/2.0/. -}
|
||||||
|
|
||||||
|
GCC_VERSION = "14.2.0"
|
||||||
|
|
||||||
TMP = Pathname.new('./build')
|
TMP = Pathname.new('./build')
|
||||||
|
|
||||||
|
class BuildTarget
|
||||||
|
attr_accessor(:build, :gcc, :target, :tmp)
|
||||||
|
|
||||||
|
def gxx
|
||||||
|
@gcc.gsub 'c', '+'
|
||||||
|
end
|
||||||
|
|
||||||
|
def sysroot
|
||||||
|
tmp + 'sysroot'
|
||||||
|
end
|
||||||
|
|
||||||
|
def rootfs
|
||||||
|
tmp + 'rootfs'
|
||||||
|
end
|
||||||
|
|
||||||
|
def tools
|
||||||
|
tmp + 'tools'
|
||||||
|
end
|
||||||
|
|
||||||
|
def configuration
|
||||||
|
case target
|
||||||
|
when /^riscv[[:digit:]]+-/
|
||||||
|
[
|
||||||
|
'--with-arch=rv32imafdc',
|
||||||
|
'--with-abi=ilp32d',
|
||||||
|
'--with-tune=rocket',
|
||||||
|
'--with-isa-spec=20191213'
|
||||||
|
]
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def gcc_verbose(gcc_binary)
|
||||||
|
read, write = IO.pipe
|
||||||
|
sh({'LANG' => 'C'}, gcc_binary, '--verbose', err: write)
|
||||||
|
write.close
|
||||||
|
output = read.read
|
||||||
|
read.close
|
||||||
|
output
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_build_target(gcc_version, target)
|
||||||
|
gcc_binary = 'gcc'
|
||||||
|
output = gcc_verbose gcc_binary
|
||||||
|
|
||||||
|
if output.start_with? 'Apple clang'
|
||||||
|
gcc_binary = "gcc-#{gcc_version.split('.').first}"
|
||||||
|
output = gcc_verbose gcc_binary
|
||||||
|
end
|
||||||
|
result = output
|
||||||
|
.lines
|
||||||
|
.each_with_object(BuildTarget.new) do |line, accumulator|
|
||||||
|
if line.start_with? 'Target: '
|
||||||
|
accumulator.build = line.split(' ').last.strip
|
||||||
|
elsif line.start_with? 'COLLECT_GCC'
|
||||||
|
accumulator.gcc = line.split('=').last.strip
|
||||||
|
end
|
||||||
|
end
|
||||||
|
result.tmp = TMP
|
||||||
|
result.target = target
|
||||||
|
result
|
||||||
|
end
|
||||||
|
@ -13,7 +13,7 @@ AS = 'build/rootfs/riscv32-unknown-linux-gnu/bin/as'
|
|||||||
|
|
||||||
namespace :test do
|
namespace :test do
|
||||||
test_sources = FileList['tests/vm/*.elna', 'tests/vm/*.s']
|
test_sources = FileList['tests/vm/*.elna', 'tests/vm/*.s']
|
||||||
compiler = `cabal list-bin elna`.strip
|
compiler = TMP + 'bin/elna'
|
||||||
object_directory = TMP + 'riscv/tests'
|
object_directory = TMP + 'riscv/tests'
|
||||||
root_directory = TMP + 'riscv/root'
|
root_directory = TMP + 'riscv/root'
|
||||||
executable_directory = root_directory + 'tests'
|
executable_directory = root_directory + 'tests'
|
||||||
|
24
source.elna
24
source.elna
@ -301,7 +301,7 @@ begin
|
|||||||
if token_end^ <> '\"' then
|
if token_end^ <> '\"' then
|
||||||
return input
|
return input
|
||||||
end;
|
end;
|
||||||
token_length := cast(token_end as Word) - cast(input as Word);
|
token_length := cast(token_end - input as Word);
|
||||||
current_token^.value.string_value := cast(calloc(token_length, 1) as pointer to Char);
|
current_token^.value.string_value := cast(calloc(token_length, 1) as pointer to Char);
|
||||||
|
|
||||||
is_valid := true;
|
is_valid := true;
|
||||||
@ -464,7 +464,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
write_c(' ');
|
write_c(' ');
|
||||||
|
|
||||||
i := i + sizeof(Token)
|
i := i + 1u
|
||||||
end;
|
end;
|
||||||
write_c('\n')
|
write_c('\n')
|
||||||
end;
|
end;
|
||||||
@ -555,7 +555,7 @@ begin
|
|||||||
input_pointer := skip_spaces(input_pointer);
|
input_pointer := skip_spaces(input_pointer);
|
||||||
|
|
||||||
while input_pointer^ <> '\0' do
|
while input_pointer^ <> '\0' do
|
||||||
tokens := cast(realloc(tokens, tokens_size^ + sizeof(Token)) as pointer to Token);
|
tokens := cast(reallocarray(tokens, tokens_size^ + 1u, sizeof(Token)) as pointer to Token);
|
||||||
current_token := tokens + tokens_size^;
|
current_token := tokens + tokens_size^;
|
||||||
|
|
||||||
if is_alpha(input_pointer^) or input_pointer^ = '_' then
|
if is_alpha(input_pointer^) or input_pointer^ = '_' then
|
||||||
@ -685,7 +685,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
if current_token^.kind <> 0 then
|
if current_token^.kind <> 0 then
|
||||||
tokens_size^ := tokens_size^ + sizeof(Token);
|
tokens_size^ := tokens_size^ + 1u;
|
||||||
input_pointer := skip_spaces(input_pointer)
|
input_pointer := skip_spaces(input_pointer)
|
||||||
else
|
else
|
||||||
write_s("Lexical analysis error on \"");
|
write_s("Lexical analysis error on \"");
|
||||||
@ -712,16 +712,16 @@ begin
|
|||||||
result^.name := cast(malloc(strlen(tokens^^.value.string_value)) as pointer to Char);
|
result^.name := cast(malloc(strlen(tokens^^.value.string_value)) as pointer to Char);
|
||||||
strcpy(result^.name, tokens^^.value.string_value);
|
strcpy(result^.name, tokens^^.value.string_value);
|
||||||
|
|
||||||
tokens^ := tokens^ + sizeof(Token) * 2u;
|
tokens^ := tokens^ + 2u;
|
||||||
tokens_size := tokens_size - sizeof(Token) * 2u;
|
tokens_size := tokens_size - 2u;
|
||||||
|
|
||||||
write_s(result^.name);
|
write_s(result^.name);
|
||||||
write_c('\n');
|
write_c('\n');
|
||||||
|
|
||||||
result^.body := parse_literal(tokens, tokens_size);
|
result^.body := parse_literal(tokens, tokens_size);
|
||||||
|
|
||||||
tokens^ := tokens^ + sizeof(Token) * 2u;
|
tokens^ := tokens^ + 2u;
|
||||||
tokens_size := tokens_size - sizeof(Token) * 2u;
|
tokens_size := tokens_size - 2u;
|
||||||
|
|
||||||
return result
|
return result
|
||||||
end;
|
end;
|
||||||
@ -737,14 +737,14 @@ begin
|
|||||||
result^.constants.count := 0u;
|
result^.constants.count := 0u;
|
||||||
|
|
||||||
if tokens^^.kind = TOKEN_CONST then
|
if tokens^^.kind = TOKEN_CONST then
|
||||||
tokens^ := tokens^ + sizeof(Token);
|
tokens^ := tokens^ + 1;
|
||||||
tokens_size^ := tokens_size^ - sizeof(Token);
|
tokens_size^ := tokens_size^ - 1u;
|
||||||
|
|
||||||
while tokens_size^ > 0u and tokens^^.kind = TOKEN_IDENTIFIER do
|
while tokens_size^ > 0u and tokens^^.kind = TOKEN_IDENTIFIER do
|
||||||
result^.constants.elements := cast(
|
result^.constants.elements := cast(
|
||||||
reallocarray(result^.constants.elements, result^.constants.count + 1u, sizeof(pointer to ConstantDefinition))
|
reallocarray(result^.constants.elements, result^.constants.count + 1u, sizeof(pointer to ConstantDefinition))
|
||||||
as pointer to pointer to ConstantDefinition);
|
as pointer to pointer to ConstantDefinition);
|
||||||
current_constant := result^.constants.elements + result^.constants.count * sizeof(pointer to ConstantDefinition);
|
current_constant := result^.constants.elements + result^.constants.count;
|
||||||
|
|
||||||
result^.constants.count := result^.constants.count + 1u;
|
result^.constants.count := result^.constants.count + 1u;
|
||||||
|
|
||||||
@ -768,7 +768,7 @@ begin
|
|||||||
result^.input := nil;
|
result^.input := nil;
|
||||||
|
|
||||||
while i < argc do
|
while i < argc do
|
||||||
parameter := argv + i * cast(sizeof(pointer to Char) as Int);
|
parameter := argv + i;
|
||||||
|
|
||||||
if strcmp(parameter^, "--tokenize") = 0 then
|
if strcmp(parameter^, "--tokenize") = 0 then
|
||||||
result^.tokenize := true
|
result^.tokenize := true
|
||||||
|
204
tools/init.c
Normal file
204
tools/init.c
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/reboot.h>
|
||||||
|
|
||||||
|
#define FILENAME_BUFFER_SIZE 256
|
||||||
|
|
||||||
|
size_t read_command(int descriptor, char *command_buffer)
|
||||||
|
{
|
||||||
|
ssize_t bytes_read = 0;
|
||||||
|
size_t read_so_far = 0;
|
||||||
|
|
||||||
|
while ((bytes_read = read(descriptor, command_buffer + read_so_far, FILENAME_BUFFER_SIZE - read_so_far - 1)) > 0)
|
||||||
|
{
|
||||||
|
read_so_far += bytes_read;
|
||||||
|
if (read_so_far >= FILENAME_BUFFER_SIZE - 1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
command_buffer[read_so_far] = 0;
|
||||||
|
return read_so_far;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum status
|
||||||
|
{
|
||||||
|
status_success,
|
||||||
|
status_failure,
|
||||||
|
status_warning,
|
||||||
|
status_fatal
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int make_path(char *destination, const char *directory, const char *filename, const char *extension)
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
for (; i < FILENAME_BUFFER_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (directory[i] == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
destination[i] = directory[i];
|
||||||
|
}
|
||||||
|
for (int j = 0; i < FILENAME_BUFFER_SIZE; i++, j++)
|
||||||
|
{
|
||||||
|
if (filename[j] == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
destination[i] = filename[j];
|
||||||
|
}
|
||||||
|
if (extension == NULL)
|
||||||
|
{
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
for (int j = 0; i < FILENAME_BUFFER_SIZE; i++, j++)
|
||||||
|
{
|
||||||
|
if (extension[j] == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
destination[i] = extension[j];
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
destination[i] = 0;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum status run_test(const char *file_entry_name)
|
||||||
|
{
|
||||||
|
printf("Running %s. ", file_entry_name);
|
||||||
|
|
||||||
|
char filename[FILENAME_BUFFER_SIZE];
|
||||||
|
char command_buffer[FILENAME_BUFFER_SIZE];
|
||||||
|
char file_buffer[256];
|
||||||
|
int pipe_ends[2];
|
||||||
|
|
||||||
|
if (pipe(pipe_ends) == -1)
|
||||||
|
{
|
||||||
|
perror("pipe");
|
||||||
|
return status_fatal;
|
||||||
|
}
|
||||||
|
make_path(filename, "./tests/", file_entry_name, NULL);
|
||||||
|
|
||||||
|
int child_pid = fork();
|
||||||
|
if (child_pid == -1)
|
||||||
|
{
|
||||||
|
return status_fatal;
|
||||||
|
}
|
||||||
|
else if (child_pid == 0)
|
||||||
|
{
|
||||||
|
close(STDIN_FILENO);
|
||||||
|
close(STDERR_FILENO);
|
||||||
|
close(pipe_ends[0]); // Close the read end.
|
||||||
|
|
||||||
|
if (dup2(pipe_ends[1], STDOUT_FILENO) == -1)
|
||||||
|
{
|
||||||
|
perror("dup2");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
execl(filename, filename);
|
||||||
|
perror("execl");
|
||||||
|
}
|
||||||
|
close(STDOUT_FILENO);
|
||||||
|
close(pipe_ends[1]);
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
close(pipe_ends[1]); // Close the write end.
|
||||||
|
read_command(pipe_ends[0], command_buffer);
|
||||||
|
close(pipe_ends[0]);
|
||||||
|
|
||||||
|
int wait_status = 0;
|
||||||
|
|
||||||
|
make_path(filename, "./expectations/", file_entry_name, ".txt");
|
||||||
|
|
||||||
|
FILE *expectation_descriptor = fopen(filename, "r");
|
||||||
|
|
||||||
|
if (expectation_descriptor == NULL)
|
||||||
|
{
|
||||||
|
return status_warning;
|
||||||
|
}
|
||||||
|
size_t read_from_file = fread(file_buffer, 1, sizeof(file_buffer) - 1, expectation_descriptor);
|
||||||
|
fclose(expectation_descriptor);
|
||||||
|
|
||||||
|
file_buffer[read_from_file] = 0;
|
||||||
|
for (unsigned int i = 0; ; ++i)
|
||||||
|
{
|
||||||
|
if (command_buffer[i] == 0 && file_buffer[i] == 0)
|
||||||
|
{
|
||||||
|
fwrite("\n", 1, 1, stdout);
|
||||||
|
return status_success;
|
||||||
|
}
|
||||||
|
else if (command_buffer[i] != file_buffer[i])
|
||||||
|
{
|
||||||
|
printf("Failed. Got:\n%s", command_buffer);
|
||||||
|
return status_failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct summary
|
||||||
|
{
|
||||||
|
size_t total;
|
||||||
|
size_t failure;
|
||||||
|
size_t success;
|
||||||
|
};
|
||||||
|
|
||||||
|
void walk()
|
||||||
|
{
|
||||||
|
DIR *directory_stream = opendir("./tests");
|
||||||
|
struct dirent *file_entry;
|
||||||
|
|
||||||
|
struct summary test_summary = { .total = 0, .failure = 0, .success = 0 };
|
||||||
|
|
||||||
|
while ((file_entry = readdir(directory_stream)) != NULL)
|
||||||
|
{
|
||||||
|
if (file_entry->d_name[0] == '.')
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
++test_summary.total;
|
||||||
|
switch (run_test(file_entry->d_name))
|
||||||
|
{
|
||||||
|
case status_failure:
|
||||||
|
++test_summary.failure;
|
||||||
|
break;
|
||||||
|
case status_success:
|
||||||
|
++test_summary.success;
|
||||||
|
break;
|
||||||
|
case status_warning:
|
||||||
|
break;
|
||||||
|
case status_fatal:
|
||||||
|
goto end_walk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("Successful: %lu, Failed: %lu, Total: %lu.\n",
|
||||||
|
test_summary.success, test_summary.failure, test_summary.total);
|
||||||
|
end_walk:
|
||||||
|
closedir(directory_stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int dev_console = open("/dev/console", O_WRONLY);
|
||||||
|
if (dev_console != -1)
|
||||||
|
{
|
||||||
|
dup2(dev_console, STDOUT_FILENO);
|
||||||
|
walk();
|
||||||
|
close(dev_console);
|
||||||
|
}
|
||||||
|
sync();
|
||||||
|
reboot(RB_POWER_OFF);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user