@@ -20,6 +20,7 @@ llvm::Value* castValue(llvm::Value* value, llvm::Type* destType, bool isSrcSigne
2020
2121std::unordered_map<std::string, Type*> unresolvedTypes;
2222std::stack<Type*> lastRetrievedElementType;
23+ std::stack<Value*> pipeOperationValue;
2324
2425std::unordered_map<std::string, bool > typeSigns = {
2526 {" int128" , true },
@@ -90,7 +91,10 @@ struct functionID {
9091 }
9192 void print ()
9293 {
93- console::Write (returnType + " " , console::blueFGColor);
94+ if (uses == 0 )
95+ return ;
96+ if (returnType != " " )
97+ console::Write (returnType + " " , console::blueFGColor);
9498 console::Write (name, console::greenFGColor);
9599 console::Write (" (" );
96100 for (int i = 0 ; i < arguments.size (); i++) {
@@ -100,7 +104,13 @@ struct functionID {
100104 if (i < arguments.size () - 1 )
101105 console::Write (" , " );
102106 }
103- console::WriteLine (" )" );
107+ console::Write (" )" );
108+ if (isStructReturn) {
109+ console::Write (" (" );
110+ console::Write (" returns struct" , console::yellowFGColor);
111+ console::Write (" )" );
112+ }
113+ console::WriteLine ();
104114 }
105115 bool compareASTNodeTypes (ASTNodeType& a, ASTNodeType& b, bool wereTypesInferred = false )
106116 {
@@ -253,6 +263,12 @@ structType* getStructTypeFromLLVMType(Type*& t)
253263 return nullptr ;
254264}
255265
266+ void printFunctionPrototypes ()
267+ {
268+ for (const auto & f : functionIDs)
269+ f->print ();
270+ }
271+
256272functionID* getFunctionFromID (std::vector<functionID*>& fnIDs, std::string& name, argumentList& arguments, tokenPair*& t, bool wereTypesInferred = false , bool isMemberFunction = false )
257273{
258274 functionID* best;
@@ -967,7 +983,7 @@ void* ASTNode::generateVariableExpression(int pass)
967983 return Builder->CreateLoad (targetPtr->getAllocatedType (), targetPtr, token->first + " _load" );
968984 }
969985 AllocaInst* A = (AllocaInst*)(val->val );
970- baseType = A-> getAllocatedType ();
986+ baseType = val-> val -> getType ();
971987
972988 if (isRef || lvalue)
973989 return A;
@@ -987,43 +1003,45 @@ void* ASTNode::generateReturn(int pass)
9871003 if (wasError) {
9881004 exit (1 );
9891005 }
1006+ Function* currentFunc = Builder->GetInsertBlock ()->getParent ();
1007+ functionID* fnID = getFunctionIDFromFunctionPointer (functionIDs, currentFunc);
9901008 // Check if we're returning a struct
9911009 Type* returnType = Builder->GetInsertBlock ()->getParent ()->getReturnType ();
992- if (returnType->isStructTy ()) {
993- // For struct returns, we need to handle this specially
994- // Option 1: If the function uses sret, copy to the sret parameter
995- Function* currentFunc = Builder->GetInsertBlock ()->getParent ();
996- if (currentFunc->hasStructRetAttr ()) {
997- // Get the sret parameter (first parameter)
998- Value* sretPtr = &*currentFunc->arg_begin ();
999-
1000- // Copy the struct value to the sret location
1001- if (RetVal->getType ()->isPointerTy ()) {
1002- // If RetVal is a pointer to struct, memcpy from it
1003- Value* structSize = ConstantInt::get (Type::getInt64Ty (*TheContext),
1004- TheModule->getDataLayout ().getTypeAllocSize (returnType));
1005-
1006- // Create memcpy call
1007- Function* memcpyFunc = Intrinsic::getDeclaration (TheModule.get (),
1008- Intrinsic::memcpy, {sretPtr->getType (), RetVal->getType (), Type::getInt64Ty (*TheContext)});
1009- Builder->CreateCall (memcpyFunc, {sretPtr, RetVal, structSize, ConstantInt::get (Type::getInt1Ty (*TheContext), 0 )});
1010- }
1011- else {
1012- // If RetVal is a struct value, store it
1013- Builder->CreateStore (RetVal, sretPtr);
1014- }
1015-
1016-
1017- Builder->CreateRetVoid ();
1010+ if (fnID->isStructReturn ) {
1011+ // //if (returnType->isStructTy()) {
1012+ // // For struct returns, we need to handle this specially
1013+ // // Option 1: If the function uses sret, copy to the sret parameter
1014+ // if (currentFunc->hasStructRetAttr()) {
1015+ // Get the sret parameter (first parameter)
1016+ Value* sretPtr = &*currentFunc->arg_begin ();
1017+
1018+ // Copy the struct value to the sret location
1019+ if (RetVal->getType ()->isPointerTy ()) {
1020+ // If RetVal is a pointer to struct, memcpy from it
1021+ Value* structSize = ConstantInt::get (Type::getInt64Ty (*TheContext),
1022+ TheModule->getDataLayout ().getTypeAllocSize (returnType));
1023+
1024+ // Create memcpy call
1025+ Function* memcpyFunc = Intrinsic::getDeclaration (TheModule.get (),
1026+ Intrinsic::memcpy, {sretPtr->getType (), RetVal->getType (), Type::getInt64Ty (*TheContext)});
1027+ Builder->CreateCall (memcpyFunc, {sretPtr, RetVal, structSize, ConstantInt::get (Type::getInt1Ty (*TheContext), 0 )});
10181028 }
10191029 else {
1020- // Option 2: Direct struct return (for small structs)
1021- if (RetVal->getType ()->isPointerTy ()) {
1022- // Load the struct value from the pointer
1023- RetVal = Builder->CreateLoad (returnType, RetVal, " struct_ret_load" );
1024- }
1025- Builder->CreateRet (RetVal);
1030+ // If RetVal is a struct value, store it
1031+ Builder->CreateStore (RetVal, sretPtr);
10261032 }
1033+
1034+
1035+ Builder->CreateRetVoid ();
1036+ // }
1037+ // else {
1038+ // // Option 2: Direct struct return (for small structs)
1039+ // if (RetVal->getType()->isPointerTy()) {
1040+ // // Load the struct value from the pointer
1041+ // RetVal = Builder->CreateLoad(returnType, RetVal, "struct_ret_load");
1042+ // }
1043+ // Builder->CreateRet(RetVal);
1044+ // }
10271045 }
10281046 else {
10291047 // Non-struct return, handle normally
@@ -1397,6 +1415,19 @@ void* ASTNode::generateBinaryExpression(int pass)
13971415 return nullptr ;
13981416 }
13991417
1418+ // Check if it is the pipe operator first
1419+ if (nodeType == Pipe_Operation) {
1420+ // add L to stack
1421+ Value* L = (Value*)(childNodes[0 ]->*(childNodes[0 ]->codegen ))(pass);
1422+ pipeOperationValue.push (L);
1423+ // then process R
1424+ Value* R = (Value*)(childNodes[1 ]->*(childNodes[1 ]->codegen ))(pass);
1425+ // pop stack
1426+ pipeOperationValue.pop ();
1427+
1428+ return R;
1429+ }
1430+
14001431 Value* L = (Value*)(childNodes[0 ]->*(childNodes[0 ]->codegen ))(pass);
14011432 Value* R = (Value*)(childNodes[1 ]->*(childNodes[1 ]->codegen ))(pass);
14021433
@@ -1412,14 +1443,26 @@ void* ASTNode::generateBinaryExpression(int pass)
14121443 if (L->getType () != R->getType ()) {
14131444 printTokenWarning (token, " Operand type mismatch, performing implicit conversion" );
14141445 castToHighestAccuracy (L, R, token);
1446+ if (L->getType () != R->getType ()) {
1447+ printTokenError (token, " Operands to multiply are not the same type (after automatic cast)" );
1448+ return nullptr ;
1449+ }
14151450 }
14161451
14171452 ValueCategory category = getValueCategory (L->getType ());
14181453
14191454 switch (category) {
14201455 case ValueCategory::Integer:
1456+ if (!L->getType ()->isIntegerTy () || !R->getType ()->isIntegerTy ()) {
1457+ printTokenError (token, " Multiply: operands are not both integers" );
1458+ return nullptr ;
1459+ }
14211460 return generateIntegerBinaryOp (L, R);
14221461 case ValueCategory::Float:
1462+ if (!L->getType ()->isFloatTy () || !R->getType ()->isFloatTy ()) {
1463+ printTokenError (token, " Multiply: operands are not both integers" );
1464+ return nullptr ;
1465+ }
14231466 return generateFloatBinaryOp (L, R);
14241467 case ValueCategory::Pointer:
14251468 return generatePointerBinaryOp (L, R);
@@ -1489,6 +1532,15 @@ Value* ASTNode::generatePointerBinaryOp(Value* L, Value* R)
14891532 return nullptr ;
14901533}
14911534
1535+ void * ASTNode::generatePipePlaceholder (int pass)
1536+ {
1537+ if (pipeOperationValue.size () > 0 ) {
1538+ return pipeOperationValue.top ();
1539+ }
1540+ printTokenError (token, " Pipe operation placeholder '%' can only be used after a pipe operation" );
1541+ return nullptr ;
1542+ }
1543+
14921544bool ASTNode::checkForOperatorOverload ()
14931545{
14941546 std::string operatorName = " operator." + tokenAsString (token->second );
@@ -2221,8 +2273,14 @@ void* ASTNode::generateCallExpression(int pass)
22212273 ArgsV.insert (ArgsV.begin (), sretAlloc);
22222274 }
22232275
2224- // Create the call (returns void for struct returns)
2225- Value* callResult = Builder->CreateCall (CalleeF, ArgsV, " calltmp" );
2276+ Value* callResult = nullptr ;
2277+ Type* retType = CalleeF->getReturnType ();
2278+
2279+ // Create the call
2280+ if (retType->isVoidTy ())
2281+ Builder->CreateCall (CalleeF, ArgsV);
2282+ else
2283+ callResult = Builder->CreateCall (CalleeF, ArgsV, " calltmp" );
22262284
22272285 // For struct returns, return the loaded struct value (or pointer if lvalue)
22282286 if (isStructReturn) {
@@ -2982,11 +3040,18 @@ int outputObjectFile(std::string& objectFilePath)
29823040 return 0 ;
29833041}
29843042
2985- int generateExecutable (const std::string& objectFilePath , const std::string& exeFilePath)
3043+ int generateExecutable (const std::string& irFilePath , const std::string& exeFilePath)
29863044{
2987- // Example using clang as the linker
2988- std::string command = " clang -o " + exeFilePath + " " + objectFilePath;
2989- int result = std::system (command.c_str ());
3045+ // llc to convert <name>.ll to assembly
3046+ std::string commandLLC = " llc " + irFilePath + " -o " + irFilePath + " .s" ;
3047+ int result = std::system (commandLLC.c_str ());
3048+ if (result != 0 )
3049+ exit (1 );
3050+ // clang as the linker
3051+ std::string commandClang = " clang -o " + exeFilePath + " " + irFilePath + " .s -g" ;
3052+ result = std::system (commandClang.c_str ());
3053+ if (result != 0 )
3054+ exit (1 );
29903055 return result;
29913056}
29923057
0 commit comments