Explorar el Código

Support of 64-bit floating point instructions (using the old mnemonics but compatible to NEON)

git-svn-id: https://svn.inf.ethz.ch/svn/lecturers/a2/trunk@6758 8c9fc860-2736-0410-a75d-ab315db34111
felixf hace 9 años
padre
commit
258bb5c3ed
Se han modificado 1 ficheros con 128 adiciones y 34 borrados
  1. 128 34
      source/FoxARMBackend.Mod

+ 128 - 34
source/FoxARMBackend.Mod

@@ -151,6 +151,17 @@ TYPE
 
 	END ImmediateReference;
 
+	ImmediateHReference = OBJECT (Reference)
+	VAR value: HUGEINT;
+
+		PROCEDURE & InitImm(v: HUGEINT);
+		BEGIN
+			Init;
+			SELF.value := v;
+		END InitImm;
+
+	END ImmediateHReference;
+
 	(* a reference to a symbol and offset in IR units that is used by at least one instruction *)
 	SymbolReference = OBJECT (Reference)
 	VAR
@@ -252,6 +263,43 @@ TYPE
 
 		END AddImmediate;
 
+		PROCEDURE AddHImmediate(value: HUGEINT; pc: LONGINT);
+		VAR
+			reference, foundReference: Reference;  immediateHReference: ImmediateHReference;
+		BEGIN
+			(* go through the list of symbol/offset-combinations and check if there already is an entry for the symbol and offset in question *)
+			reference := firstReference;
+			WHILE reference # NIL DO
+				IF reference IS ImmediateHReference THEN
+				WITH reference: ImmediateHReference DO
+					IF (reference.value = value) THEN
+						foundReference := reference (* an entry already exists *)
+					END;
+				END;
+				END;
+				reference := reference.next
+			END;
+
+			IF foundReference # NIL THEN
+				reference := foundReference
+			ELSE
+				(* no entry was found for the symbol/offset combination: create a new one *)
+				NEW(immediateHReference, value);
+				reference := immediateHReference;
+
+				IF firstReference = NIL THEN firstReference := reference ELSE lastReference.next := reference END;
+				lastReference := reference;
+
+				INC(referenceCount)
+			END;
+
+			(* add a citation to the reference *)
+			reference.AddCitation(pc);
+
+			IF pcOfFirstCitation = None THEN pcOfFirstCitation := pc END
+
+		END AddHImmediate;
+
 
 	END ListOfReferences;
 
@@ -536,9 +584,13 @@ TYPE
 				*)
 
 			| IntermediateCode.conv:
-				result := ~IsFloat(irInstruction.op1) & ~IsFloat(irInstruction.op2)
+				IF IsInteger64(irInstruction.op1) & IsFloat(irInstruction.op2) THEN  (* ENTIERH *)
+					result := FALSE
+				ELSE
+					result := ~IsFloat(irInstruction.op1) & ~IsFloat(irInstruction.op2)
 									OR backend.useFPU32 & ~IsDoublePrecisionFloat(irInstruction.op1) & ~IsDoublePrecisionFloat(irInstruction.op2)
 									OR backend.useFPU64;
+				END;
 			| IntermediateCode.mod:
 				result := FALSE;
 				(*
@@ -1273,6 +1325,11 @@ TYPE
 		BEGIN RETURN irOperand.type.form IN IntermediateCode.Integer
 		END IsInteger;
 
+		(** whether an IR operand hold am integer value **)
+		PROCEDURE IsInteger64(CONST irOperand: IntermediateCode.Operand): BOOLEAN;
+		BEGIN RETURN (irOperand.type.form IN IntermediateCode.Integer) & (irOperand.type.sizeInBits = 64)
+		END IsInteger64;
+
 		PROCEDURE PartType(CONST type: IntermediateCode.Type; part: LONGINT): IntermediateCode.Type;
 		VAR
 			result: IntermediateCode.Type;
@@ -1549,19 +1606,16 @@ TYPE
 		(** get a single precision VFP register that holds a certain floating point value **)
 		PROCEDURE DoublePrecisionFloatRegisterFromValue(value: LONGREAL; registerHint: Operand): Operand;
 		VAR
-			intValue, dummy: LONGINT;
+			intValue: HUGEINT; dummy: LONGINT;
 			result, temp: Operand;
 		BEGIN
-			intValue := SYSTEM.VAL(LONGINT, value);
+			intValue := SYSTEM.VAL(HUGEINT, value);
 			(* alternative: integerValue := BinaryCode.ConvertReal(value) *)
-
-			temp := GetFreeRegisterOrHint(IntermediateCode.UnsignedIntegerType(64), registerHint);
-			dummy := ValueComposition(intValue, TRUE, temp);
 			result := GetFreeRegisterOrHint(IntermediateCode.FloatType(64), registerHint);
-			Emit2(opFMSR, result, temp);
-
+			listOfReferences.AddHImmediate(intValue, out.pc);
+			Emit2(opFLDD, result, InstructionSet.NewImmediateOffsetMemory(opPC.register, 0, {InstructionSet.Increment})); (* LDR ..., [PC, #+???] *)
 			ASSERT(result.mode = InstructionSet.modeRegister);
-			ASSERT((result.register >= InstructionSet.SR0) & (result.register <= InstructionSet.SR31));
+			ASSERT((result.register >= InstructionSet.DR0) & (result.register <= InstructionSet.DR31));
 			RETURN result;
 		END DoublePrecisionFloatRegisterFromValue;
 
@@ -1752,7 +1806,7 @@ TYPE
 			(*pc: LONGINT;*)
 		BEGIN
 			register := RegisterFromIrOperand(irOperand, part, emptyOperand);
-			IF ~IsRegisterForType(register.register, IntermediateCode.FloatType(32)) THEN
+			IF ~IsRegisterForType(register.register, IntermediateCode.FloatType(32)) & ~IsRegisterForType(register.register, IntermediateCode.FloatType(64)) THEN
 				Emit2(opSTR, register, InstructionSet.NewImmediateOffsetMemory(InstructionSet.SP, 4, {InstructionSet.Decrement, InstructionSet.PreIndexed}));
 			ELSE
 				partType := PartType(irOperand.type, part);
@@ -1969,7 +2023,15 @@ TYPE
 					Emit3(opFSUBS, destination, left, right)
 				END;
 				WriteBack(irInstruction.op1, Low, destination)
-
+			ELSIF IsDoublePrecisionFloat(irInstruction.op1) THEN
+				ASSERT(backend.useFPU32);
+				PrepareDoubleSourceOp(irInstruction, Low, destination, left, right);
+				IF irInstruction.opcode = IntermediateCode.add THEN
+					Emit3(opFADDD, destination, left, right)
+				ELSE
+					Emit3(opFSUBD, destination, left, right)
+				END;
+				WriteBack(irInstruction.op1, Low, destination)
 			ELSIF IsInteger(irInstruction.op1) THEN
 				IF IsComplex(irInstruction.op1) THEN
 					EmitPartialAddOrSub(irInstruction, Low, TRUE);
@@ -2116,6 +2178,11 @@ TYPE
 				PrepareDoubleSourceOp(irInstruction, Low, destination, left, right);
 				Emit3(opFDIVS, destination, left, right);
 				WriteBack(irInstruction.op1, Low, destination)
+			ELSIF IsDoublePrecisionFloat(irInstruction.op1) THEN
+				ASSERT(backend.useFPU64);
+				PrepareDoubleSourceOp(irInstruction, Low, destination, left, right);
+				Emit3(opFDIVD, destination, left, right);
+				WriteBack(irInstruction.op1, Low, destination)
 			ELSE
 				HALT(200)
 			END
@@ -2194,6 +2261,11 @@ TYPE
 				PrepareSingleSourceOp(irInstruction, Low, destination[Low], source[Low]);
 				Emit2(opFNEGS, destination[Low], source[Low]);
 				WriteBack(irInstruction.op1, Low, destination[Low])
+			ELSIF IsDoublePrecisionFloat(irInstruction.op1) THEN
+				ASSERT(backend.useFPU64);
+				PrepareSingleSourceOp(irInstruction, Low, destination[Low], source[Low]);
+				Emit2(opFNEGD, destination[Low], source[Low]);
+				WriteBack(irInstruction.op1, Low, destination[Low])
 			ELSE
 				HALT(200)
 			END
@@ -2834,6 +2906,7 @@ TYPE
 			IF IsInteger(irDestination) THEN
 				(* to integer: *)
 				IF IsComplex(irDestination) THEN
+					ASSERT(IsInteger(irDestination));
 					(* to complex integer: *)
 					IF IsInteger(irSource) THEN
 						(* integer to complex integer: *)
@@ -2853,29 +2926,11 @@ TYPE
 								Emit2(opMOV, destination[High], InstructionSet.NewRegister(source[Low].register, InstructionSet.shiftASR, None, 32))
 							END
 						END
-
-					ELSIF IsSinglePrecisionFloat(irSource) THEN
-						ASSERT(backend.useFPU32);
-						(* single precision float to complex integer: *)
-						temp := GetFreeRegister(IntermediateCode.FloatType(32));
-						IF irDestination.type.form = IntermediateCode.UnsignedInteger THEN
-							(* single precision float to non-complex unsigned integer: *)
-							Emit2(opFTOUIS, temp, source[Low]);
-						ELSE
-							(* single precision float to non-complex signed integer: *)
-							Emit2(opFTOSIS, temp, source[Low]);
-						END;
-						Emit2(opFMRS, destination[Low], temp);
-						IF irDestination.type.form = IntermediateCode.UnsignedInteger THEN
-							Emit2(opMOV, destination[High], InstructionSet.NewImmediate(0));
-						ELSE
-							(* for signed values the high part is set to 0...0 or 1...1, depending on the sign of the low part *)
-							Emit2(opMOV, destination[High], InstructionSet.NewRegister(destination[Low].register, InstructionSet.shiftASR, None, 32))
-						END
+					ELSIF IsFloat(irSource) THEN (* ENTIERH not supported natively *)
+						HALT(200);
 					ELSE
-						(* anything else to complex-integer: *)
-						HALT(200)
-					END
+						HALT(100);
+					END;
 				ELSE
 					(* to non-complex integer: *)
 					IF IsInteger(irSource) THEN
@@ -2884,6 +2939,7 @@ TYPE
 						SignOrZeroExtendOperand(source[Low], partType);
 						MovIfDifferent(destination[Low], source[Low])
 					ELSIF IsSinglePrecisionFloat(irSource) THEN
+						(* REAL --> INTEGER *)
 						ASSERT(backend.useFPU32);
 						(* single precision float to non-complex integer: *)
 						temp := GetFreeRegister(IntermediateCode.FloatType(32));
@@ -2895,12 +2951,24 @@ TYPE
 							Emit2(opFTOSIS, temp, source[Low]);
 						END;
 						Emit2(opFMRS, destination[Low], temp)
+					ELSIF IsDoublePrecisionFloat(irSource) THEN
+						(* LONGREAL --> INTEGER *)
+						ASSERT(backend.useFPU64);
+						(* single precision float to non-complex integer: *)
+						temp := GetFreeRegister(IntermediateCode.FloatType(32));
+						IF irDestination.type.form = IntermediateCode.UnsignedInteger THEN
+							(* single precision float to non-complex unsigned integer: *)
+							Emit2(opFTOUID, temp, source[Low]);
+						ELSE
+							(* single precision float to non-complex signed integer: *)
+							Emit2(opFTOSID, temp, source[Low]);
+						END;
+						Emit2(opFMRS, destination[Low], temp)
 					ELSE
 						(* anything to non-complex integer: *)
 						HALT(200)
 					END
 				END
-
 			ELSIF IsSinglePrecisionFloat(irDestination) THEN
 				(* to single precision float: *)
 			 	IF IsInteger(irSource) THEN
@@ -2917,10 +2985,36 @@ TYPE
 			 	ELSIF IsSinglePrecisionFloat(irSource) THEN
 			 		(* single precision float to single precision float: *)
 			 		MovIfDifferent(destination[Low], source[Low])
+			 	ELSIF IsDoublePrecisionFloat(irSource) THEN
+			 		(* LONGREAL --> REAL *)
+			 		Emit2(opFCVTSD, destination[Low], source[Low])
 			 	ELSE
 			 		(* anything else to single precision float: *)
 			 		HALT(200)
 			 	END
+			ELSIF IsDoublePrecisionFloat(irDestination) THEN
+				(* to double precision float: *)
+			 	IF IsInteger(irSource) THEN
+			 		(* integer to double precision float: ignore high part of source *)
+			 		temp := GetFreeRegister(IntermediateCode.FloatType(32));
+			 		Emit2(opFMSR, temp, source[Low]);
+		 			IF irSource.type.form = IntermediateCode.UnsignedInteger THEN
+						(* non-complex unsigned integer to double precision float: *)
+						Emit2(opFUITOD, destination[Low], temp)
+					ELSE
+						(* non-complex signed integer to double precision float: *)
+						Emit2(opFSITOD, destination[Low], temp)
+					END
+			 	ELSIF IsSinglePrecisionFloat(irSource) THEN
+			 		(* REAL --> LONGREAL *)
+			 		Emit2(opFCVTDS, destination[Low], source[Low])
+			 	ELSIF IsDoublePrecisionFloat(irSource) THEN
+			 		(* single precision float to single precision float: *)
+			 		MovIfDifferent(destination[Low], source[Low])
+			 	ELSE
+			 		(* anything else to single precision float: *)
+			 		HALT(200)
+			 	END				
 			ELSE
 				(* to anything else: *)
 				HALT(200)