From 62b605c6c0ea13e9763c0a0115464007b13a8831 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Tue, 20 Oct 2026 11:57:16 +0000 Subject: refactor(strings): replace compiler builtins with the STRING library Construct literals as STRING values and route string operations through ordinary library functions and operators. Preserve value ownership in records, arrays, constants and file I/O. Co-Authored-By: Claude Opus 5.5 --- lib/CodeGen/StringHandler.cc | 206 ------------------------------------------- 1 file changed, 206 deletions(-) delete mode 100644 lib/CodeGen/StringHandler.cc (limited to 'lib/CodeGen/StringHandler.cc') diff --git a/lib/CodeGen/StringHandler.cc b/lib/CodeGen/StringHandler.cc deleted file mode 100644 index f91539c..0000000 --- a/lib/CodeGen/StringHandler.cc +++ /dev/null @@ -1,206 +0,0 @@ -#include "cps/StringHandler.h" -#include "cps/Lexer.h" -#include "llvm/IR/Type.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Constants.h" - -using namespace llvm; -using namespace cps; - -StringHandler::StringHandler(LLVMContext &Ctx, IRBuilder<> &B, llvm::Module &M) - : Context(Ctx), Builder(B), Module(M) { - setupExternalFunctions(); -} - -void StringHandler::setupExternalFunctions() { - FunctionType *MallocType = FunctionType::get(PointerType::getUnqual(Context), {Type::getInt64Ty(Context)}, false); - MallocFunc = Module.getOrInsertFunction("malloc", MallocType); - - FunctionType *StrLenType = FunctionType::get(Type::getInt64Ty(Context), {PointerType::getUnqual(Context)}, false); - StrLenFunc = Module.getOrInsertFunction("strlen", StrLenType); - - std::vector MemCpyArgs = {PointerType::getUnqual(Context), PointerType::getUnqual(Context), Type::getInt64Ty(Context)}; - FunctionType *MemCpyType = FunctionType::get(PointerType::getUnqual(Context), MemCpyArgs, false); - MemCpyFunc = Module.getOrInsertFunction("memcpy", MemCpyType); - - FunctionType *StrCpyType = FunctionType::get(PointerType::getUnqual(Context), - {PointerType::getUnqual(Context), PointerType::getUnqual(Context)}, - false); - StrCpyFunc = Module.getOrInsertFunction("strcpy", StrCpyType); - StrCatFunc = Module.getOrInsertFunction("strcat", StrCpyType); - StrCmpFunc = Module.getOrInsertFunction("strcmp", - FunctionType::get(Type::getInt32Ty(Context), - {PointerType::getUnqual(Context), PointerType::getUnqual(Context)}, false)); - - FunctionType *CharCaseType = FunctionType::get(Type::getInt32Ty(Context), {Type::getInt32Ty(Context)}, false); - ToUpperFunc = Module.getOrInsertFunction("toupper", CharCaseType); - ToLowerFunc = Module.getOrInsertFunction("tolower", CharCaseType); -} - -Value *StringHandler::createLiteral(const std::string &Val) { - return Builder.CreateGlobalString(Val); -} - -Value *StringHandler::emitLength(Value *Str) { - if (!Str) return nullptr; - return Builder.CreateCall(StrLenFunc, Str, "len"); -} - -Value *StringHandler::emitConcat(Value *LHS, Value *RHS) { - if (!LHS || !RHS) return nullptr; - - Value *LLen = Builder.CreateCall(StrLenFunc, {LHS}, "llen"); - Value *RLen = Builder.CreateCall(StrLenFunc, {RHS}, "rlen"); - Value *TotalLen = Builder.CreateAdd(LLen, RLen, "totallen"); - Value *AllocSize = Builder.CreateAdd(TotalLen, ConstantInt::get(Type::getInt64Ty(Context), 1), "allocsize"); - - Value *NewStr = Builder.CreateCall(MallocFunc, {AllocSize}, "concat_str"); - - Builder.CreateCall(StrCpyFunc, {NewStr, LHS}); - Builder.CreateCall(StrCatFunc, {NewStr, RHS}); - - return NewStr; -} - -Value *StringHandler::emitCompare(int Op, Value *LHS, Value *RHS) { - if (!LHS || !RHS) return nullptr; - - CmpInst::Predicate Pred; - switch (Op) { - case tok_eq: Pred = CmpInst::ICMP_EQ; break; - case tok_ne: Pred = CmpInst::ICMP_NE; break; - case '<': Pred = CmpInst::ICMP_SLT; break; - case '>': Pred = CmpInst::ICMP_SGT; break; - case tok_le: Pred = CmpInst::ICMP_SLE; break; - case tok_ge: Pred = CmpInst::ICMP_SGE; break; - default: return nullptr; - } - - Value *Cmp = Builder.CreateCall(StrCmpFunc, {LHS, RHS}, "strcmp_result"); - return Builder.CreateICmp(Pred, Cmp, ConstantInt::get(Type::getInt32Ty(Context), 0), "str_compare"); -} - -// malloc(Len + 1), copy Len bytes from Src + StartIdx, NUL-terminate. -// Clamping is each caller's business — MID/RIGHT/LEFT clamp different things. -Value *StringHandler::allocCopySubstring(Value *Src, Value *StartIdx, Value *Len) { - Value *One = ConstantInt::get(Context, APInt(64, 1)); - Value *AllocSize = Builder.CreateAdd(Len, One); - Value *NewStr = Builder.CreateCall(MallocFunc, AllocSize, "substr_mem"); - - Value *SrcPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), Src, StartIdx); - Builder.CreateCall(MemCpyFunc, {NewStr, SrcPtr, Len}); - - Value *NullTermPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), NewStr, Len); - Builder.CreateStore(ConstantInt::get(Type::getInt8Ty(Context), 0), NullTermPtr); - - return NewStr; -} - -Value *StringHandler::emitMid(Value *Str, Value *Start, Value *Len) { - Value *FullLen = emitLength(Str); - - Value *One = ConstantInt::get(Context, APInt(64, 1)); - Value *Zero = ConstantInt::get(Context, APInt(64, 0)); - Value *StartZeroBased = Builder.CreateSub(Start, One, "start_idx"); - - Value *IsNeg = Builder.CreateICmpSLT(StartZeroBased, Zero); - StartZeroBased = Builder.CreateSelect(IsNeg, Zero, StartZeroBased); - - Value *IsTooBig = Builder.CreateICmpSGT(StartZeroBased, FullLen); - StartZeroBased = Builder.CreateSelect(IsTooBig, FullLen, StartZeroBased); - - Value *RemLen = Builder.CreateSub(FullLen, StartZeroBased); - - Value *IsLenTooBig = Builder.CreateICmpSGT(Len, RemLen); - Value *ActualLen = Builder.CreateSelect(IsLenTooBig, RemLen, Len); - - Value *IsLenNeg = Builder.CreateICmpSLT(ActualLen, Zero); - ActualLen = Builder.CreateSelect(IsLenNeg, Zero, ActualLen); - - return allocCopySubstring(Str, StartZeroBased, ActualLen); -} - -Value *StringHandler::emitRight(Value *Str, Value *Len) { - Value *FullLen = emitLength(Str); - - Value *StartIdx = Builder.CreateSub(FullLen, Len, "right_start"); - - Value *Zero = ConstantInt::get(Context, APInt(64, 0)); - Value *IsNeg = Builder.CreateICmpSLT(StartIdx, Zero); - StartIdx = Builder.CreateSelect(IsNeg, Zero, StartIdx); - - Value *ActualLen = Builder.CreateSub(FullLen, StartIdx); - - return allocCopySubstring(Str, StartIdx, ActualLen); -} - -Value *StringHandler::emitLeft(Value *Str, Value *Len) { - Value *FullLen = emitLength(Str); - - Value *Zero = ConstantInt::get(Context, APInt(64, 0)); - Value *IsNeg = Builder.CreateICmpSLT(Len, Zero); - Value *SafeLen = Builder.CreateSelect(IsNeg, Zero, Len); - - Value *IsTooBig = Builder.CreateICmpSGT(SafeLen, FullLen); - Value *ActualLen = Builder.CreateSelect(IsTooBig, FullLen, SafeLen); - - return allocCopySubstring(Str, Zero, ActualLen); -} - -// Shared loop for LCASE/UCASE: malloc a copy of Str with every byte run -// through CaseFn (tolower/toupper). -Value *StringHandler::emitCaseConvert(Value *Str, FunctionCallee CaseFn) { - if (!Str) return nullptr; - Value *Len = emitLength(Str); - Value *One = ConstantInt::get(Context, APInt(64, 1)); - Value *AllocSize = Builder.CreateAdd(Len, One); - Value *NewStr = Builder.CreateCall(MallocFunc, AllocSize, "case_str"); - - Function *TheFunction = Builder.GetInsertBlock()->getParent(); - BasicBlock *LoopBB = BasicBlock::Create(Context, "loop", TheFunction); - BasicBlock *AfterBB = BasicBlock::Create(Context, "afterloop", TheFunction); - - IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - AllocaInst *IdxVar = TmpB.CreateAlloca(Type::getInt64Ty(Context), nullptr, "idx"); - Builder.CreateStore(ConstantInt::get(Context, APInt(64, 0)), IdxVar); - - Builder.CreateBr(LoopBB); - Builder.SetInsertPoint(LoopBB); - - Value *CurIdx = Builder.CreateLoad(Type::getInt64Ty(Context), IdxVar); - Value *Cond = Builder.CreateICmpSLT(CurIdx, Len); - - BasicBlock *BodyBB = BasicBlock::Create(Context, "body", TheFunction); - Builder.CreateCondBr(Cond, BodyBB, AfterBB); - - Builder.SetInsertPoint(BodyBB); - - Value *SrcPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), Str, CurIdx); - Value *CharVal = Builder.CreateLoad(Type::getInt8Ty(Context), SrcPtr); - - Value *ExtChar = Builder.CreateSExt(CharVal, Type::getInt32Ty(Context)); - Value *ConvChar = Builder.CreateCall(CaseFn, ExtChar); - Value *TruncChar = Builder.CreateTrunc(ConvChar, Type::getInt8Ty(Context)); - - Value *DestPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), NewStr, CurIdx); - Builder.CreateStore(TruncChar, DestPtr); - - Value *NextIdx = Builder.CreateAdd(CurIdx, One); - Builder.CreateStore(NextIdx, IdxVar); - Builder.CreateBr(LoopBB); - - Builder.SetInsertPoint(AfterBB); - - Value *NullPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), NewStr, Len); - Builder.CreateStore(ConstantInt::get(Type::getInt8Ty(Context), 0), NullPtr); - - return NewStr; -} - -Value *StringHandler::emitLCase(Value *Str) { - return emitCaseConvert(Str, ToLowerFunc); -} - -Value *StringHandler::emitUCase(Value *Str) { - return emitCaseConvert(Str, ToUpperFunc); -} -- cgit v1.3.1-4-g156e