From 6eb61f905fe5762e270bb8e99936c6a63012bf70 Mon Sep 17 00:00:00 2001 From: Marvin Kaiser Date: Wed, 4 Mar 2020 19:29:24 +0100 Subject: [PATCH] 25: Add logic for handling float in function calls --- .../hsrm/compiler/Klang/visitors/GenASM.java | 252 ++++++++++-------- src/test/functionCall/functionCall.c | 33 +++ src/test/functionCall/functionCall.h | 24 +- src/test/print/print.c | 10 + src/test/print/print.h | 3 + src/test/test.k | 84 ++++++ 6 files changed, 295 insertions(+), 111 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java index cf94562..f1b5efc 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -1,6 +1,7 @@ package de.hsrm.compiler.Klang.visitors; import java.io.*; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -61,9 +62,15 @@ public class GenASM implements Visitor { private int id = -1; public String getFloat(double d) { - String binary = Long.toBinaryString(Double.doubleToLongBits(d)); - String upper = binary.substring(0, 30); - String lower = binary.substring(31, 61); + Long longBits = Double.doubleToRawLongBits(d); + String binary = Long.toBinaryString(longBits); + int padCount = 64 - binary.length(); + while (padCount > 0) { + binary = "0" + binary; + padCount--; + } + String upper = binary.substring(0, 32); + String lower = binary.substring(32, 64); long first = Long.parseLong(lower, 2); long second = Long.parseLong(upper, 2); String lbl = ".FL" + ++id; @@ -101,12 +108,12 @@ public class GenASM implements Visitor { private String mainName; Map env = new HashMap<>(); Set vars; - String[] rs = { "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9" }; - String[] frs = {"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"}; + String[] registers = { "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9" }; + String[] floatRegisters = { "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" }; private int lCount = 0; // Invariante: lCount ist benutzt private void intToFloat(String src, String dst) { - this.ex.write(" cvtsi2sd " + src +", " + dst + "\n"); + this.ex.write(" cvtsi2sd " + src + ", " + dst + "\n"); } private boolean prepareRegisters(Expression lhs, Expression rhs) { @@ -131,8 +138,6 @@ public class GenASM implements Visitor { this.ex.write(" popq %rbx\n"); return false; } - - public GenASM(ExWriter ex, String mainName) { this.ex = ex; this.mainName = mainName; @@ -183,14 +188,14 @@ public class GenASM implements Visitor { } else { this.ex.write(" cmp %rax, %rbx\n"); } - this.ex.write(" je .L" + lblTrue + "\n"); - // false - this.ex.write(" movq $0, %rax\n"); - this.ex.write(" jmp .L" + lblEnd + "\n"); - this.ex.write(".L" + lblTrue + ":\n"); - // true - this.ex.write(" movq $1, %rax\n"); - this.ex.write(".L" + lblEnd + ":\n"); + this.ex.write(" je .L" + lblTrue + "\n"); + // false + this.ex.write(" movq $0, %rax\n"); + this.ex.write(" jmp .L" + lblEnd + "\n"); + this.ex.write(".L" + lblTrue + ":\n"); + // true + this.ex.write(" movq $1, %rax\n"); + this.ex.write(".L" + lblEnd + ":\n"); return null; } @@ -243,7 +248,6 @@ public class GenASM implements Visitor { int lblTrue = ++lCount; int lblEnd = ++lCount; - boolean isFloatOperation = this.prepareRegisters(e.lhs, e.rhs); if (isFloatOperation) { this.ex.write(" ucomisd %xmm0, %xmm1\n"); @@ -430,20 +434,20 @@ public class GenASM implements Visitor { // also ist das Gesamtergebnis false e.rhs.welcome(this); this.ex.write(" cmpq $0, %rax\n"); - this.ex.write(" je .L" + lblFalse +"\n"); + this.ex.write(" je .L" + lblFalse + "\n"); // Die Expression wertet zu true aus // Springe am false Teil vorbei - this.ex.write(".L" + lblTrue +":\n"); + this.ex.write(".L" + lblTrue + ":\n"); this.ex.write(" movq $1, %rax\n"); this.ex.write(" jmp .L" + lblEnd + "\n"); // Die Expressoin wertet zu false aus - this.ex.write(".L" + lblFalse +":\n"); + this.ex.write(".L" + lblFalse + ":\n"); this.ex.write(" movq $0, %rax\n"); // Das hier ist das ende - this.ex.write(".L" + lblEnd +":\n"); + this.ex.write(".L" + lblEnd + ":\n"); return null; } @@ -451,26 +455,26 @@ public class GenASM implements Visitor { public Void visit(NotExpression e) { int lblFalse = ++lCount; int lblEnd = ++lCount; - + // Werte LHS aus // Wenn LHS != 0 bedeutet das true, also jumpe zum false Teil // Wenn nicht, falle durch zum true Teil e.lhs.welcome(this); this.ex.write(" cmpq $0, %rax\n"); - this.ex.write(" jne .L" +lblFalse +"\n"); + this.ex.write(" jne .L" + lblFalse + "\n"); // Hier ist das Ergebnis true // Springe am false Teil vorbei this.ex.write(" movq $1, %rax\n"); - this.ex.write(" jmp .L" +lblEnd +"\n"); + this.ex.write(" jmp .L" + lblEnd + "\n"); // Hier ist das Ergebnis false // Falle zum Ende durch - this.ex.write(".L" +lblFalse + ":\n"); + this.ex.write(".L" + lblFalse + ":\n"); this.ex.write("movq $0, %rax\n"); // Hier ist das Ende - this.ex.write(".L" +lblEnd + ":\n"); + this.ex.write(".L" + lblEnd + ":\n"); return null; } @@ -604,19 +608,51 @@ public class GenASM implements Visitor { this.env = new HashMap(); // Merke dir die offsets der parameter, die direkt auf den stack gelegt wurden - int offset = 16; // Per Stack übergebene Parameter liegen über unserm BSP + int offset = 16; // Per Stack übergebene Parameter liegen über unserem BSP + int ri = 0; + int fi = 0; // Per stack übergebene variablen in env registrieren - for (int i = this.rs.length; i < e.parameters.length; i++) { - env.put(e.parameters[i].name, offset); - offset += 8; + var registerParameters = new ArrayList(); + for (int i = 0; i < e.parameters.length; i++) { + if (e.parameters[i].type.equals(Type.getFloatType())) { + if (fi >= this.floatRegisters.length) { + // parameter is on stack already + env.put(e.parameters[i].name, offset); + offset += 8; + } else { + // parameter is in a xmm register + registerParameters.add(e.parameters[i]); + fi++; + } + } else { + if (ri >= this.registers.length) { + // parameter is on stack already + env.put(e.parameters[i].name, offset); + offset += 8; + } else { + // parameter is in a register + registerParameters.add(e.parameters[i]); + ri++; + } + } } - - // pushe die aufrufparameter aus den Registern wieder auf den Stack + offset = 0; - for (int i = 0; i < Math.min(this.rs.length, e.parameters.length); i++) { - this.ex.write(" pushq " + this.rs[i] + "\n"); - offset -= 8; - this.env.put(e.parameters[i].name, offset); // negative, liegt unter aktuellem BP + ri = 0; + fi = 0; + for (var param: registerParameters) { + if (param.type.equals(Type.getFloatType())) { + this.ex.write(" movq "+ this.floatRegisters[fi] + ", %rax\n"); + this.ex.write(" pushq %rax\n"); + offset -= 8; + this.env.put(param.name, offset); // negative, liegt unter aktuellem BP + fi++; + } else { + this.ex.write(" pushq " + this.registers[ri] + "\n"); + offset -= 8; + this.env.put(param.name, offset); // negative, liegt unter aktuellem BP + ri++; + } } // Reserviere Platz auf dem Stack für jede lokale variable @@ -632,84 +668,80 @@ public class GenASM implements Visitor { @Override public Void visit(FunctionCall e) { - /* - Idee: - Über arguments iterieren, sich für jedes Argument merken an welche Position es kommt - Über e.arguments iterieren, jedes welcomen, ergebnis auf den stack pushen - Vom stack in die jeweiligen register / den richtigen Platz auf den Stack pushen - */ - // // An xmmIdxy[i] steht ein index, der in e.arguments zeigt - // // this.frs[i] = register | xmmIdxs[i] = index in arguments das in dieses register gehört - // int[] xmmIdxs = new int[this.frs.length]; - // int fi = 0; - // // Selbe Idee wie bei xmmIdxs - // int[] rIdxs = new int[this.rs.length]; - // int ri = 0; - //// Selbe Idee wie bei xmmIdxs - // ArrayList stackIdxs = new ArrayList(); - // - // // Go through arguments - // // sort them into the memory regions they go when being passed to function later on - // for (int i = 0; i < e.arguments.length; i++) { - // var arg = e.arguments[i]; - // if (arg.type.equals(Type.getFloatType())) { - // if (fi >= this.frs.length) { - // // Float onto stack - // stackIdxs.add(i); - // } else { - // // Float into float reg - // xmmIdxs[fi] = i; - // fi += 1; - // } - // } else { - // if (ri >= this.rs.length) { - // // bool/int onto stack - // stackIdxs.add(i); - // } else { - // // bool/int into reg - // rIdxs[ri] = i; - // ri += 1; - // } - // } - // } + if (e.arguments.length > 0) { + // Mapping arguments index -> xmm registers index + int[] xmmIdxs = new int[this.floatRegisters.length]; + int fi = -1; - // // Welcome the arguments in order - // for (var arg : e.arguments) { - // arg.welcome(this); - // if (arg.type.equals(Type.getFloatType())) { - // this.ex.write(" movq %xmm0, %rax\n"); - // this.ex.write(" pushq %rax\n"); - // } else { - // this.ex.write(" pushq %rax\n"); - // } - // } - // // Move floats from stack to xmm registers - // TODO: Check if indexInArguments is valid - // for (int i = 0; i < xmmIdxs.length ; i++) { - // int indexInArguments = xmmIdxs[i]; - // int rspOffset = (((e.arguments.length - indexInArguments) - 1) * 8) * -1; - // this.ex.write(" movsd " + rspOffset + "(%rsp), " + this.frs[i] + "\n"); - // } + // Mapping arguments index -> all purpose registers index + int[] rIdxs = new int[this.registers.length]; + int ri = -1; + + // Mapping arguments index -> stack + ArrayList stackIdxs = new ArrayList(); - // // Move primitives from stack to all purpose registers - // TODO: Check if indexInArguments is valid - // for (int i = 0; i < rIdxs.length ; i++) { - // int indexInArguments = rIdxs[i]; - // int rspOffset = (((e.arguments.length - indexInArguments) - 1) * 8) * -1; - // this.ex.write(" movq " + rspOffset + "(%rsp), " + this.rs[i] + "\n"); - // } - // int stackStart = (e.arguments.length - 1) * 8 * -1; + // Go through arguments + // sort them into the memory regions they go when being passed to functions + for (int i = 0; i < e.arguments.length; i++) { + var arg = e.arguments[i]; + if (arg.type.equals(Type.getFloatType())) { + if (fi < this.floatRegisters.length - 1) { + // Float into float reg + fi += 1; + xmmIdxs[fi] = i; + } else { + // Float onto stack + stackIdxs.add(i); + } + } else { + if (ri < this.registers.length - 1) { + // bool/int into reg + ri += 1; + rIdxs[ri] = i; + } else { + // bool/int onto stack + stackIdxs.add(i); + } + } + } - // Die ersten sechs params in die register schieben - for (int i = 0; i < Math.min(this.rs.length, e.arguments.length); i++) { - e.arguments[i].welcome(this); - this.ex.write(" movq %rax, " + this.rs[i] + "\n"); - } + // Welcome the arguments in order, push everything onto the stack + for (var arg : e.arguments) { + arg.welcome(this); + if (arg.type.equals(Type.getFloatType())) { + this.ex.write(" movq %xmm0, %rax\n"); + this.ex.write(" pushq %rax\n"); + } else { + this.ex.write(" pushq %rax\n"); + } + } - // Den Rest auf den stack pushen - for (int i = e.arguments.length - 1; i >= this.rs.length; i--) { - e.arguments[i].welcome(this); - this.ex.write(" pushq %rax\n"); + // Move floats from stack to xmm registers + for (int i = 0; i <= fi; i++) { + int indexInArguments = xmmIdxs[i]; + int rspOffset = (((e.arguments.length - indexInArguments) - 1) * 8); + this.ex.write(" movsd " + rspOffset + "(%rsp), " + this.floatRegisters[i] + "\n"); + } + + // Move primitives from stack to all purpose registers + for (int i = 0; i <= ri; i++) { + int indexInArguments = rIdxs[i]; + int rspOffset = (((e.arguments.length - indexInArguments) - 1) * 8); + this.ex.write(" movq " + rspOffset + "(%rsp), " + this.registers[i] + "\n"); + } + + // Move everything else from a higher stack position to our stack frame start + int stackStartOffset = ((e.arguments.length) * 8); + for (int i = stackIdxs.size() - 1; i >= 0; i--) { + stackStartOffset -= 8; + int indexInArguments = stackIdxs.get(i); + int rspOffset = (((e.arguments.length - indexInArguments) - 1) * 8); + this.ex.write(" movq " + rspOffset + "(%rsp), %rax\n"); + this.ex.write(" movq %rax, " + stackStartOffset + "(%rsp)\n"); + } + + // Rescue RSP + this.ex.write(" addq $" + stackStartOffset + ", %rsp\n"); } this.ex.write(" call " + e.name + "\n"); diff --git a/src/test/functionCall/functionCall.c b/src/test/functionCall/functionCall.c index 0ac208b..66fe1f5 100644 --- a/src/test/functionCall/functionCall.c +++ b/src/test/functionCall/functionCall.c @@ -12,6 +12,16 @@ int argumentTest(char* name, int expected, int result) { } } +int argumentTest_f(char* name, int expected, int result) { + if (expected == result) { + succ_f(name, expected, result); + return 0; + } else { + err_f(name, expected, result); + return 1; + } +} + int runFunctionCallTests () { printf("\nFunction Call Tests \n"); // Checks that parameters are correctly passed from gcc to functions @@ -36,4 +46,27 @@ int runFunctionCallTests () { argumentTest("get8(...args)", 8, get8()); argumentTest("get9(...args)", 9, get9()); argumentTest("get10(...args)", 10, get10()); + + printf("\nFunction Call Tests With Floats \n"); + argumentTest_f("farg1(...args)", 1.0, farg1(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg2(...args)", 2.0, farg2(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg3(...args)", 3.0, farg3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg4(...args)", 4.0, farg4(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg5(...args)", 5.0, farg5(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg6(...args)", 6.0, farg6(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg7(...args)", 7.0, farg7(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg8(...args)", 8.0, farg8(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg9(...args)", 9.0, farg9(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg10(...args)", 10.0, farg10(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + // Checks that parameters are correctly passed from klang to functions + argumentTest_f("fget1(...args)", 1.0, fget1()); + argumentTest_f("fget2(...args)", 2.0, fget2()); + argumentTest_f("fget3(...args)", 3.0, fget3()); + argumentTest_f("fget4(...args)", 4.0, fget4()); + argumentTest_f("fget5(...args)", 5.0, fget5()); + argumentTest_f("fget6(...args)", 6.0, fget6()); + argumentTest_f("fget7(...args)", 7.0, fget7()); + argumentTest_f("fget8(...args)", 8.0, fget8()); + argumentTest_f("fget9(...args)", 9.0, fget9()); + argumentTest_f("fget10(...args)", 10.0, fget10()); } \ No newline at end of file diff --git a/src/test/functionCall/functionCall.h b/src/test/functionCall/functionCall.h index 56fbff7..4281631 100644 --- a/src/test/functionCall/functionCall.h +++ b/src/test/functionCall/functionCall.h @@ -18,4 +18,26 @@ int get6(); int get7(); int get8(); int get9(); -int get10(); \ No newline at end of file +int get10(); + +double farg1(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg2(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg3(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg4(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg5(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg6(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg7(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg8(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg9(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg10(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); + +double fget1(); +double fget2(); +double fget3(); +double fget4(); +double fget5(); +double fget6(); +double fget7(); +double fget8(); +double fget9(); +double fget10(); \ No newline at end of file diff --git a/src/test/print/print.c b/src/test/print/print.c index 21109f9..b8ff8af 100644 --- a/src/test/print/print.c +++ b/src/test/print/print.c @@ -28,6 +28,16 @@ void err(char* name, int expected, int result) { printf("\033[0;31mERROR:\t\t%s:\tGOT: %d\tExpected: %d\033[0;0m\n", name, result, expected); } +void succ_f(char* name, double expected, double result) { + incSuccess(); + printf("\033[0;32mSUCCESS:\t%s:\tGOT: %f\tExpected: %f\033[0;0m\n", name, result, expected); +} + +void err_f(char* name, double expected, double result) { + incFailure(); + printf("\033[0;31mERROR:\t\t%s:\tGOT: %f\tExpected: %f\033[0;0m\n", name, result, expected); +} + void succPrefixOne(char* name, int x, int expected, int result) { incSuccess(); printf("\033[0;32mSUCCESS:\t%s(%d)\tGOT: %d\tExpected: %d\033[0;0m\n", name, x, result, expected); diff --git a/src/test/print/print.h b/src/test/print/print.h index 637cc5c..8318341 100644 --- a/src/test/print/print.h +++ b/src/test/print/print.h @@ -6,6 +6,9 @@ void incFailure(); void succ(char* name, int expected, int result); void err(char* name, int expected, int result); +void succ_f(char* name, double expected, double result); +void err_f(char* name, double expected, double result); + void succPrefixOne(char* name, int x, int expected, int result); void errPrefixOne(char* name, int x, int expected, int result); diff --git a/src/test/test.k b/src/test/test.k index a5c08ec..f065cff 100644 --- a/src/test/test.k +++ b/src/test/test.k @@ -102,6 +102,90 @@ function get10(): int { return arg10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); } +// FLOATS + +function farg1(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return a; +} + +function fget1(): float { + return farg1(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg2(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return b; +} + +function fget2(): float { + return farg2(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg3(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return c; +} + +function fget3(): float { + return farg3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg4(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return d; +} + +function fget4(): float { + return farg4(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg5(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return e; +} + +function fget5(): float { + return farg5(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg6(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return f; +} + +function fget6(): float { + return farg6(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg7(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return g; +} + +function fget7(): float { + return farg7(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg8(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return h; +} + +function fget8(): float { + return farg8(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg9(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return i; +} + +function fget9(): float { + return farg9(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg10(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return j; +} + +function fget10(): float { + return farg10(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +// END FLOATS + function fac(x: int): int { if (x) { return (x * fac((x - 1)));