Optionally search relative to the current source file to find headers.
This commit is contained in:
parent
bc787c3adb
commit
11987fcb6d
|
@ -12,6 +12,10 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(APPLE)
|
||||||
|
#include <errno.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The function of the importer is to read in definitions from a file, and store
|
* The function of the importer is to read in definitions from a file, and store
|
||||||
* them into the symbol tables.
|
* them into the symbol tables.
|
||||||
|
@ -50,6 +54,10 @@
|
||||||
// Read in the string that we know must be there.
|
// Read in the string that we know must be there.
|
||||||
char* Module = strdup(CurrentIdentifier);
|
char* Module = strdup(CurrentIdentifier);
|
||||||
|
|
||||||
|
// Two strategies for finding the module; either it's relative to cwd, or it's relative to source.
|
||||||
|
bool FoundImport = false;
|
||||||
|
// Check the cwd first.
|
||||||
|
|
||||||
// Figure out the working directory
|
// Figure out the working directory
|
||||||
char CWD[PATH_MAX];
|
char CWD[PATH_MAX];
|
||||||
|
|
||||||
|
@ -65,8 +73,23 @@
|
||||||
|
|
||||||
// Stat the file to see if it exists
|
// Stat the file to see if it exists
|
||||||
struct stat FileInfo;
|
struct stat FileInfo;
|
||||||
if (stat(ModulePath, &FileInfo) != 0)
|
if (stat(ModulePath, &FileInfo) != 0) {
|
||||||
DieMessage("Unable to access the imported module", ModulePath);
|
free(ModulePath);
|
||||||
|
char SourcePath[PATH_MAX + 1];
|
||||||
|
realpath(CurrentFile->SourceName, SourcePath);
|
||||||
|
char* SourceFolderLength = strrchr(SourcePath, '/');
|
||||||
|
*(SourceFolderLength + 1) = '\0';
|
||||||
|
size_t SourcePathLength = strlen(SourcePath);
|
||||||
|
|
||||||
|
ModulePath = malloc(SourcePathLength + sizeof(Module) + 1);
|
||||||
|
strcpy(ModulePath, SourcePath);
|
||||||
|
strcpy(ModulePath + SourcePathLength, Module);
|
||||||
|
|
||||||
|
printf("Scanning %s for module definitions.\n", ModulePath);
|
||||||
|
|
||||||
|
if (stat(ModulePath, &FileInfo) != 0)
|
||||||
|
DieMessage("Unable to access the imported module", ModulePath);
|
||||||
|
}
|
||||||
|
|
||||||
// At this point, the file exists and we have the path.
|
// At this point, the file exists and we have the path.
|
||||||
// Save the current file, so that we can restore it later
|
// Save the current file, so that we can restore it later
|
||||||
|
|
|
@ -1337,4 +1337,903 @@ static struct AssemblerModule Win32ASMModule = {
|
||||||
|
|
||||||
void RegisterWin32ASM() {
|
void RegisterWin32ASM() {
|
||||||
RegisterModule(&Win32ASMModule);
|
RegisterModule(&Win32ASMModule);
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* * * * R E G I S T E R M A N A G E M E N T * * * *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
// Set all Registers to unused.
|
||||||
|
void DeallocateAllRegisters() {
|
||||||
|
UsedRegisters[0] = UsedRegisters[1] = UsedRegisters[2] = UsedRegisters[3] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Search for an unused register, allocate it, and return it.
|
||||||
|
* If none available, cancel compilation.
|
||||||
|
*/
|
||||||
|
int RetrieveRegister() {
|
||||||
|
for (size_t i = 0; i < 4; i++) {
|
||||||
|
if (UsedRegisters[i] == 0) {
|
||||||
|
UsedRegisters[i] = 1;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(stderr, "Out of registers!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the given register to unused.
|
||||||
|
* If the register is not used, it is an invalid state.
|
||||||
|
* @param Register: The Registers index to deallocate.
|
||||||
|
*/
|
||||||
|
void DeallocateRegister(int Register) {
|
||||||
|
if (UsedRegisters[Register] != 1) {
|
||||||
|
fprintf(stderr, "Error trying to free register %d\n", Register);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
UsedRegisters[Register] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* * * * * * S T A C K M A N A G E M E N T * * * * * *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prepare a new stack frame pointer.
|
||||||
|
* This resets the highest local.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void AsNewStackFrame() {
|
||||||
|
LocalVarOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given the type of input, how far do we need to go down the stack frame
|
||||||
|
* to store or retrieve this type?
|
||||||
|
*
|
||||||
|
* The stack must be 4-bytes aligned, so we set a hard minimum.
|
||||||
|
*
|
||||||
|
* @param Type: The DataTypes we want to store.
|
||||||
|
* @return the offset to store the type, taking into account the current state of the stack frame.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int AsCalcOffset(int Type) {
|
||||||
|
LocalVarOffset += PrimitiveSize(Type) > 4 ? PrimitiveSize(Type) : 4;
|
||||||
|
return -LocalVarOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* * * * C O D E G E N E R A T I O N * * * *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A way to keep track of the largest label number.
|
||||||
|
* Call this function to increase the number SRG-like.
|
||||||
|
*
|
||||||
|
* @return the highest available label number
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int NewLabel(void) {
|
||||||
|
static int id = 1;
|
||||||
|
return id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Align non-char types to a 4 byte alignment.
|
||||||
|
* Chars need no alignment on x86_64.
|
||||||
|
*
|
||||||
|
* @param Type: The DataTypes representation of the data to align
|
||||||
|
* @param Offset: The offset to align
|
||||||
|
* @param Direction: The desired direction to move the address for alignment. 1 = up, -1 = down.
|
||||||
|
* @return the new alignment
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int AsAlignMemory(int Type, int Offset, int Direction) {
|
||||||
|
switch (Type) {
|
||||||
|
case RET_CHAR:
|
||||||
|
return Offset;
|
||||||
|
case RET_INT:
|
||||||
|
case RET_LONG:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DieDecimal("Unable to align type", Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Alignment = 4;
|
||||||
|
Offset = (Offset + Direction * (Alignment - 1)) & ~(Alignment - 1);
|
||||||
|
return (Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble an If statement
|
||||||
|
int AsIf(struct ASTNode* Node, int LoopStartLabel, int LoopEndLabel) {
|
||||||
|
int FalseLabel, EndLabel;
|
||||||
|
|
||||||
|
FalseLabel = NewLabel();
|
||||||
|
if (Node->Right)
|
||||||
|
EndLabel = NewLabel();
|
||||||
|
|
||||||
|
// Left is the condition
|
||||||
|
AssembleTree(Node->Left, FalseLabel, LoopStartLabel, LoopEndLabel, Node->Operation);
|
||||||
|
DeallocateAllRegisters();
|
||||||
|
|
||||||
|
// Middle is the true block
|
||||||
|
AssembleTree(Node->Middle, -1, LoopStartLabel, LoopEndLabel, Node->Operation);
|
||||||
|
DeallocateAllRegisters();
|
||||||
|
|
||||||
|
// Right is the optional else
|
||||||
|
if (Node->Right)
|
||||||
|
AsJmp(EndLabel);
|
||||||
|
|
||||||
|
AsLabel(FalseLabel);
|
||||||
|
|
||||||
|
if (Node->Right) {
|
||||||
|
AssembleTree(Node->Right, -1, LoopStartLabel, LoopEndLabel, Node->Operation);
|
||||||
|
DeallocateAllRegisters();
|
||||||
|
AsLabel(EndLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a comparison
|
||||||
|
int AsCompare(int Operation, int RegisterLeft, int RegisterRight) {
|
||||||
|
printf("Comparing registers %d & %d\n", RegisterLeft, RegisterRight);
|
||||||
|
|
||||||
|
if (Operation < OP_EQUAL || Operation > OP_GREATE)
|
||||||
|
Die("Bad Operation in AsCompare");
|
||||||
|
|
||||||
|
fprintf(OutputFile, "\tcmpq\t%s, %s\n", Registers[RegisterRight], Registers[RegisterLeft]);
|
||||||
|
fprintf(OutputFile, "\t%s\t\t%s\n", Comparisons[Operation - OP_EQUAL], ByteRegisters[RegisterRight]);
|
||||||
|
fprintf(OutputFile, "\tmovzbq\t%s, %s\n", ByteRegisters[RegisterRight], Registers[RegisterLeft]);
|
||||||
|
DeallocateRegister(RegisterLeft);
|
||||||
|
return RegisterRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble an inverse comparison (a one-line jump)
|
||||||
|
int AsCompareJmp(int Operation, int RegisterLeft, int RegisterRight, int Label) {
|
||||||
|
if (Operation < OP_EQUAL || Operation > OP_GREATE)
|
||||||
|
Die("Bad Operation in AsCompareJmp");
|
||||||
|
|
||||||
|
printf("\tBranching on comparison of registers %d & %d, with operation %s\n\n", RegisterLeft, RegisterRight,
|
||||||
|
Comparisons[Operation - OP_EQUAL]);
|
||||||
|
|
||||||
|
fprintf(OutputFile, "\tcmpq\t%s, %s\n", Registers[RegisterRight], Registers[RegisterLeft]);
|
||||||
|
fprintf(OutputFile, "\t%s\tL%d\n", InvComparisons[Operation - OP_EQUAL], Label);
|
||||||
|
DeallocateAllRegisters();
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble an immediate jump
|
||||||
|
void AsJmp(int Label) {
|
||||||
|
printf("\t\tJumping to label %d\n", Label);
|
||||||
|
fprintf(OutputFile, "\tjmp\tL%d\n", Label);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a new base label
|
||||||
|
* @param Label: The number to create the label of
|
||||||
|
*/
|
||||||
|
void AsLabel(int Label) {
|
||||||
|
printf("\tCreating label %d\n", Label);
|
||||||
|
fprintf(OutputFile, "\nL%d:\n", Label);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assemble a new global string into the data segment.
|
||||||
|
* @param Value: The name of the string, as a string
|
||||||
|
*/
|
||||||
|
int AsNewString(char* Value) {
|
||||||
|
int Label = NewLabel();
|
||||||
|
char* CharPtr;
|
||||||
|
|
||||||
|
AsLabel(Label);
|
||||||
|
|
||||||
|
for (CharPtr = Value; *CharPtr; CharPtr++)
|
||||||
|
fprintf(OutputFile, "\t.byte\t%d\r\n", *CharPtr);
|
||||||
|
fprintf(OutputFile, "\t.byte\t0\r\n");
|
||||||
|
|
||||||
|
return Label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load a string into a Register.
|
||||||
|
* @param ID: the Label number of the string
|
||||||
|
*/
|
||||||
|
int AsLoadString(int ID) {
|
||||||
|
int Register = RetrieveRegister();
|
||||||
|
fprintf(OutputFile, "\tleaq\tL%d(\%%rip), %s\r\n", ID, Registers[Register]);
|
||||||
|
return Register;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a While loop
|
||||||
|
int AsWhile(struct ASTNode* Node) {
|
||||||
|
int BodyLabel, BreakLabel;
|
||||||
|
|
||||||
|
BodyLabel = NewLabel();
|
||||||
|
BreakLabel = NewLabel();
|
||||||
|
|
||||||
|
printf("\tInitiating loop between labels %d and %d\n", BodyLabel, BreakLabel);
|
||||||
|
|
||||||
|
// Mark the start position
|
||||||
|
AsLabel(BodyLabel);
|
||||||
|
|
||||||
|
// Assemble the condition - this should include a jump to end!
|
||||||
|
AssembleTree(Node->Left, BreakLabel, BodyLabel, BreakLabel, Node->Operation);
|
||||||
|
DeallocateAllRegisters();
|
||||||
|
|
||||||
|
// Assemble the body
|
||||||
|
AssembleTree(Node->Right, -1, BodyLabel, BreakLabel, Node->Operation);
|
||||||
|
DeallocateAllRegisters();
|
||||||
|
|
||||||
|
// Jump back to the body - as awe've already failed the condition check if we get here
|
||||||
|
AsJmp(BodyLabel);
|
||||||
|
|
||||||
|
// Set up the label to break out of the loop.
|
||||||
|
AsLabel(BreakLabel);
|
||||||
|
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load a value into a register.
|
||||||
|
int AsLoad(int Value) {
|
||||||
|
int Register = RetrieveRegister();
|
||||||
|
|
||||||
|
printf("\tStoring value %d into %s\n", Value, Registers[Register]);
|
||||||
|
|
||||||
|
fprintf(OutputFile, "\tmovq\t$%d, %s\n", Value, Registers[Register]);
|
||||||
|
|
||||||
|
return Register;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble an addition.
|
||||||
|
int AsAdd(int Left, int Right) {
|
||||||
|
printf("\tAdding Registers %s, %s\n", Registers[Left], Registers[Right]);
|
||||||
|
fprintf(OutputFile, "\taddq\t%s, %s\n", Registers[Left], Registers[Right]);
|
||||||
|
|
||||||
|
DeallocateRegister(Left);
|
||||||
|
|
||||||
|
return Right;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a multiplication.
|
||||||
|
int AsMul(int Left, int Right) {
|
||||||
|
printf("\tMultiplying Registers %s, %s\n", Registers[Left], Registers[Right]);
|
||||||
|
fprintf(OutputFile, "\timulq\t%s, %s\n", Registers[Left], Registers[Right]);
|
||||||
|
|
||||||
|
DeallocateRegister(Left);
|
||||||
|
|
||||||
|
return Right;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a subtraction.
|
||||||
|
int AsSub(int Left, int Right) {
|
||||||
|
printf("\tSubtracting Registers %s, %s\n", Registers[Left], Registers[Right]);
|
||||||
|
fprintf(OutputFile, "\tsubq\t%s, %s\n", Registers[Right], Registers[Left]);
|
||||||
|
|
||||||
|
DeallocateRegister(Right);
|
||||||
|
|
||||||
|
return Left;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a division.
|
||||||
|
int AsDiv(int Left, int Right) {
|
||||||
|
printf("\tDividing Registers %s, %s\n", Registers[Left], Registers[Right]);
|
||||||
|
fprintf(OutputFile, "\tmovq\t%s, %%rax\n", Registers[Left]);
|
||||||
|
fprintf(OutputFile, "\tcqo\n");
|
||||||
|
fprintf(OutputFile, "\tidivq\t%s\n", Registers[Right]);
|
||||||
|
fprintf(OutputFile, "\tmovq\t%%rax, %s\n", Registers[Left]);
|
||||||
|
|
||||||
|
DeallocateRegister(Right);
|
||||||
|
|
||||||
|
return Left;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble an ASL
|
||||||
|
int AsShl(int Register, int Val) {
|
||||||
|
printf("\tShifting %s to the left by %d bits.\n", Registers[Register], Val);
|
||||||
|
fprintf(OutputFile, "\tsalq\t$%d, %s\n", Val, Registers[Register]);
|
||||||
|
return Register;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load a global variable into a register, with optional pre/post-inc/dec
|
||||||
|
* @param Entry: The variable to load.
|
||||||
|
* @param Operation: An optional SyntaxOps element
|
||||||
|
*/
|
||||||
|
int AsLdGlobalVar(struct SymbolTableEntry* Entry, int Operation) {
|
||||||
|
int Reg = RetrieveRegister();
|
||||||
|
printf("\tGlobally storing a %s\n", ScopeNames[Entry->Storage]);
|
||||||
|
printf("\tStoring %s's contents into %s, globally\n", Entry->Name, Registers[Reg]);
|
||||||
|
|
||||||
|
int TypeSize = PrimitiveSize(Entry->Type);
|
||||||
|
switch (TypeSize) {
|
||||||
|
case 1:
|
||||||
|
switch (Operation) {
|
||||||
|
case OP_PREINC:
|
||||||
|
fprintf(OutputFile, "\tincb\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
|
case OP_PREDEC:
|
||||||
|
fprintf(OutputFile, "\tdecb\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(OutputFile, "\tmovzbq\t%s(\%%rip), %s\n", Entry->Name, Registers[Reg]);
|
||||||
|
|
||||||
|
switch (Operation) {
|
||||||
|
case OP_POSTINC:
|
||||||
|
fprintf(OutputFile, "\tincb\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
|
case OP_POSTDEC:
|
||||||
|
fprintf(OutputFile, "\tdecb\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
switch (Operation) {
|
||||||
|
case OP_PREINC:
|
||||||
|
fprintf(OutputFile, "\tincl\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
|
case OP_PREDEC:
|
||||||
|
fprintf(OutputFile, "\tdecl\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(OutputFile, "\tmovslq\t%s(\%%rip), %s\n", Entry->Name, Registers[Reg]);
|
||||||
|
|
||||||
|
switch (Operation) {
|
||||||
|
case OP_POSTINC:
|
||||||
|
fprintf(OutputFile, "\tincl\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
|
case OP_POSTDEC:
|
||||||
|
fprintf(OutputFile, "\tdecl\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
switch (Operation) {
|
||||||
|
case OP_PREINC:
|
||||||
|
fprintf(OutputFile, "\tincq\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
|
case OP_PREDEC:
|
||||||
|
fprintf(OutputFile, "\tdecq\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(OutputFile, "\tmovq\t%s(\%%rip), %s\n", Entry->Name, Registers[Reg]);
|
||||||
|
|
||||||
|
switch (Operation) {
|
||||||
|
case OP_POSTINC:
|
||||||
|
fprintf(OutputFile, "\tincq\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
|
case OP_POSTDEC:
|
||||||
|
fprintf(OutputFile, "\tdecq\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DieMessage("Bad type for loading", TypeNames(Entry->Type));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store a value from a register into a global variable.
|
||||||
|
* @param Entry: The variable to store into.
|
||||||
|
* @param Regsiter: The Registers index containing the value to store.
|
||||||
|
*/
|
||||||
|
int AsStrGlobalVar(struct SymbolTableEntry* Entry, int Register) {
|
||||||
|
printf("\tStoring contents of %s into %s, type %d, globally:\n", Registers[Register], Entry->Name, Entry->Type);
|
||||||
|
|
||||||
|
int TypeSize = PrimitiveSize(Entry->Type);
|
||||||
|
switch (TypeSize) {
|
||||||
|
case 1:
|
||||||
|
// movzbq zeroes, then moves a byte into the quad register
|
||||||
|
fprintf(OutputFile, "\tmovb\t%s, %s(\%%rip)\n", ByteRegisters[Register], Entry->Name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
fprintf(OutputFile, "\tmovl\t%s, %s(\%%rip)\n", DoubleRegisters[Register], Entry->Name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
fprintf(OutputFile, "\tmovq\t%s, %s(%%rip)\n", Registers[Register], Entry->Name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DieMessage("Bad type for saving", TypeNames(Entry->Type));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Register;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load a value from a local variable into a register, with optional post/pre-inc/dec
|
||||||
|
* @param Entry: The local variable to read
|
||||||
|
* @param Operation: An optional SyntaxOps entry
|
||||||
|
*/
|
||||||
|
|
||||||
|
int AsLdLocalVar(struct SymbolTableEntry* Entry, int Operation) {
|
||||||
|
int Reg = RetrieveRegister();
|
||||||
|
|
||||||
|
printf("\tStoring the var at %d's contents into %s, locally\n", Entry->SinkOffset, Registers[Reg]);
|
||||||
|
|
||||||
|
int TypeSize = PrimitiveSize(Entry->Type);
|
||||||
|
switch (TypeSize) {
|
||||||
|
case 1:
|
||||||
|
switch (Operation) {
|
||||||
|
case OP_PREINC:
|
||||||
|
fprintf(OutputFile, "\tincb\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
|
case OP_PREDEC:
|
||||||
|
fprintf(OutputFile, "\tdecb\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(OutputFile, "\tmovzbq\t%d(\%%rbp), %s\n", Entry->SinkOffset, Registers[Reg]);
|
||||||
|
|
||||||
|
switch (Operation) {
|
||||||
|
case OP_POSTINC:
|
||||||
|
fprintf(OutputFile, "\tincb\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
|
case OP_POSTDEC:
|
||||||
|
fprintf(OutputFile, "\tdecb\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
switch (Operation) {
|
||||||
|
case OP_PREINC:
|
||||||
|
fprintf(OutputFile, "\tincl\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
|
case OP_PREDEC:
|
||||||
|
fprintf(OutputFile, "\tdecl\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(OutputFile, "\tmovslq\t%d(\%%rbp), %s\n", Entry->SinkOffset, Registers[Reg]);
|
||||||
|
|
||||||
|
switch (Operation) {
|
||||||
|
case OP_POSTINC:
|
||||||
|
fprintf(OutputFile, "\tincl\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
|
case OP_POSTDEC:
|
||||||
|
fprintf(OutputFile, "\tdecl\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
switch (Operation) {
|
||||||
|
case OP_PREINC:
|
||||||
|
fprintf(OutputFile, "\tincq\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
|
case OP_PREDEC:
|
||||||
|
fprintf(OutputFile, "\tdecq\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(OutputFile, "\tmovq\t%d(\%%rbp), %s\n", Entry->SinkOffset, Registers[Reg]);
|
||||||
|
|
||||||
|
switch (Operation) {
|
||||||
|
case OP_POSTINC:
|
||||||
|
fprintf(OutputFile, "\tincq\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
|
case OP_POSTDEC:
|
||||||
|
fprintf(OutputFile, "\tdecq\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DieMessage("Bad type for loading", TypeNames(Entry->Type));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store a value from a register into a local variable.
|
||||||
|
* @param Entry: The local variable to write to.
|
||||||
|
* @param Register: The Registers index containing the desired value
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int AsStrLocalVar(struct SymbolTableEntry* Entry, int Register) {
|
||||||
|
printf("\tStoring contents of %s into %s, type %d, locally\n", Registers[Register], Entry->Name, Entry->Type);
|
||||||
|
|
||||||
|
int TypeSize = PrimitiveSize(Entry->Type);
|
||||||
|
switch (TypeSize) {
|
||||||
|
case 1:
|
||||||
|
// movzbq zeroes, then moves a byte into the quad register
|
||||||
|
fprintf(OutputFile, "\tmovb\t%s, %d(\%%rbp)\n", ByteRegisters[Register], Entry->SinkOffset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
fprintf(OutputFile, "\tmovl\t%s, %d(\%%rbp)\n", DoubleRegisters[Register], Entry->SinkOffset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
fprintf(OutputFile, "\tmovq\t%s, %d(%%rbp)\n", Registers[Register], Entry->SinkOffset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DieMessage("Bad type for saving", TypeNames(Entry->Type));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Register;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a pointerisation
|
||||||
|
int AsAddr(struct SymbolTableEntry* Entry) {
|
||||||
|
int Register = RetrieveRegister();
|
||||||
|
printf("\tSaving pointer of %s into %s\n", Entry->Name, Registers[Register]);
|
||||||
|
|
||||||
|
fprintf(OutputFile, "\tleaq\t%s(%%rip), %s\n", Entry->Name, Registers[Register]);
|
||||||
|
return Register;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a dereference
|
||||||
|
int AsDeref(int Reg, int Type) {
|
||||||
|
|
||||||
|
int DestSize = PrimitiveSize(ValueAt(Type));
|
||||||
|
|
||||||
|
printf("\tDereferencing %s\n", Registers[Reg]);
|
||||||
|
switch (DestSize) {
|
||||||
|
case 1:
|
||||||
|
fprintf(OutputFile, "\tmovzbq\t(%s), %s\n", Registers[Reg], Registers[Reg]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
fprintf(OutputFile, "\tmovslq\t(%s), %s\n", Registers[Reg], DoubleRegisters[Reg]);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
fprintf(OutputFile, "\tmovl\t(%s), %s\n", Registers[Reg], DoubleRegisters[Reg]);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
fprintf(OutputFile, "\tmovq\t(%s), %s\n", Registers[Reg], Registers[Reg]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DieDecimal("Can't generate dereference for type", Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a store-through-dereference
|
||||||
|
int AsStrDeref(int Register1, int Register2, int Type) {
|
||||||
|
printf("\tStoring contents of %s into %s through a dereference, type %d\n", Registers[Register1],
|
||||||
|
Registers[Register2], Type);
|
||||||
|
|
||||||
|
switch (Type) {
|
||||||
|
case RET_CHAR:
|
||||||
|
fprintf(OutputFile, "\tmovb\t%s, (%s)\n", ByteRegisters[Register1], Registers[Register2]);
|
||||||
|
break;
|
||||||
|
case RET_INT:
|
||||||
|
fprintf(OutputFile, "\tmovl\t%s, (%s)\n", DoubleRegisters[Register1], Registers[Register2]);
|
||||||
|
break;
|
||||||
|
case RET_LONG:
|
||||||
|
fprintf(OutputFile, "\tmovq\t%s, (%s)\n", Registers[Register1], Registers[Register2]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DieDecimal("Can't generate store-into-deref of type", Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Register1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a global symbol (variable, struct, enum, function, string)
|
||||||
|
void AsGlobalSymbol(struct SymbolTableEntry* Entry) {
|
||||||
|
|
||||||
|
if (Entry == NULL) return;
|
||||||
|
if (Entry->Structure == ST_FUNC) return;
|
||||||
|
|
||||||
|
|
||||||
|
int Size = TypeSize(Entry->Type, Entry->CompositeType);
|
||||||
|
|
||||||
|
fprintf(OutputFile, "\t.data\n"
|
||||||
|
"\t.globl\t%s\n",
|
||||||
|
Entry->Name);
|
||||||
|
|
||||||
|
fprintf(OutputFile, "%s:\n", Entry->Name);
|
||||||
|
|
||||||
|
switch (Size) {
|
||||||
|
case 1:
|
||||||
|
fprintf(OutputFile, "\t.byte\t0\r\n");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
fprintf(OutputFile, "\t.long\t0\r\n");
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
fprintf(OutputFile, "\t.quad\t0\r\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
for (int i = 0; i < Size; i++)
|
||||||
|
fprintf(OutputFile, "\t.byte\t0\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a function call, with all associated parameter bumping and stack movement.
|
||||||
|
int AsCallWrapper(struct ASTNode* Node) {
|
||||||
|
struct ASTNode* CompositeTree = Node->Left;
|
||||||
|
int Register, Args = 0;
|
||||||
|
|
||||||
|
while (CompositeTree) {
|
||||||
|
Register = AssembleTree(CompositeTree->Right, -1, -1, -1, CompositeTree->Operation);
|
||||||
|
AsCopyArgs(Register, CompositeTree->Size);
|
||||||
|
if (Args == 0) Args = CompositeTree->Size;
|
||||||
|
DeallocateAllRegisters();
|
||||||
|
CompositeTree = CompositeTree->Left;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AsCall(Node->Symbol, Args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy a function argument from Register to argument Position
|
||||||
|
void AsCopyArgs(int Register, int Position) {
|
||||||
|
if (Position > 4) { // Args above 4 go on the stack
|
||||||
|
fprintf(OutputFile, "\tpushq\t%s\n", Registers[Register]);
|
||||||
|
} else {
|
||||||
|
fprintf(OutputFile, "\tmovq\t%s, %s\n", Registers[Register], Registers[8 - Position]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble an actual function call.
|
||||||
|
// NOTE: this should not be called. Use AsCallWrapper.
|
||||||
|
int AsCall(struct SymbolTableEntry* Entry, int Args) {
|
||||||
|
|
||||||
|
int OutRegister = RetrieveRegister();
|
||||||
|
|
||||||
|
printf("\t\tCalling function %s with %d parameters\n", Entry->Name, Args);
|
||||||
|
printf("\t\t\tFunction returns into %s\n", Registers[OutRegister]);
|
||||||
|
|
||||||
|
// Allocate shadow space
|
||||||
|
fprintf(OutputFile, "\taddq\t$-32, %%rsp\n");
|
||||||
|
fprintf(OutputFile, "\tcall\t%s\n", Entry->Name);
|
||||||
|
// Deallocate arguments and stack space.
|
||||||
|
if (Args > 4)
|
||||||
|
fprintf(OutputFile, "\taddq\t$%d, %%rsp\n", (8 * (Args - 4)) + 32);
|
||||||
|
else
|
||||||
|
fprintf(OutputFile, "\taddq\t$32, %%rsp\n");
|
||||||
|
|
||||||
|
fprintf(OutputFile, "\tmovq\t%%rax, %s\n", Registers[OutRegister]);
|
||||||
|
|
||||||
|
return OutRegister;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a function return.
|
||||||
|
int AsReturn(struct SymbolTableEntry* Entry, int Register) {
|
||||||
|
|
||||||
|
printf("\t\tCreating return for function %s\n", Entry->Name);
|
||||||
|
|
||||||
|
switch (Entry->Type) {
|
||||||
|
case RET_CHAR:
|
||||||
|
fprintf(OutputFile, "\tmovzbl\t%s, %%eax\n", ByteRegisters[Register]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RET_INT:
|
||||||
|
fprintf(OutputFile, "\tmovl\t%s, %%eax\n", DoubleRegisters[Register]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RET_LONG:
|
||||||
|
fprintf(OutputFile, "\tmovq\t%s, %%rax\n", Registers[Register]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DieMessage("Bad function type in generating return", TypeNames(Entry->Type));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
AsJmp(Entry->EndLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Assemble a =?
|
||||||
|
int AsEqual(int Left, int Right) {
|
||||||
|
// Set the lowest bit if left = right
|
||||||
|
return AsCompare(OP_EQUAL, Left, Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a !=
|
||||||
|
int AsIneq(int Left, int Right) {
|
||||||
|
// Set the lowest bit if left != right
|
||||||
|
return AsCompare(OP_INEQ, Left, Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a <
|
||||||
|
int AsLess(int Left, int Right) {
|
||||||
|
// Set the lowest bit if left < right
|
||||||
|
return AsCompare(OP_LESS, Left, Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a >
|
||||||
|
int AsGreat(int Left, int Right) {
|
||||||
|
// Set the lowest bit if left > right
|
||||||
|
return AsCompare(OP_GREAT, Left, Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a <=
|
||||||
|
int AsLessE(int Left, int Right) {
|
||||||
|
// Set the lowest bit if left <= right
|
||||||
|
return AsCompare(OP_LESSE, Left, Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a =>
|
||||||
|
int AsGreatE(int Left, int Right) {
|
||||||
|
// Set the lowest bit if left => right
|
||||||
|
return AsCompare(OP_GREATE, Left, Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a print statement
|
||||||
|
void AssemblerPrint(int Register) {
|
||||||
|
printf("\t\tPrinting Register %s\n", Registers[Register]);
|
||||||
|
|
||||||
|
fprintf(OutputFile, "\tmovq\t%s, %%rcx\n", Registers[Register]);
|
||||||
|
//fprintf(OutputFile, "\tleaq\t.LC0(%%rip), %%rcx\n");
|
||||||
|
fprintf(OutputFile, "\tcall\tPrintInteger\n");
|
||||||
|
|
||||||
|
DeallocateRegister(Register);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a &
|
||||||
|
int AsBitwiseAND(int Left, int Right) {
|
||||||
|
fprintf(OutputFile, "\tandq\t%s, %s\n", Registers[Left], Registers[Right]);
|
||||||
|
DeallocateRegister(Left);
|
||||||
|
return Right;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a |
|
||||||
|
int AsBitwiseOR(int Left, int Right) {
|
||||||
|
fprintf(OutputFile, "\torq\t%s, %s\n", Registers[Left], Registers[Right]);
|
||||||
|
DeallocateRegister(Left);
|
||||||
|
return Right;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a ^
|
||||||
|
int AsBitwiseXOR(int Left, int Right) {
|
||||||
|
fprintf(OutputFile, "\txorq\t%s, %s\n", Registers[Left], Registers[Right]);
|
||||||
|
DeallocateRegister(Left);
|
||||||
|
return Right;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a ~
|
||||||
|
int AsNegate(int Register) {
|
||||||
|
fprintf(OutputFile, "\tnegq\t%s\n", Registers[Register]);
|
||||||
|
return Register;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a !
|
||||||
|
int AsInvert(int Register) {
|
||||||
|
fprintf(OutputFile, "\tnotq\t%s\n", Registers[Register]);
|
||||||
|
return Register;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a !
|
||||||
|
int AsBooleanNOT(int Register) {
|
||||||
|
fprintf(OutputFile, "\ttest\t%s, %s\n", Registers[Register], Registers[Register]);
|
||||||
|
fprintf(OutputFile, "\tsete\t%s\n", ByteRegisters[Register]);
|
||||||
|
fprintf(OutputFile, "\tmovzbq\t%s, %s\n", ByteRegisters[Register], Registers[Register]);
|
||||||
|
return Register;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a <<
|
||||||
|
int AsShiftLeft(int Left, int Right) {
|
||||||
|
fprintf(OutputFile, "\tmovb\t%s, \%%cl\n", ByteRegisters[Right]);
|
||||||
|
fprintf(OutputFile, "\tshlq\t\%%cl, %s\n", Registers[Left]);
|
||||||
|
DeallocateRegister(Right);
|
||||||
|
return Left;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a >>
|
||||||
|
int AsShiftRight(int Left, int Right) {
|
||||||
|
fprintf(OutputFile, "\tmovb\t%s, \%%cl\n", ByteRegisters[Right]);
|
||||||
|
fprintf(OutputFile, "\tshrq\t\%%cl, %s\n", Registers[Left]);
|
||||||
|
DeallocateRegister(Right);
|
||||||
|
return Left;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble a conversion from arbitrary type to boolean.
|
||||||
|
// Facilitates if(ptr)
|
||||||
|
int AsBooleanConvert(int Register, int Operation, int Label) {
|
||||||
|
fprintf(OutputFile, "\ttest\t%s, %s\n", Registers[Register], Registers[Register]);
|
||||||
|
|
||||||
|
switch (Operation) {
|
||||||
|
case OP_IF:
|
||||||
|
case OP_LOOP:
|
||||||
|
fprintf(OutputFile, "\tje\tL%d\n", Label);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(OutputFile, "\tsetnz\t%s\n", ByteRegisters[Register]);
|
||||||
|
fprintf(OutputFile, "\tmovzbq\t%s, %s\n", ByteRegisters[Register], Registers[Register]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Register;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble the start of an assembly file
|
||||||
|
void AssemblerPreamble() {
|
||||||
|
DeallocateAllRegisters();
|
||||||
|
fputs(
|
||||||
|
"\t.text\n", /*
|
||||||
|
".LC0:\n"
|
||||||
|
"\t.string\t\"%d\\n\"\n", */
|
||||||
|
OutputFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assemble a function block for the Entry.
|
||||||
|
* Handles all stack logic for local variables,
|
||||||
|
* as well as copying parameters out of registers and
|
||||||
|
* into the spill space.
|
||||||
|
*
|
||||||
|
* @param Entry: The function to generate
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void AsFunctionPreamble(struct SymbolTableEntry* Entry) {
|
||||||
|
char* Name = Entry->Name;
|
||||||
|
struct SymbolTableEntry* Param, * Local;
|
||||||
|
int ParamOffset = 0, ParamReg = 9, ParamCount = 0;
|
||||||
|
|
||||||
|
LocalVarOffset = 4; // Prepare parameters
|
||||||
|
|
||||||
|
fprintf(OutputFile,
|
||||||
|
"\t.text\n"
|
||||||
|
"\t.globl\t%s\n"
|
||||||
|
"\t.def\t%s; .scl 2; .type 32; .endef\n"
|
||||||
|
"%s:\n"
|
||||||
|
"\tpushq\t%%rbp\n"
|
||||||
|
"\tmovq\t%%rsp, %%rbp\r\n",
|
||||||
|
Name, Name, Name);
|
||||||
|
|
||||||
|
//PECOFF requires we call the global initialisers
|
||||||
|
if (!strcmp(Name, "main"))
|
||||||
|
fprintf(OutputFile, "\tcall\t__main\n");
|
||||||
|
|
||||||
|
// Need to share this between two loops. Fun.
|
||||||
|
int LoopIndex;
|
||||||
|
|
||||||
|
// If we have parameters, move them to the last 4 registers
|
||||||
|
for (Param = Entry->Start, ParamCount = 1; Param != NULL; Param = Param->NextSymbol, ParamCount++) {
|
||||||
|
if (ParamCount > 4) { // We only have 4 argument registers
|
||||||
|
Param->SinkOffset = ParamOffset;
|
||||||
|
ParamOffset += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry->SinkOffset = AsCalcOffset(Param->Type);
|
||||||
|
AsStrLocalVar(Param, ParamReg--);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have more parameters, move them to the stack
|
||||||
|
for (Local = Locals; Local != NULL; Local = Local->NextSymbol) {
|
||||||
|
Local->SinkOffset = AsCalcOffset(Local->Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// With all the parameters on the stack, we can allocate the shadow space
|
||||||
|
StackFrameOffset = ((LocalVarOffset + 31) & ~31);
|
||||||
|
fprintf(OutputFile,
|
||||||
|
"\taddq\t$%d, %%rsp\n", -StackFrameOffset);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Assemble the epilogue of a function
|
||||||
|
void AsFunctionEpilogue(struct SymbolTableEntry* Entry) {
|
||||||
|
AsLabel(Entry->EndLabel);
|
||||||
|
|
||||||
|
fprintf(OutputFile,
|
||||||
|
"\tpopq\t%%rbp\n"
|
||||||
|
"\taddq\t$%d, %%rsp\n"
|
||||||
|
"\tret\n",
|
||||||
|
StackFrameOffset);
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import "tests/import/defs.eh"
|
import "import/defs.eh"
|
||||||
|
|
||||||
long num[100];
|
long num[100];
|
||||||
int :: main() {
|
int :: main() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user