Skip to content

Commit adea1d5

Browse files
committed
Add version option, change actual compilation method to llc
1 parent 495a7fd commit adea1d5

File tree

8 files changed

+202
-88
lines changed

8 files changed

+202
-88
lines changed

examples/start/main.asa

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,25 @@ create::string() #inline; #replaceable; {
2828
return *(#new string);
2929
}
3030
create :: string(c : *char) {
31-
s : string = *(#new string);
31+
s : string = string();
3232
puts("Creating new string from *char\n");
3333

34-
len : uint32 = 10;
35-
//for(i : 0..4_294_967_296){
36-
// //if(c[i] == '\0')
37-
// // break;
38-
// len++;
34+
//len : uint32 = 10;
35+
////for(i : 0..4_294_967_296){
36+
//// //if(c[i] == '\0')
37+
//// // break;
38+
//// len++;
39+
////}
40+
//s.address = malloc(10*2);
41+
//s.length = 10;
42+
////len = 5;
43+
////s.address = malloc(5);
44+
//for(i : 0..len){
45+
// s.address[i] = 'A';
46+
// //s.address[i] = c[i];
3947
//}
40-
s.address = malloc(10*2);
41-
s.length = 10;
42-
//len = 5;
43-
//s.address = malloc(5);
44-
for(i : 0..len){
45-
s.address[i] = 'A';
46-
//s.address[i] = c[i];
47-
}
48-
//s.length = len;
49-
//s.address = "String value example";
48+
////s.length = len;
49+
////s.address = "String value example";
5050
puts("Done!\n");
5151
return s;
5252
}
@@ -73,7 +73,7 @@ TEST_MACRO :: {printl("Macro works!")};
7373
//}
7474

7575
printint:: (n : uint64) #hideast {
76-
putchar(48+n);
76+
putchar(int(48+n));
7777
}
7878

7979
modifyReference::(n : ref int) #hideast {
@@ -103,22 +103,24 @@ main :: (){
103103

104104
//var : bool;
105105

106+
pipeVal = pipeTest(1);
107+
printint(pipeVal);
108+
newline();
109+
106110
s : string = string();
107111
s = string("This works");
108112

109-
pipeTest(1);
110-
111-
//s.length = 8;
113+
////s.length = 8;
114+
////printint(s.length);
115+
////s.size();
116+
//puts("printing string...");
117+
////s.length = 5;
112118
//printint(s.length);
113-
//s.size();
114-
puts("printing string...");
115-
//s.length = 5;
116-
printint(s.length);
117-
newline();
118-
s.print();
119-
puts("Done!");
119+
//newline();
120+
////s.print();
121+
//puts("Done!");
120122

121-
newline();
123+
//newline();
122124

123125
//puts(s.address);
124126

modules/Builtin/asa.asa

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,10 @@ Strings :: module{
178178

179179
PipeOperatorTest :: module{
180180
fnX :: int(x : int){
181-
return x*5;
181+
return x*3;
182182
}
183183
fnY :: int(y : int){
184-
return y*5;
184+
return y*2;
185185
}
186186
pipeTest::int(z : int){
187187
return fnX(z) -> fnY(%);

src/codegen.cpp

Lines changed: 106 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ llvm::Value* castValue(llvm::Value* value, llvm::Type* destType, bool isSrcSigne
2020

2121
std::unordered_map<std::string, Type*> unresolvedTypes;
2222
std::stack<Type*> lastRetrievedElementType;
23+
std::stack<Value*> pipeOperationValue;
2324

2425
std::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+
256272
functionID* 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+
14921544
bool 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

src/codegen.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ extern bool wasError;
2222

2323
void initializeCodeGenerator();
2424
int outputObjectFile(std::string& objectFilePath);
25-
int generateExecutable(const std::string& objectFilePath, const std::string& exeFilePath);
25+
int generateExecutable(const std::string& irFilePath, const std::string& exeFilePath);
2626
void removeUnusedPrototypes();
27+
void printFunctionPrototypes();

0 commit comments

Comments
 (0)