aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-14 09:21:29 +0000
committer_ov4 <ov4@ov4.org>2026-10-14 09:21:29 +0000
commit83c5d8ecbf019a4f3cea6874566a5631764d3d9b (patch)
tree8b6d30fb8e22d5cbaa45ecccdc68efe1ac8ead2b
parenta2ba22397598d558e83725283495de3cf37e68d6 (diff)
build(toolchain)!: require LLVM and Clang 23
Reject other compiler and LLVM major versions and remove GCC compiler fallbacks. Adapt string globals, block termination checks and the embedded target triple to LLVM 23 without changing pseudocode behavior. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
-rw-r--r--CMakeLists.txt14
-rw-r--r--cmake/BuildTools.cmake15
-rw-r--r--lib/CodeGen/CTypeGen.cc6
-rw-r--r--lib/CodeGen/CodeGen.cc52
-rw-r--r--lib/CodeGen/ExceptionHandler.cc2
-rw-r--r--lib/CodeGen/FileHandler.cc6
-rw-r--r--lib/CodeGen/FunctionGen.cc2
-rw-r--r--lib/CodeGen/StringConversionHandler.cc4
-rw-r--r--lib/CodeGen/StringHandler.cc2
-rw-r--r--tools/driver/EmbeddedRunner.cc3
10 files changed, 62 insertions, 44 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 679ba62..c5cce71 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,6 +3,15 @@ include(cmake/LocalDependencies.cmake)
include(cmake/BuildTools.cmake)
project(cps_compiler)
+foreach(language C CXX)
+ if(NOT CMAKE_${language}_COMPILER_ID STREQUAL "Clang"
+ OR CMAKE_${language}_COMPILER_VERSION VERSION_LESS 23
+ OR NOT CMAKE_${language}_COMPILER_VERSION VERSION_LESS 24)
+ message(FATAL_ERROR
+ "cpsc requires Clang 23 for ${language}; found ${CMAKE_${language}_COMPILER_ID} ${CMAKE_${language}_COMPILER_VERSION} (${CMAKE_${language}_COMPILER})")
+ endif()
+endforeach()
+
if(WIN32 AND CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
if("$ENV{LOCALAPPDATA}" STREQUAL "")
message(FATAL_ERROR "LOCALAPPDATA is unset; specify -DCMAKE_INSTALL_PREFIX explicitly")
@@ -19,6 +28,9 @@ endif()
include(cmake/LLVMDependencies.cmake)
find_package(LLVM REQUIRED CONFIG)
+if(NOT LLVM_VERSION_MAJOR EQUAL 23)
+ message(FATAL_ERROR "cpsc requires LLVM 23; found LLVM ${LLVM_PACKAGE_VERSION} (${LLVM_DIR})")
+endif()
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
@@ -70,7 +82,7 @@ if(CPSC_RUN_MODE STREQUAL "EMBEDDED")
target_sources(cpsc PRIVATE tools/driver/EmbeddedRunner.cc)
if(MINGW)
target_link_options(cpsc PRIVATE -static)
- elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" AND UNIX AND NOT APPLE)
+ elseif(UNIX AND NOT APPLE)
target_link_options(cpsc PRIVATE -static-libstdc++ -static-libgcc -Wl,--as-needed)
endif()
endif()
diff --git a/cmake/BuildTools.cmake b/cmake/BuildTools.cmake
index d6928bb..e2d3e2f 100644
--- a/cmake/BuildTools.cmake
+++ b/cmake/BuildTools.cmake
@@ -2,15 +2,20 @@
if(CMAKE_GENERATOR MATCHES "Makefiles|Ninja")
foreach(language C CXX)
if(language STREQUAL "C")
- set(names clang cc gcc)
+ set(names clang-23 clang)
+ set(compiler_environment CC)
else()
- set(names clang++ c++ g++)
+ set(names clang++-23 clang++)
+ set(compiler_environment CXX)
endif()
if(CMAKE_${language}_COMPILER)
- get_filename_component(requested "${CMAKE_${language}_COMPILER}" NAME)
- list(INSERT names 0 "${requested}")
+ if(NOT IS_ABSOLUTE "${CMAKE_${language}_COMPILER}")
+ cpsc_find_dependency(PROGRAM CMAKE_${language}_COMPILER
+ NAMES "${CMAKE_${language}_COMPILER}" REQUIRED)
+ endif()
+ elseif("$ENV{${compiler_environment}}" STREQUAL "")
+ cpsc_find_dependency(PROGRAM CMAKE_${language}_COMPILER NAMES ${names} REQUIRED)
endif()
- cpsc_find_dependency(PROGRAM CMAKE_${language}_COMPILER NAMES ${names} REQUIRED)
# project() would otherwise restore the previous path from this file.
set(compiler_info "${CMAKE_BINARY_DIR}/CMakeFiles/${CMAKE_VERSION}/CMake${language}Compiler.cmake")
if(EXISTS "${compiler_info}")
diff --git a/lib/CodeGen/CTypeGen.cc b/lib/CodeGen/CTypeGen.cc
index 4d945a7..22ecb9f 100644
--- a/lib/CodeGen/CTypeGen.cc
+++ b/lib/CodeGen/CTypeGen.cc
@@ -179,7 +179,7 @@ void CodeGen::emitCOutput(Value *Val, const TypeInfo *Info, bool AppendNewline)
Val = convertNumericValue(Val, Info, Types->promoteCScalar(Info));
}
if (AppendNewline) Format += '\n';
- Value *Fmt = Builder->CreateGlobalStringPtr(Format, "fmt_c_output", 0, TheModule.get());
+ Value *Fmt = Builder->CreateGlobalString(Format, "fmt_c_output", 0, TheModule.get());
Builder->CreateCall(PrintfFunc, {Fmt, Val});
}
@@ -193,13 +193,13 @@ void CodeGen::emitCInput(const SymbolInfo *Symbol, const TypeInfo *Info) {
AllocaInst *Temp = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(),
NativeInt->LLVMType, "c_bool_input");
Builder->CreateStore(Types->getZeroValue("C_INT"), Temp);
- Value *Fmt = Builder->CreateGlobalStringPtr("%d", "fmt_c_input_bool", 0, TheModule.get());
+ Value *Fmt = Builder->CreateGlobalString("%d", "fmt_c_input_bool", 0, TheModule.get());
Builder->CreateCall(ScanfFunc, {Fmt, Temp});
Value *Input = Builder->CreateLoad(NativeInt->LLVMType, Temp);
Value *Bool = convertNumericValue(Input, NativeInt, Info);
Builder->CreateStore(Bool, Symbol->Storage);
return;
}
- Value *Fmt = Builder->CreateGlobalStringPtr(Info->CInputFormat, "fmt_c_input", 0, TheModule.get());
+ Value *Fmt = Builder->CreateGlobalString(Info->CInputFormat, "fmt_c_input", 0, TheModule.get());
Builder->CreateCall(ScanfFunc, {Fmt, Symbol->Storage});
}
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index a88941b..b86a0ae 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -121,18 +121,18 @@ void CodeGen::SetupExternalFunctions() {
false);
MallocFunc = TheModule->getOrInsertFunction("malloc", MallocType);
- PrintfFormatStr = Builder->CreateGlobalStringPtr("%lld\n", "fmt_nl", 0, TheModule.get());
- PrintfFloatFormatStr = Builder->CreateGlobalStringPtr("%f\n", "fmt_flt", 0, TheModule.get());
- PrintfStringFormatStr = Builder->CreateGlobalStringPtr("%s\n", "fmt_str", 0, TheModule.get());
- PrintfCharFormatStr = Builder->CreateGlobalStringPtr("%c\n", "fmt_chr", 0, TheModule.get());
+ PrintfFormatStr = Builder->CreateGlobalString("%lld\n", "fmt_nl", 0, TheModule.get());
+ PrintfFloatFormatStr = Builder->CreateGlobalString("%f\n", "fmt_flt", 0, TheModule.get());
+ PrintfStringFormatStr = Builder->CreateGlobalString("%s\n", "fmt_str", 0, TheModule.get());
+ PrintfCharFormatStr = Builder->CreateGlobalString("%c\n", "fmt_chr", 0, TheModule.get());
- ScanfFormatStr = Builder->CreateGlobalStringPtr("%lld", "fmt_in", 0, TheModule.get());
- ScanfFloatFormatStr = Builder->CreateGlobalStringPtr("%lf", "fmt_in_flt", 0, TheModule.get());
- ScanfStringFormatStr = Builder->CreateGlobalStringPtr("%s", "fmt_in_str", 0, TheModule.get());
+ ScanfFormatStr = Builder->CreateGlobalString("%lld", "fmt_in", 0, TheModule.get());
+ ScanfFloatFormatStr = Builder->CreateGlobalString("%lf", "fmt_in_flt", 0, TheModule.get());
+ ScanfStringFormatStr = Builder->CreateGlobalString("%s", "fmt_in_str", 0, TheModule.get());
- TrueStr = Builder->CreateGlobalStringPtr("TRUE", "str_true", 0, TheModule.get());
- FalseStr = Builder->CreateGlobalStringPtr("FALSE", "str_false", 0, TheModule.get());
- EmptyStringStr = Builder->CreateGlobalStringPtr("", "str_empty", 0, TheModule.get());
+ TrueStr = Builder->CreateGlobalString("TRUE", "str_true", 0, TheModule.get());
+ FalseStr = Builder->CreateGlobalString("FALSE", "str_false", 0, TheModule.get());
+ EmptyStringStr = Builder->CreateGlobalString("", "str_empty", 0, TheModule.get());
Arrays->setupExternalFunctions();
}
@@ -462,7 +462,7 @@ void CodeGen::emitOutputValue(Value *Val, const TypeInfo *Info, bool AppendNewli
case TypeKind::Real:
Fmt = AppendNewline
? PrintfFloatFormatStr
- : Builder->CreateGlobalStringPtr("%f", "fmt_flt_inline", 0, TheModule.get());
+ : Builder->CreateGlobalString("%f", "fmt_flt_inline", 0, TheModule.get());
Args.push_back(Fmt);
Args.push_back(Val);
break;
@@ -471,7 +471,7 @@ void CodeGen::emitOutputValue(Value *Val, const TypeInfo *Info, bool AppendNewli
Value *BoolVal = coerceValueToType(Val, resolveType("BOOLEAN"));
Fmt = AppendNewline
? PrintfStringFormatStr
- : Builder->CreateGlobalStringPtr("%s", "fmt_str_inline", 0, TheModule.get());
+ : Builder->CreateGlobalString("%s", "fmt_str_inline", 0, TheModule.get());
Args.push_back(Fmt);
Args.push_back(Builder->CreateSelect(BoolVal, TrueStr, FalseStr));
break;
@@ -481,7 +481,7 @@ void CodeGen::emitOutputValue(Value *Val, const TypeInfo *Info, bool AppendNewli
Value *StrVal = emitStringNullGuard(Val);
Fmt = AppendNewline
? PrintfStringFormatStr
- : Builder->CreateGlobalStringPtr("%s", "fmt_str_inline", 0, TheModule.get());
+ : Builder->CreateGlobalString("%s", "fmt_str_inline", 0, TheModule.get());
Args.push_back(Fmt);
Args.push_back(StrVal);
break;
@@ -492,7 +492,7 @@ void CodeGen::emitOutputValue(Value *Val, const TypeInfo *Info, bool AppendNewli
Value *Promoted = Builder->CreateZExt(CharVal, Type::getInt32Ty(*TheContext), "char_for_printf");
Fmt = AppendNewline
? PrintfCharFormatStr
- : Builder->CreateGlobalStringPtr("%c", "fmt_chr_inline", 0, TheModule.get());
+ : Builder->CreateGlobalString("%c", "fmt_chr_inline", 0, TheModule.get());
Args.push_back(Fmt);
Args.push_back(Promoted);
break;
@@ -503,7 +503,7 @@ void CodeGen::emitOutputValue(Value *Val, const TypeInfo *Info, bool AppendNewli
Value *IntVal = Info->isEnum() ? Val : coerceValueToType(Val, resolveType("INTEGER"));
Fmt = AppendNewline
? PrintfFormatStr
- : Builder->CreateGlobalStringPtr("%lld", "fmt_int_inline", 0, TheModule.get());
+ : Builder->CreateGlobalString("%lld", "fmt_int_inline", 0, TheModule.get());
Args.push_back(Fmt);
Args.push_back(IntVal);
break;
@@ -558,7 +558,7 @@ void CodeGen::compile(const std::vector<std::unique_ptr<StmtAST>> &Statements) {
emitStmt(Stmt.get());
}
- if (!Builder->GetInsertBlock()->getTerminator()) {
+ if (!Builder->GetInsertBlock()->hasTerminator()) {
Builder->CreateRet(ConstantInt::get(*TheContext, APInt(32, 0)));
}
@@ -566,7 +566,7 @@ void CodeGen::compile(const std::vector<std::unique_ptr<StmtAST>> &Statements) {
Builder->SetInsertPoint(UnhandledBB);
Exceptions->beginCatch(Exception);
Exceptions->endCatch();
- Value *Msg = Builder->CreateGlobalStringPtr("Unhandled exception. Program terminated.\n",
+ Value *Msg = Builder->CreateGlobalString("Unhandled exception. Program terminated.\n",
"err_unhandled", 0, TheModule.get());
Builder->CreateCall(PrintfFunc, {Msg});
Builder->CreateRet(ConstantInt::get(Type::getInt32Ty(*TheContext), 1));
@@ -922,14 +922,14 @@ void CodeGen::emitTryStmt(TryStmtAST *Stmt) {
Exceptions->pushHandler(CatchBB);
for (const auto &S : Stmt->getBody()) emitStmt(S.get());
auto *Exception = Exceptions->popHandler();
- if (!Builder->GetInsertBlock()->getTerminator()) Builder->CreateBr(AfterBB);
+ if (!Builder->GetInsertBlock()->hasTerminator()) Builder->CreateBr(AfterBB);
Arrays->exchangeTable(SavedArrays);
Builder->SetInsertPoint(CatchBB);
Exceptions->beginCatch(Exception);
for (const auto &S : Stmt->getCatchBody()) emitStmt(S.get());
Exceptions->endCatch();
- if (!Builder->GetInsertBlock()->getTerminator()) Builder->CreateBr(AfterBB);
+ if (!Builder->GetInsertBlock()->hasTerminator()) Builder->CreateBr(AfterBB);
Arrays->exchangeTable(std::move(SavedArrays));
Builder->SetInsertPoint(AfterBB);
}
@@ -950,12 +950,12 @@ void CodeGen::emitIfStmt(IfStmtAST *Stmt) {
auto SavedArrays = Arrays->snapshotTable();
Builder->SetInsertPoint(ThenBB);
for (const auto &S : Stmt->getThenStmts()) emitStmt(S.get());
- if (!Builder->GetInsertBlock()->getTerminator()) Builder->CreateBr(MergeBB);
+ if (!Builder->GetInsertBlock()->hasTerminator()) Builder->CreateBr(MergeBB);
Arrays->exchangeTable(SavedArrays);
Builder->SetInsertPoint(ElseBB);
for (const auto &S : Stmt->getElseStmts()) emitStmt(S.get());
- if (!Builder->GetInsertBlock()->getTerminator()) Builder->CreateBr(MergeBB);
+ if (!Builder->GetInsertBlock()->hasTerminator()) Builder->CreateBr(MergeBB);
Arrays->exchangeTable(std::move(SavedArrays));
Builder->SetInsertPoint(MergeBB);
@@ -982,7 +982,7 @@ void CodeGen::emitWhileStmt(WhileStmtAST *Stmt) {
for (const auto &S : Stmt->getBody()) emitStmt(S.get());
Arrays->exchangeTable(std::move(SavedArrays));
- if (!Builder->GetInsertBlock()->getTerminator())
+ if (!Builder->GetInsertBlock()->hasTerminator())
Builder->CreateBr(CondBB);
Builder->SetInsertPoint(AfterBB);
@@ -1002,7 +1002,7 @@ void CodeGen::emitRepeatStmt(RepeatStmtAST *Stmt) {
Builder->SetInsertPoint(LoopBB);
for (const auto &S : Stmt->getBody()) emitStmt(S.get());
Arrays->exchangeTable(std::move(SavedArrays));
- if (!Builder->GetInsertBlock()->getTerminator())
+ if (!Builder->GetInsertBlock()->hasTerminator())
Builder->CreateBr(CondBB);
Builder->SetInsertPoint(CondBB);
@@ -1070,7 +1070,7 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
Builder->SetInsertPoint(LoopBB);
for (const auto &S : Stmt->getBody()) emitStmt(S.get());
Arrays->exchangeTable(std::move(SavedArrays));
- if (!Builder->GetInsertBlock()->getTerminator())
+ if (!Builder->GetInsertBlock()->hasTerminator())
Builder->CreateBr(IncBB);
Builder->SetInsertPoint(IncBB);
@@ -1102,7 +1102,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
// Keep diagnosing statements after RETURN/THROW without appending code
// to a terminated block or making those statements reachable.
- if (Builder->GetInsertBlock()->getTerminator()) {
+ if (Builder->GetInsertBlock()->hasTerminator()) {
auto *F = Builder->GetInsertBlock()->getParent();
Builder->SetInsertPoint(BasicBlock::Create(*TheContext, "unreachable_code", F));
}
@@ -1224,7 +1224,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
Builder->CreateCall(ScanfFunc, Args);
Builder->CreateStore(Mem, Info->Storage);
} else if (TypeInfo->isChar()) {
- Value *CharFmt = Builder->CreateGlobalStringPtr(" %c", "fmt_in_char", 0, TheModule.get());
+ Value *CharFmt = Builder->CreateGlobalString(" %c", "fmt_in_char", 0, TheModule.get());
Args.push_back(CharFmt);
Args.push_back(Info->Storage);
Builder->CreateCall(ScanfFunc, Args);
diff --git a/lib/CodeGen/ExceptionHandler.cc b/lib/CodeGen/ExceptionHandler.cc
index 048f8a6..21eb011 100644
--- a/lib/CodeGen/ExceptionHandler.cc
+++ b/lib/CodeGen/ExceptionHandler.cc
@@ -69,7 +69,7 @@ void ExceptionHandler::endCatch() {
auto &Depth = States[Builder.GetInsertBlock()->getParent()].CatchDepth;
assert(Depth != 0);
--Depth;
- if (!Builder.GetInsertBlock()->getTerminator()) Builder.CreateCall(EndCatch);
+ if (!Builder.GetInsertBlock()->hasTerminator()) Builder.CreateCall(EndCatch);
}
void ExceptionHandler::emitReturnCleanup() {
diff --git a/lib/CodeGen/FileHandler.cc b/lib/CodeGen/FileHandler.cc
index 66a7606..f2e7824 100644
--- a/lib/CodeGen/FileHandler.cc
+++ b/lib/CodeGen/FileHandler.cc
@@ -55,9 +55,9 @@ void FileHandler::setupGlobals() {
// Text mode on purpose (no "b"): on Windows the CRT translates CRLF<->LF,
// which is exactly what line-oriented READFILE/WRITEFILE want.
- ModeReadStr = Builder.CreateGlobalStringPtr("r", "file_mode_r", 0, &Module);
- ModeWriteStr = Builder.CreateGlobalStringPtr("w", "file_mode_w", 0, &Module);
- ModeAppendStr = Builder.CreateGlobalStringPtr("a", "file_mode_a", 0, &Module);
+ ModeReadStr = Builder.CreateGlobalString("r", "file_mode_r", 0, &Module);
+ ModeWriteStr = Builder.CreateGlobalString("w", "file_mode_w", 0, &Module);
+ ModeAppendStr = Builder.CreateGlobalString("a", "file_mode_a", 0, &Module);
}
void FileHandler::ensureRuntime() {
diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc
index 480d9ba..9ccd8af 100644
--- a/lib/CodeGen/FunctionGen.cc
+++ b/lib/CodeGen/FunctionGen.cc
@@ -201,7 +201,7 @@ Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST,
StmtEmitter(Stmt.get());
}
- if (!Builder.GetInsertBlock()->getTerminator()) {
+ if (!Builder.GetInsertBlock()->hasTerminator()) {
if (Proto->getReturnType() == "VOID") {
Builder.CreateRetVoid();
} else {
diff --git a/lib/CodeGen/StringConversionHandler.cc b/lib/CodeGen/StringConversionHandler.cc
index af7f385..3b49cbb 100644
--- a/lib/CodeGen/StringConversionHandler.cc
+++ b/lib/CodeGen/StringConversionHandler.cc
@@ -28,9 +28,9 @@ Value *StringConversionHandler::emitNumToStr(Value *Num, bool IsReal) {
Value *FormatStr;
if (IsReal) {
- FormatStr = Builder.CreateGlobalStringPtr("%f");
+ FormatStr = Builder.CreateGlobalString("%f");
} else {
- FormatStr = Builder.CreateGlobalStringPtr("%lld");
+ FormatStr = Builder.CreateGlobalString("%lld");
}
Builder.CreateCall(SprintfFunc, {Buffer, FormatStr, Num});
diff --git a/lib/CodeGen/StringHandler.cc b/lib/CodeGen/StringHandler.cc
index 0830021..f91539c 100644
--- a/lib/CodeGen/StringHandler.cc
+++ b/lib/CodeGen/StringHandler.cc
@@ -38,7 +38,7 @@ void StringHandler::setupExternalFunctions() {
}
Value *StringHandler::createLiteral(const std::string &Val) {
- return Builder.CreateGlobalStringPtr(Val);
+ return Builder.CreateGlobalString(Val);
}
Value *StringHandler::emitLength(Value *Str) {
diff --git a/tools/driver/EmbeddedRunner.cc b/tools/driver/EmbeddedRunner.cc
index 56e3195..a654d5a 100644
--- a/tools/driver/EmbeddedRunner.cc
+++ b/tools/driver/EmbeddedRunner.cc
@@ -6,6 +6,7 @@
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/TargetParser/Host.h"
+#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include <cxxabi.h>
#include <typeinfo>
@@ -54,7 +55,7 @@ int runEmbedded(const cps::CodeGen &CG) {
registerExceptionSymbols();
// Keep CodeGen's module and context alive while the engine owns its clone.
auto Module = llvm::CloneModule(CG.getModule());
- Module->setTargetTriple(llvm::sys::getProcessTriple());
+ Module->setTargetTriple(llvm::Triple(llvm::sys::getProcessTriple()));
llvm::EngineBuilder Builder(std::move(Module));
Builder.setEngineKind(llvm::EngineKind::JIT);
Builder.setErrorStr(&Error);