Coder Social home page Coder Social logo

zaskar9 / oberon-lang Goto Github PK

View Code? Open in Web Editor NEW
15.0 4.0 2.0 1.32 MB

An LLVM frontend for the Oberon programming language

License: MIT License

CMake 1.52% C++ 69.40% Assembly 1.92% C 3.50% Modula-2 20.19% Makefile 0.65% Batchfile 0.08% Shell 0.03% Python 2.63% Dockerfile 0.08%
compiler llvm llvm-frontend oberon oberon-compiler programming-language

oberon-lang's Introduction

Github Actions Badge Github Actions Badge Github Actions Badge Github Actions Badge

A Compiler for the Oberon Programming Language

The Oberon programming language was proposed in 1987 by Niklaus Wirth as a successor to Pascal and Modula-2. Due to this lineage, Oberon is an ALGOL-like language with strong (static and dynamic) typing discipline. The programming paradigm of Oberon can be classified as imperative, structured, modular, and object-oriented.

About

This project implements a compiler for the Oberon programming language as a frontend to the LLVM Compiler Infrastructure. It is written in C++ and originated as project accompanying the MSc course "Compiler Construction" taught at the University of Konstanz. As a consequence, this compiler originally only targeted the Oberon-0 subset of the language, as described in Niklaus Wirth's book "Compiler Construction" (Chapter 6, pp. 30-32). Since then, the supported subset of the Oberon has been continuously extended with the goal to eventually cover the full language specification as described in the latest version of the Oberon Language Report. In addition to these "official" extensions, other features were added to the supported dialect of the Oberon programming language. These feature were either inspired by convenience, such as interfacing with standard libraries, or by the compiler author's nostalgia of learning Turbo Pascal 6.0 as his first programming language at high school. A description of the currently supported Oberon dialect in terms of syntax and semantics (of unofficial features) can be found in the Wiki section of this project repository.

Dependencies and Toolchains

Owing to its origin as a course project, care has been taken that the provided C++ sourcecode can be compiled on different operating systems and with different toolchains. Currently the sourcecode only depends on Boost and LLVM. As of August 2023, the following configurations are tested and known to work.

macOS Windows MSYS2 (CLANG64) Linux (Ubuntu)
Boost 1.83.0 1.83.0 1.85.0 1.74.0
LLVM 17.0.6 17.0.2 18.1.4 17.0.0
CMake 3.28.0 3.27.0 3.29.3 3.26.0
CXX LLVM Clang 17.0.6 CL 19.38.33133 LLVM Clang 18.1.4 GCC 11.4.0

For macOS and Linux, both the x64 and the arm64 version have been tested. Full support for Windows (arm64) is currently under development. Detailed instruction on how to build the Oberon compiler and its dependencies can be found in the Wiki section of this project repository.

Getting started

See the Documentation pages.

oberon-lang's People

Contributors

leowoerteler avatar tenko avatar zaskar9 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

tenko gmh5225

oberon-lang's Issues

Array passed as argument is shorten

The following code:

MODULE Test;
IMPORT Out;
VAR
str : ARRAY 25 OF CHAR;

PROCEDURE Capacity(str : ARRAY OF CHAR): LONGINT;
BEGIN RETURN LEN(str)
END Capacity;

PROCEDURE CapacityVar(VAR str : ARRAY OF CHAR): LONGINT;
BEGIN RETURN LEN(str)
END CapacityVar;

BEGIN
Out.Long(LEN(str), 0); Out.Ln();
Out.Long(Capacity(str), 0); Out.Ln();
Out.Long(CapacityVar(str), 0); Out.Ln();
str := "test";
Out.Long(LEN(str), 0); Out.Ln();
Out.Long(Capacity(str), 0); Out.Ln();
Out.Long(CapacityVar(str), 0); Out.Ln()
END Test.

Outputs:

25
25
25
25
5
5

The array seems to be changed when passed as argument.

Output file argument not working

I added/replaced the following lines to src\codegen\llvm\LLVMCodeGen.cpp from line 254:

std::string name = config_.getOutputFile();
if (name == "") {
name = path.replace_extension(ext).string();
}

This seems to fix the issue.

Making Unit Tests Work!

This issue is intended to track the current state of the unit tests. Below is a summary of all tests that need work. They fall into the Unsupported, Failed, and Unexpectedly Passed categories. For every test, there is a brief summary of the problem or a description of the feature that is missing.

Unsupported

  • loop_1.mod: LOOP and EXIT statement missing โ†’ infinite loop
  • module_unterminated.mod: no terminating dot at end of module โ†’ infinite loop
  • procedure_missing_return.mod: no error on missing/unreachable RETURN

Failed

  • arithmetic_12.mod: data type BYTE missing
  • array_5.mod: data type PROCEDURE missing
  • case_1.mod: CASE statement missing
  • loop_2.mod: LOOP statement missing
  • system_6.mod: problem in Out.Real (NaN instead of INF/-INF)
  • system_7.mod: problem with signedness of 64-bit hexadecimal values
  • fail_on_extra_semicolon.mod: expected fail

Unexpectedly Passed

  • arithmetic_3.mod: should trigger integer overflow trap
  • arithmetic_5.mod: divisor cannot be negative (cf. O07.8.2.2)
  • arithmetic_6.mod: divisor cannot be negative (cf. O07.8.2.2)
  • arithmetic_9.mod: should trigger integer overflow trap
  • arithmetic_10.mod: should trigger division by zero trap
  • arithmetic_11.mod: Oberon has no implicit type conversions, should be disabled by default
  • arithmetic_15.mod: should trigger division by zero trap
  • array_6.mod: should trigger out-of-bounds trap
  • procedure_4.mod: Oberon-07 scoping rules not enforced: intermediate declarations cannot be accessed in nested procedures
  • if_with_trailing_end.mod: parser does not complain about superfluous END in IF-ELSIF-ELSE statement

Overall State

  Unsupported        :  2
  Passed             : 68
  Expectedly Failed  :  7
  Failed             :  5
  Unexpectedly Passed:  9

endian.h not found on Windows platform

Added the following to ieee754.h:

#elif (defined(_WIN32) || defined(_WIN64))
#include <winsock2.h>
#ifdef GNUC
#include <sys/param.h>
#endif

Fixes compilation.

Export of CHAR constants not supported

The following code:

MODULE Char ;
CONST
NUL* = 00X;
TAB* = 09X;
LF* = 0AX;
CR* = 0DX;
SPC* = 020X;
END Char.

Fails with:

sym\Char.smb: error: Cannot export constant NUL*.
sym\Char.smb: error: Cannot export constant TAB*.
sym\Char.smb: error: Cannot export constant LF*.
sym\Char.smb: error: Cannot export constant CR*.
sym\Char.smb: error: Cannot export constant SPC*.
Compilation failed: 5 error(s), 0 warning(s), 0 message(s).

It seems CHAR is not supported in symbol files.

Unable to execute unit tests

The unit tests fail to execute when I execute the following commands on my MacBook (macOS Sonoma 14.3.1).

cmake .. -G "Unix Makefiles"
make test

I get the following error message.

usage: lit [-h] [--version] [-j N] [--config-prefix NAME] [-D NAME=VAL] [-q] [-s] [-v] [-vv] [-a] [-o PATH]
           [--no-progress-bar] [--show-excluded] [--show-skipped] [--show-unsupported] [--show-pass]
           [--show-flakypass] [--show-xfail] [--path PATH] [--vg] [--vg-leak] [--vg-arg ARG] [--time-tests]
           [--no-execute] [--xunit-xml-output XUNIT_XML_OUTPUT] [--resultdb-output RESULTDB_OUTPUT]
           [--time-trace-output TIME_TRACE_OUTPUT] [--timeout MAXINDIVIDUALTESTTIME] [--max-failures MAX_FAILURES]
           [--allow-empty-runs] [--ignore-fail] [--max-tests N] [--max-time N] [--order {lexical,random,smart}]
           [--shuffle] [-i] [--filter REGEX] [--filter-out REGEX] [--xfail LIST] [--xfail-not LIST] [--num-shards M]
           [--run-shard N] [--debug] [--show-suites] [--show-tests] [--show-used-features]
           TEST_PATH [TEST_PATH ...]
lit: error: argument -s/--succinct: ignored explicit argument ' -v'
make[3]: *** [test/CMakeFiles/test] Error 2
make[2]: *** [test/CMakeFiles/test.dir/all] Error 2
make[1]: *** [test/CMakeFiles/test.dir/rule] Error 2
make: *** [test] Error 2

I am using lit 17.0.6 and filecheck 17.0.6.

Furthermore, when I try to execute a single test, for example with lit -a codegen/array_1.mod, I also get an error that seems to indicate that the lib and include paths are concatenated the with ; (which is platform-specific to Windows). On Linux and macOS, these paths should be concatenated with :.

CHAR variable not treated equal to CHAR literal

Consider the following code:

MODULE Test4;
(* Fails to compile in line 38 *)

PROCEDURE Length (str: ARRAY OF CHAR) : LONGINT;
VAR i: LONGINT;
BEGIN
    i := 0;
    WHILE (i < LEN(str)) & (str[i] # 00X) DO INC(i) END;
    RETURN i
END Length;

PROCEDURE Append(VAR dst : ARRAY OF CHAR; src : ARRAY OF CHAR);
VAR
    i, n: LONGINT;
    ch : CHAR;
BEGIN
    n := Length(dst);
    i := 0;
    ch := src[i];
    WHILE (ch # 00X) & (i < LEN(src)) & (i + n < LEN(dst)) DO
        dst[i + n] := ch;
        INC(i);
        ch := src[i]
    END
END Append;

PROCEDURE Test();
VAR
    str : ARRAY 32 OF CHAR;
    sch : ARRAY 1 OF CHAR;
    ch : CHAR;
BEGIN
    str := "test";
    sch := "1";
    ch := "3";
    Append(str, sch);
    Append(str, "2"); (* Char literal works *)
    Append(str, ch) (* Fails. Should probably work? *)
END Test;

BEGIN
    Test()
END Test4.

Should this work?

Bug in name mangling of (un)nested procedures

Consider the following code:

MODULE Test;

PROCEDURE Run1();
VAR   
    str : ARRAY 25 OF CHAR;
    PROCEDURE Assert(b: BOOLEAN);
    BEGIN
        ASSERT(b)
    END Assert;
BEGIN
    str := "test1";
END Run1;

PROCEDURE Run2();
VAR   
    str : ARRAY 25 OF CHAR;
    PROCEDURE Assert(b: BOOLEAN);
    BEGIN
        ASSERT(b)
    END Assert;
BEGIN
    str := "test2";
END Run2;

BEGIN
    Run1();
    Run2()
END Test.

This fails to compile with the following error:

Test.ob07:17:5: error: Function Test__Assert already defined.

Can not build on Linux

$ mkdir build
$ cd build
$ cmake .. -G "Unix Makefiles"
-- The C compiler identification is GNU 13.2.1
-- The CXX compiler identification is GNU 13.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found Boost: /usr/lib/cmake/Boost-1.83.0/BoostConfig.cmake (found version "1.83.0") found components: filesystem program_options 
-- Performing Test HAVE_FFI_CALL
-- Performing Test HAVE_FFI_CALL - Success
-- Found FFI: /usr/lib/libffi.so  
-- Performing Test Terminfo_LINKABLE
-- Performing Test Terminfo_LINKABLE - Success
-- Found Terminfo: /usr/lib/libtinfo.so  
-- Found ZLIB: /usr/lib/libz.so (found version "1.3")  
-- Found zstd: /usr/lib/libzstd.so  
-- Found LibXml2: /usr/lib/libxml2.so (found version "2.12.3") 
-- Found LLVM: 16.0.6
-- Found Boost: /usr/lib/cmake/Boost-1.83.0/BoostConfig.cmake (found version "1.83.0") found components: filesystem 
-- Configuring done (0.6s)
-- Generating done (0.0s)
-- Build files have been written to: /home/user/install/oberon-lang/build

$ make
[  1%] Building CXX object src/CMakeFiles/oberon-lang.dir/main.cpp.o
[  3%] Building CXX object src/CMakeFiles/oberon-lang.dir/logging/Logger.cpp.o
[  5%] Building CXX object src/CMakeFiles/oberon-lang.dir/scanner/Scanner.cpp.o
[  6%] Building CXX object src/CMakeFiles/oberon-lang.dir/scanner/Token.cpp.o
[  8%] Building CXX object src/CMakeFiles/oberon-lang.dir/scanner/LiteralToken.cpp.o
[ 10%] Building CXX object src/CMakeFiles/oberon-lang.dir/scanner/IdentToken.cpp.o
[ 11%] Building CXX object src/CMakeFiles/oberon-lang.dir/scanner/UndefinedToken.cpp.o
[ 13%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/Ident.cpp.o
[ 15%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/Selector.cpp.o
[ 16%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/NodeVisitor.cpp.o
[ 18%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/Node.cpp.o
[ 20%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/ExpressionNode.cpp.o
[ 22%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/TypeNode.cpp.o
[ 23%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/ArrayTypeNode.cpp.o
[ 25%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/BasicTypeNode.cpp.o
[ 27%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/ProcedureTypeNode.cpp.o
[ 28%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/RecordTypeNode.cpp.o
[ 30%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/PointerTypeNode.cpp.o
[ 32%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/BlockNode.cpp.o
[ 33%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/ModuleNode.cpp.o
[ 35%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/ProcedureNode.cpp.o
[ 37%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/DeclarationNode.cpp.o
[ 38%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/NodeReference.cpp.o
[ 40%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/StatementNode.cpp.o
[ 42%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/AssignmentNode.cpp.o
[ 44%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/IfThenElseNode.cpp.o
[ 45%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/LoopNode.cpp.o
[ 47%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/StatementSequenceNode.cpp.o
[ 49%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/ImportNode.cpp.o
[ 50%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/ast/NodePrettyPrinter.cpp.o
[ 52%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/symtab/SymbolTable.cpp.o
[ 54%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/symtab/Scope.cpp.o
[ 55%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/symtab/SymbolFile.cpp.o
[ 57%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/symtab/SymbolExporter.cpp.o
[ 59%] Building CXX object src/CMakeFiles/oberon-lang.dir/data/symtab/SymbolImporter.cpp.o
[ 61%] Building CXX object src/CMakeFiles/oberon-lang.dir/parser/Parser.cpp.o
[ 62%] Building CXX object src/CMakeFiles/oberon-lang.dir/system/OberonSystem.cpp.o
[ 64%] Building CXX object src/CMakeFiles/oberon-lang.dir/system/PredefinedProcedure.cpp.o
[ 66%] Building CXX object src/CMakeFiles/oberon-lang.dir/analyzer/Analyzer.cpp.o
[ 67%] Building CXX object src/CMakeFiles/oberon-lang.dir/analyzer/SemanticAnalysis.cpp.o
[ 69%] Building CXX object src/CMakeFiles/oberon-lang.dir/analyzer/LambdaLifter.cpp.o
[ 71%] Building CXX object src/CMakeFiles/oberon-lang.dir/codegen/CodeGen.cpp.o
[ 72%] Building CXX object src/CMakeFiles/oberon-lang.dir/codegen/llvm/LLVMIRBuilder.cpp.o
[ 74%] Building CXX object src/CMakeFiles/oberon-lang.dir/codegen/llvm/LLVMCodeGen.cpp.o
[ 76%] Building CXX object src/CMakeFiles/oberon-lang.dir/compiler/CompilerFlags.cpp.o
[ 77%] Building CXX object src/CMakeFiles/oberon-lang.dir/compiler/CompilationStatus.cpp.o
[ 79%] Building CXX object src/CMakeFiles/oberon-lang.dir/compiler/Compiler.cpp.o
[ 81%] Linking CXX executable oberon-lang
/usr/bin/ld: cannot find -lLLVMCore: No such file or directory
/usr/bin/ld: cannot find -lLLVMPasses: No such file or directory
/usr/bin/ld: cannot find -lLLVMAArch64CodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMAArch64AsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMAArch64Desc: No such file or directory
/usr/bin/ld: cannot find -lLLVMAArch64Disassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMAArch64Info: No such file or directory
/usr/bin/ld: cannot find -lLLVMAArch64Utils: No such file or directory
/usr/bin/ld: cannot find -lLLVMAMDGPUCodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMAMDGPUAsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMAMDGPUDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMAMDGPUDisassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMAMDGPUInfo: No such file or directory
/usr/bin/ld: cannot find -lLLVMAMDGPUUtils: No such file or directory
/usr/bin/ld: cannot find -lLLVMARMCodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMARMAsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMARMDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMARMDisassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMARMInfo: No such file or directory
/usr/bin/ld: cannot find -lLLVMARMUtils: No such file or directory
/usr/bin/ld: cannot find -lLLVMAVRCodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMAVRAsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMAVRDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMAVRDisassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMAVRInfo: No such file or directory
/usr/bin/ld: cannot find -lLLVMBPFCodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMBPFAsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMBPFDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMBPFDisassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMBPFInfo: No such file or directory
/usr/bin/ld: cannot find -lLLVMHexagonCodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMHexagonAsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMHexagonDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMHexagonDisassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMHexagonInfo: No such file or directory
/usr/bin/ld: cannot find -lLLVMLanaiCodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMLanaiAsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMLanaiDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMLanaiDisassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMLanaiInfo: No such file or directory
/usr/bin/ld: cannot find -lLLVMLoongArchCodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMLoongArchAsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMLoongArchDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMLoongArchDisassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMLoongArchInfo: No such file or directory
/usr/bin/ld: cannot find -lLLVMMipsCodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMMipsAsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMMipsDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMMipsDisassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMMipsInfo: No such file or directory
/usr/bin/ld: cannot find -lLLVMMSP430CodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMMSP430AsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMMSP430Desc: No such file or directory
/usr/bin/ld: cannot find -lLLVMMSP430Disassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMMSP430Info: No such file or directory
/usr/bin/ld: cannot find -lLLVMNVPTXCodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMNVPTXDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMNVPTXInfo: No such file or directory
/usr/bin/ld: cannot find -lLLVMPowerPCCodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMPowerPCAsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMPowerPCDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMPowerPCDisassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMPowerPCInfo: No such file or directory
/usr/bin/ld: cannot find -lLLVMRISCVCodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMRISCVAsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMRISCVDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMRISCVDisassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMRISCVInfo: No such file or directory
/usr/bin/ld: cannot find -lLLVMSparcCodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMSparcAsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMSparcDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMSparcDisassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMSparcInfo: No such file or directory
/usr/bin/ld: cannot find -lLLVMSystemZCodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMSystemZAsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMSystemZDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMSystemZDisassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMSystemZInfo: No such file or directory
/usr/bin/ld: cannot find -lLLVMVECodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMVEAsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMVEDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMVEDisassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMVEInfo: No such file or directory
/usr/bin/ld: cannot find -lLLVMWebAssemblyCodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMWebAssemblyAsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMWebAssemblyDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMWebAssemblyDisassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMWebAssemblyInfo: No such file or directory
/usr/bin/ld: cannot find -lLLVMWebAssemblyUtils: No such file or directory
/usr/bin/ld: cannot find -lLLVMX86CodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMX86AsmParser: No such file or directory
/usr/bin/ld: cannot find -lLLVMX86Desc: No such file or directory
/usr/bin/ld: cannot find -lLLVMX86Disassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMX86Info: No such file or directory
/usr/bin/ld: cannot find -lLLVMXCoreCodeGen: No such file or directory
/usr/bin/ld: cannot find -lLLVMXCoreDesc: No such file or directory
/usr/bin/ld: cannot find -lLLVMXCoreDisassembler: No such file or directory
/usr/bin/ld: cannot find -lLLVMXCoreInfo: No such file or directory
collect2: error: ld returned 1 exit status
make[2]: *** [src/CMakeFiles/oberon-lang.dir/build.make:841: src/oberon-lang] Error 1
make[1]: *** [CMakeFiles/Makefile2:104: src/CMakeFiles/oberon-lang.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

$ llvm-config --libs
-lLLVM-16

Report for Oberon compiler on x86_64 GNU/Linux

I have checked Oberon compiler.
Hello World with LLVM backend is working fine.

Linux Mint 21.2 Cinnamon
Linux laptop 5.15.0-91-generic #101-Ubuntu SMP Tue Nov 14 13:30:08 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
cmake (3.22.1-1ubuntu1.22.04.1)
libboost-all-dev (1.74.0.3ubuntu7)
llvm (1:14.0-55~exp2)
clang (1:14.0-55~exp2)
sudo apt install cmake llvm libboost-all-dev clang
cmake src
make
cp test/oberon/HelloWorld.Mod ./liboberon/
mv oberon-lang ./liboberon/
cd liboberon/
./oberon-lang --filetype ll Out.Mod
./oberon-lang --filetype ll HelloWorld.Mod
clang -o hello.elf Out.ll HelloWorld.ll
./hello.elf 
Hoi Niklaus!

Access to argc & argv

As far as I can see it seems the only cross platform way to access argc & argv is to store these variables
in the main procedure. Right now the main procedure is without arguments. This would then need to
changed and argc, argc stored in external visible variables.

Alternative access from external visible functions in similar way to outline in #46. This way the argument
can be modified by the runtime for example when running on embedded MCU in semihosting mode.

Also in the JIT mode the original argv should be modified so that perhaps all arguments after -- from the
command line is propagated to the main function.

MSYS2/CLANG64 build success and some comments

Hi,

I was able to easily build the oberon-lang repo on MSYS2/CLANG64 platform:

pacman -S mingw-w64-clang-x86_64-toolchain
pacman -S mingw-w64-clang-x86_64-boost
pacman -S mingw-w64-clang-x86_64-cmake
git clone https://github.com/zaskar9/oberon-lang.git
cd oberon-lang/
mkdir build
cd build
cmake .. -G "MSYS Makefiles"
make

Makefiles could be updated with support:

uname -s
MINGW64_NT-10.0-19045

MSYS2/CLANG64 platform is new, but seems to be stable and is an good option on the windows platform.

I was curious if I could use this compiler for embedded development and found some issues affecting this:

  • The SYSTEM module seems missing. Several procedures here is needed for direct memory access.
  • The SET type seems missing. This is useful for bit manipulation.
  • There is a trick used in with binary constants which is useful: 'SYSTEM.ADR($0808 FFFF C3C3 C3C3 FFFF$);'
  • The target triple configuration is not exposed for cross compilation.

I was thinking to build the compiler with the LLVM-embedded-toolchain-for-Arm project as the Oberon language is really suited to this role with it simplicity and limited footguns compared to well known languages :-)

Enforce position of module level VAR section?

The following gives an error undefined identifier x:

MODULE Test;

PROCEDURE Max (x, y : REAL) : REAL;
VAR ret : REAL;
BEGIN
IF x > y THEN
ret := x
ELSE
ret := y
END;
RETURN ret
END Max;

VAR
x, y, z : REAL;

BEGIN
x := -2.5;
y := 1.0;
z := Max(x, y)
END Test.

Moving the module level VAR section to top of the file fixes the
problem, but perhaps the order of declaration should be enforced here
and give another error message?

Small typo error in main.cpp

Found this when building on MSYS2:

C:/msys64/home/rute/oberon-lang/src/main.cpp:97:36: error: expected ';' at end of declaration
97 | std::string separator = ";"
| ^
| ;
1 error generated.

Undefined behavior due to nested procedure

Consider the following code (simplified larger module):

MODULE Test;
IMPORT Out;

TYPE
    TEST = 
    RECORD
        title : ARRAY 64 OF CHAR;
        tests : LONGINT
    END;
   
VAR
    test : TEST;  

PROCEDURE Length(str: ARRAY OF CHAR) : INTEGER;
VAR i: INTEGER;
BEGIN
    i := 0;
    WHILE (i < LEN(str)) & (str[i] # 00X) DO INC(i) END;
    RETURN i
END Length;

PROCEDURE FillString(VAR s : ARRAY OF CHAR);
VAR   
   i : INTEGER;
BEGIN
   i := 0;
   WHILE i < LEN(s) DO
      s[i] := CHR(SHORT(i MOD 20) + 65);
      INC(i)
   END
END FillString;

PROCEDURE Run1(VAR test: TEST);
VAR   
    str : ARRAY 257 OF CHAR;
BEGIN
    str := "test";
    Out.String("1.1 : Length(str) = "); Out.Int(Length(str), 0); Out.Ln;
    FillString(str);
    Out.String("1.2 : Length(str) = "); Out.Int(Length(str), 0); Out.Ln;
END Run1;

PROCEDURE Run2(VAR test: TEST);
VAR   
    str : ARRAY 257 OF CHAR;
    PROCEDURE Assert(b: BOOLEAN);
    BEGIN
        ASSERT(b)
    END Assert;
BEGIN
    str := "test";
    Out.String("2.1 : Length(str) = "); Out.Int(Length(str), 0); Out.Ln;
    FillString(str);
    Out.String("2.2 : Length(str) = "); Out.Int(Length(str), 0); Out.Ln;
END Run2;

PROCEDURE Run3(VAR test: TEST);
VAR   
    str : ARRAY 257 OF CHAR;
    i : LONGINT;
    res : BOOLEAN;
BEGIN
    str := "test";
    Out.String("3.1 : Length(str) = "); Out.Int(Length(str), 0); Out.Ln;
    FillString(str);
    Out.String("3.2 : Length(str) = "); Out.Int(Length(str), 0); Out.Ln;
END Run3;

BEGIN
    Run1(test);
    Run2(test);
    Run2(test)
END Test.

This outputs unexpected result:

1.1 : Length(str) = 4
1.2 : Length(str) = 257
2.1 : Length(str) = 257
2.2 : Length(str) = 257
2.1 : Length(str) = 257
2.2 : Length(str) = 257

implicit conversion error 'unsigned int' to 'long' in Sema.cpp

Windows 10 MSYS 2, LLVM version 17.0.6:

C:/msys64/home/rute/dev/oberon-lang/src/sema/Sema.cpp:659:112: error: implicit conversion changes signedness: 'unsigned int'
to 'long' [-Werror,-Wsign-conversion]
659 | assertInBounds(dynamic_cast<const IntegerLiteralNode *>(index.get()), 0, array->getDimension() - 1);
| ~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~^~~

Build report ArchLinux

Successfully built on latest ArchLinux distribution.

Version:

oberon-lang version 0.1.0
Target: x86_64-pc-linux-gnu
Includes: Boost 1.83.0, LLVM 17.0.6

Small fixes performed on src/global.h due to missing include:

#include <sstream>
#include <string>
+#include <cstdint>

Small fixes performed on src/data/ast/ASTContext.h due to missing include:

#include <string>
#include <vector>
+#include <algorithm>

Small fixes performed on src/CMakeLists.txt due to different LLVM library structure:

-    target_link_libraries(${OBERON_LANG} PRIVATE ${llvm_libs})
+    target_link_libraries(${OBERON_LANG} PRIVATE "LLVM-17")

On ArchLinux LLVM is build to a single dynamic library LLVM-17.so.
Not sure how to reliable detect this.

Small fix performed on liboberon/Makefile to proceed with the build:

-	O7CFLAGS = -q -O3 --reloc=pic -fenable-extern -fenable-varargs # --target $(TGT)
+	O7CFLAGS = -q -I. -O3 --reloc=pic -fenable-extern -fenable-varargs # --target $(TGT)
-install : dist Oberon.smb Out.smb Random.smb Math.smb Reals.smb Texts.smb
+install : dist Oberon.smb Reals.smb Texts.smb Out.smb Random.smb Math.smb

These changes are probably generic and could be added to the main repository.

Output summary from make test:

 Failed Tests (4):
   Oberon :: codegen/arithmetic_12.mod
   Oberon :: codegen/array_5.mod
   Oberon :: codegen/case_1.mod
   Oberon :: codegen/loop_2.mod
 
 Unexpectedly Passed Tests (7):
   Oberon :: codegen/arithmetic_11.mod
   Oberon :: codegen/arithmetic_15.mod
   Oberon :: codegen/arithmetic_3.mod
   Oberon :: codegen/arithmetic_5.mod
   Oberon :: codegen/arithmetic_6.mod
   Oberon :: codegen/arithmetic_9.mod
   Oberon :: codegen/procedure_4.mod

 Total Discovered Tests: 92
   Unsupported        :  2 (2.17%)
   Passed             : 70 (76.09%)
   Expectedly Failed  :  9 (9.78%)
   Failed             :  4 (4.35%)
   Unexpectedly Passed:  7 (7.61%)

Compilation error due to extra semicolon

This code fails to compile due to the extra semicolon:

MODULE Test3;
(* Fails to compile in line 15 *)
VAR
    res : LONGINT;

PROCEDURE Test() : LONGINT;
VAR i, j : LONGINT;
BEGIN
    i := 0; j := 6;
    WHILE i < 10 DO
        IF i = 8 THEN
            RETURN i
        ELSIF i  = 7 THEN
            RETURN i; (* Error triggered by this extra semicolon *)
        ELSIF i = j THEN
            RETURN i
        END;
        INC(i)
    END;
END Test;

BEGIN
    res := Test();
END Test3.

Proposal to make runtime functionality configurable.

Right now the functions createNewCall, createFreeCall in src\codegen\llvm\LLVMIRBuilder.cpp has hard coded references to malloc, free, abort and exit. This can be made more flexible by utilizing the linker support for weak symbols.

I replaced malloc with OberonRuntime_Allocate:

Value *
LLVMIRBuilder::createNewCall(TypeNode *type, llvm::Value *param) {
    auto fun = module_->getFunction("OberonRuntime_Allocate");
    if (!fun) {
        auto funTy = FunctionType::get(builder_.getPtrTy(), { builder_.getInt64Ty() }, false);
        fun = Function::Create(funTy, GlobalValue::ExternalLinkage, "OberonRuntime_Allocate", module_);
        fun->addFnAttr(Attribute::getWithAllocSizeArgs(builder_.getContext(), 0, {}));
        fun->addParamAttr(0, Attribute::NoUndef);
    }
    ...

and free with OberonRuntime_Deallocate:

Value *
LLVMIRBuilder::createFreeCall([[maybe_unused]] TypeNode *type, Value *param) {
    auto fun = module_->getFunction("OberonRuntime_Deallocate");
#ifdef _LLVM_LEGACY
    auto voidTy = PointerType::get(builder_.getVoidTy(), 0);
#else
    auto voidTy = builder_.getPtrTy();
#endif
    if (!fun) {
        auto funTy = FunctionType::get(builder_.getVoidTy(), {voidTy}, false);
        fun = Function::Create(funTy, GlobalValue::ExternalLinkage, "OberonRuntime_Deallocate", module_);
        fun->addParamAttr(0, Attribute::NoUndef);
    }
    ...

Then creates a default implementation OberonRuntimeDefault.c:

#include <stdlib.h>
#include <stdio.h>

__attribute__((weak)) void *OberonRuntime_Allocate( size_t size ) {
    printf("OberonRuntimeDefault.Allocate\n");
    return malloc(size);
}

__attribute__((weak)) void OberonRuntime_Deallocate( void *ptr ) {
    printf("OberonRuntimeDefault.Deallocate\n");
    free(ptr);
}

Functions here are decorated with the weak attribute.
This is then just compiled to a static library and works as expected when linked.

This can then exploited to replace the functionality with for example a Garbage Collector (Boehm):

#include <stdlib.h>
#include <stdio.h>
#include <gc.h>

void *OberonRuntime_Allocate( size_t size ) {
    printf("OberonRuntimeGC.Allocate\n");
    return GC_malloc(size);
}

void OberonRuntime_Deallocate( void *ptr ) {
    printf("OberonRuntimeGC.Deallocate\n");
    // Skip
}

By linking this as a static library, these definitions take precedence over the weak version.
(This could also be done with an Oberon module.)

In order for this to work as expected with the JIT implementation, default functions need to be injected.
Perhaps default functions can just be defined in the main module.

Also this can be expanded to cover putchar etc., so that the Out module can be redirected.

DIV and MOD not in line with Oberon-07 report

I found this problem with treating INTEGER as unsigned integers in order to print hex string.
The following tests module reproduce the problem:

(*
  RUN: %oberon -I "%S%{pathsep}%inc" -L "%S%{pathsep}%lib" -l oberon --run %s | filecheck %s
  Fails : Current DIV and MOD implementation is not in line with Oberon report.
          Ref. link : https://lists.inf.ethz.ch/pipermail/oberon/2019/013353.html
*)
MODULE Arithmetic17;

IMPORT Out;

(* From Texts.Mod : JG 21.11.90 / NW 11.7.90 / 24.12.95 / 22.11.10 / 18.11.2014 / 10.1.2019 / AP 15.9.20 Extended Oberon*)
PROCEDURE WriteHex* (x: INTEGER);
VAR i: INTEGER; y, base: INTEGER;
    a: ARRAY 20 OF CHAR;
BEGIN 
    i := 0; base := 16;
    REPEAT
        y := x MOD base;
        IF y < 10 THEN
            a[i] := CHR(SHORT(y) + 30H)
        ELSE
            a[i] := CHR(SHORT(y) + 37H)
        END;
        x := x DIV base; INC(i)
    UNTIL i = 8;
    REPEAT DEC(i); Out.Char(a[i]) UNTIL i = 0;
    Out.Ln;
END WriteHex;

PROCEDURE Test();
BEGIN
  WriteHex(07FFFFFFFH); (* OK *)
  WriteHex(08FFFFFFFH); (* Fails due to sign bit *)
  WriteHex(0FFFFFFFFH); (* Fails due to sign bit *)
  Out.Int(5 DIV 3, 0); Out.Ln;
  Out.Int(5 MOD 3, 0); Out.Ln;
  Out.Int((-5) DIV 3, 0); Out.Ln;
  Out.Int((-5) MOD 3, 0); Out.Ln;
  Out.Int(-5 DIV 3, 0); Out.Ln; (* expected : -1,  same as -(5 DIV 3) *)
  Out.Int(-5 MOD 3, 0); Out.Ln; (* expected : -2,  same as -(5 MOD 3) *)
END Test;

BEGIN
    Test
END Arithmetic17.
(*
    CHECK: 7FFFFFFF
    CHECK: 8FFFFFFF
    CHECK: FFFFFFFF
    CHECK: 1
    CHECK: 2
    CHECK: -2
    CHECK: 1
    CHECK: -1
    CHECK: -2
*)

I believe the DIV and MOD operators is defined in this way in Oberon in order to be used for integers treated as
unsigned values. Ref. the WriteHex procedure.

The above expected values was checked with Extended Oberon on an emulator.

The Oberon-07 behaviour of DIV and MOD implementation with C/C++ operators which I guess LLVM is based
on is described in this post and should be straightforward to implement.

However there is also an related issue with mixed type integer operations which is currently allowed.
This will sign extend the smaller type and the calculation could fail.

Also if the WriteHex had an LONGINT argument then passing an INTEGER would be sign extended to LONGINT and the procedure will print the wrong value if the INTEGER value had the sign bit set.

This type inclusion was removed in the Oberon-07 report except for BYTE type which is treated as a sub-range of INTEGER.

Maybe we should add an explicit CAST or VAL procedure?

EDIT : I am currently busy porting code and unittests from the XDS library to oberon-lang compiler.
Can look at fix in the end of the week.
EDIT : Adde note on BYTE type.

Crash with assignment of string literal reference returned from procedure

This is not so easy to reproduce.
I have a custom procedure defined which return a string literal.

From OberonSystem.cpp:

this->createProcedure(ProcKind::COMPILER_ENV, "Env", {{stringType, false}}, stringType, false, true);

And in LLVMIRBuilder.cpp:

Value *
LLVMIRBuilder::createCompilerEnvCall(vector<unique_ptr<ExpressionNode>> &actuals) {
    auto param = actuals[0].get();
    auto arg = dynamic_cast<StringLiteralNode*>(param);
    if (!arg) {
        logger_.error(param->pos(), "expected constant string");
        return value_;
    }
    std::string val;
    auto str = arg->value();
    if (str == "HOST") {
        val = sys::getProcessTriple();
    } else if (str == "FILE") {
        val = param->pos().fileName;
    } else {
        logger_.error(param->pos(), "unknown argumen '" + str + "'");
        return value_;
    }
    auto len = val.size() + 1;
    auto type = StructType::get(builder_.getInt64Ty(), ArrayType::get(builder_.getInt8Ty(), len));
    value_ = strings_[val];
    if (!value_) {
        auto initializer = ConstantStruct::get(type, {builder_.getInt64(len), ConstantDataArray::getRaw(val, len, builder_.getInt8Ty())});
        auto str = new GlobalVariable(*module_, type, true, GlobalValue::InternalLinkage, initializer, ".str");
        str->setAlignment(module_->getDataLayout().getPrefTypeAlign(type));
        strings_[val] = str;
        value_ = strings_[val];
    }
    return value_;
}

The following works until the code crashes on assignment in global scope.

MODULE Test;
IMPORT SYSTEM, COMPILER, RTS := RUNTIME;

VAR
    str : ARRAY 64 OF CHAR;

PROCEDURE test(s : ARRAY OF CHAR);
BEGIN
    str := s;
END test;

BEGIN
    RTS.Println(COMPILER.Env("FILE")); (* OK *)
    test(COMPILER.Env("FILE")); (* OK *)
    RTS.Println(str);
    str := COMPILER.Env("FILE"); (* Crash *)
    RTS.Println(str);
END Test.

Assignment in the test procedure works.

Crash triggered by accessing exported variable

While porting some code and unittests from XDS I triggered a crash in the compiler and
created a test module:

MODULE M;

CONST
    CCHAR* = 041X;
    CINT* = 100;
    CLINT* = 0FFFFFFFFFFFFFFFFH;
    CREAL* = 1.1;
    CREALMAX* = 1.7976931348623158E308;
    CBOOL* = TRUE;
    CSET* = {0, 31};
    CSTR* = "testing123";

VAR
    C* : CHAR;
    (* X* : BYTE; Not supported *)
    I* : INTEGER;
    LI* : LONGINT;
    R* : REAL;
    LR* : LONGREAL;
    B* : BOOLEAN;
    S* : SET;
    STR* : ARRAY 25 OF CHAR;

BEGIN
    C := CCHAR;
    I := CINT;
    LI := CLINT;
    R := CREAL;
    LR := CREALMAX;
    B := CBOOL;
    S := CSET;
    STR := CSTR
END M.

And a main module:

MODULE TestImport;
IMPORT M, Out;

VAR
    c : CHAR;
    i : INTEGER;
    l : LONGINT;
    r : REAL;
    lr : LONGREAL;
    b : BOOLEAN;
    s : SET;
    str : ARRAY 25 OF CHAR;
BEGIN
    (* Test CONST *)
    c := M.CCHAR;
    Out.Char(c); Out.Ln;
    i := M.CINT;
    Out.Int(i, 0); Out.Ln;
    i := M.CLINT;
    Out.Int(i, 0); Out.Ln;
    l := M.CLINT;
    Out.Long(l, 0); Out.Ln;
    r := M.CREAL;
    Out.Real(r, 9); Out.Ln;
    lr := M.CREAL;
    Out.LongReal(lr, 17); Out.Ln;
    r := SHORT(M.CREALMAX); (* SHORT needed here *)
    Out.Real(r, 9); Out.Ln;
    lr := M.CREALMAX;
    Out.LongReal(lr, 17); Out.Ln;
    b := M.CBOOL;
    Out.Int(ORD(b), 0); Out.Ln;
    s := M.CSET;
    Out.Set(s); Out.Ln;
    str := M.CSTR;
    Out.String(str); Out.Ln;
    (* Test VAR *)
    (* c := M.C *) (* This gives segmentation fault *)
END TestImport.

This creates the following output:

A
100
-1
-1
 1.10E+00
 1.100000024E+000
      INF
 1.797693135E+308
1
{ 0 31 }
testing123
  1. I guess integer constants is always LONGINT, so that the problem with sign extension where the integer value
    is treated as an unsigned value is not a problem here.
  2. The decimal float value 1.1 is inexact represented in base 2 floating point representation and the constant will
    have different value depending on whether the type is REAL or LONGREAL.
    The Oberon-02 report solves this with creating an additional float format were 1.1 and 1.1E0 is REAL, while 1.1D0 is LONGREAL.
  3. The last line commented out triggers the crash here.
  4. Oberon-07 limit exported constant to integer type. e.g. REAL not allowed to be exported. This is probably done to keep the compiler as simple as possible and I do not see any logical reason for that.
  5. Exported variables in Oberon-07 is read only. This makes sense as it forces the module state to be encapsulated.

EDIT : Added notes on Oberon-07.

Cross platform support

I was thinking how to support the diverse number of target the LLVM infrastructure is supporting.
There is targets for 64bit, 32bit and 16bit. 8bit target (AVR) is currently marked as "experimental".

(8bit may sound crazy, but these platforms is actually in use very
much today in new designs as it replaces transistor/CMOS logic due
to the low cost (order of 30 cents). Your christmas lights is probably
run on one of these.)

We have the type CHAR and BYTE which should be fixed 8bit.

Then there is SHORTINT, INTEGER and LONGINT. I believe it makes
sense to let LONGINT follow the platform pointer size and array size
limit. The LEN procedure and SYSTEM.ADR all return a LONGINT.

SET should probably follow LONGINT size?

Proposal:

Platform 8Bit 16Bit 32Bit 64Bit
BYTE 8bit 8bit 8bit 8bit
CHAR 8bit 8bit 8bit 8bit
SHORTINT 8bit 8bit 8bit 8bit
INTEGER 16bit 16bit 16bit 32bit
LONGINT 16bit 16bit 32bit 64bit
SET 16bit 16bit 32bit 64bit
REAL 32bit 32bit 32bit 32bit
LONGREAL 64bit 64bit 64bit 64bit

Legacy Oberon-2 code probably have some assumptions tied to 32bit I
guess and could fail on newer 64bit platforms as 64bit platforms was
not so common. Legacy Oberon-2 code should work fine on 32bit platform
as the bit sizes here are similar to the XDS compiler.

Then if Oberon-07 is to be followed with only REAL, BYTE, INTEGER & SET.
INTEGER could be alias for LONGINT and LEN & SYSTEM.ADR etc should
work on all platforms.

For Oberon-07 REAL should probably be then possible to select if 32bit or 64bit.

For interface with OS functionality or hardware registers probably fixed integer sizes
should be added to SYSTEM. Otherwise this would be to fragile and 64bit integer
is missing on 32bit platforms.

I see that many "modern" languages or modernized (C++11) now use fixed sizes.
This creates the need for additional types for array sizes and pointers etc and I guess
any library code which should be cross platform probably use some kind logic to select
a suitable fast integer size for the target platform.

Not looked into any implementation details other than I found the compiler is smart enough to
detect when upper bits is discarded in a return statement and acts accordingly for earlier operations.

EDIT : Changed SHORTINT to 8bit on all platforms.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.