Browse Source

improved handling of huge sparse case tables: use if cascade on a register (can potentially be improved further with binary search or hash tables if required)

git-svn-id: https://svn.inf.ethz.ch/svn/lecturers/a2/trunk@8342 8c9fc860-2736-0410-a75d-ab315db34111
felixf 6 năm trước cách đây
mục cha
commit
6d1f056e3d
2 tập tin đã thay đổi với 67 bổ sung36 xóa
  1. 67 29
      source/FoxIntermediateBackend.Mod
  2. 0 7
      source/FoxSemanticChecker.Mod

+ 67 - 29
source/FoxIntermediateBackend.Mod

@@ -10640,50 +10640,86 @@ TYPE
 			out,else: Label; label: Label;
 			fixups: POINTER TO ARRAY OF Label; section: IntermediateCode.Section; name: Basic.SegmentedName; string: ARRAY 32 OF CHAR;
 			symbol: SyntaxTree.Symbol;
+			table: BOOLEAN;
 		BEGIN
 			(*! split case statement into if-elsif statements for large case label lists *)
 			IF Trace THEN TraceEnter("VisitCaseStatement") END;
 			range := x.max-x.min+1;
-			IF (range<0) OR (range > 1024*1024) THEN Error(x.position,"implementation restriction: case table size too large"); RETURN
+			IF (range < 0) OR (range > 1024) & (range DIV x.caseParts.Length() >10) THEN
+				(* if case table is larger than 1024 elements and only sparsely used, then do not employ a table *)
+				table := FALSE;
+				size := x.caseParts.Length();
+			ELSE
+				table := TRUE;
+				size := LONGINT(range);
 			END;
-			size := LONGINT(range);
 			Evaluate(x.variable,var);
 			ReuseCopy(tmp,var.op);
 			ReleaseIntermediateOperand(var.op);
 			var.op := tmp;
-			Emit(Sub(position,var.op,var.op,IntermediateCode.Immediate(IntermediateCode.GetType(system,x.variable.type),x.min)));
-			Convert(var.op,addressType);
-			else := NewLabel();
-			BrgeL(else,var.op,IntermediateCode.Immediate(addressType,size));
 			(*
 			UniqueId(name,module.module,"case",caseId);
 			*)
-			string := "@case"; Basic.AppendNumber(string, caseId); INC(caseId);
-			Global.GetModuleSegmentedName(module.module, name);
-			Basic.SuffixSegmentedName(name,Basic.MakeString(string));
-			symbol := SyntaxTree.NewSymbol(name[1]);
-			symbol.SetScope(moduleScope);
 			NEW(fixups,size); FOR i := 0 TO size-1 DO fixups[i] := NIL END;
-			section := NewSection(module.allSections, Sections.ConstSection,name,SyntaxTree.NewSymbol(name[1]),commentPrintout # NIL);
-			IntermediateCode.InitAddress(jmp, addressType, section.name, GetFingerprint(section.symbol), 0);
-			ReuseCopy(res,var.op);
-			ReleaseOperand(var);
-			Emit(Mul(position,res,res,IntermediateCode.Immediate(addressType,ToMemoryUnits(system,system.addressSize))));
-			Emit(Add(position,res,res,jmp));
-			IntermediateCode.MakeMemory(res,addressType);
-			Emit(Br(position,res));
-			ReleaseIntermediateOperand(res);
+			else := NewLabel();
+			IF table THEN
+				Emit(Sub(position,var.op,var.op,IntermediateCode.Immediate(IntermediateCode.GetType(system,x.variable.type),x.min)));
+				Convert(var.op,addressType);
+				BrgeL(else,var.op,IntermediateCode.Immediate(addressType,size));
+				ReuseCopy(res,var.op);
+				ReleaseOperand(var);
+				string := "@case"; Basic.AppendNumber(string, caseId); INC(caseId);
+				Global.GetModuleSegmentedName(module.module, name);
+				Basic.SuffixSegmentedName(name,Basic.MakeString(string));
+				symbol := SyntaxTree.NewSymbol(name[1]);
+				symbol.SetScope(moduleScope);
+				section := NewSection(module.allSections, Sections.ConstSection,name,SyntaxTree.NewSymbol(name[1]),commentPrintout # NIL);
+				IntermediateCode.InitAddress(jmp, addressType, section.name, GetFingerprint(section.symbol), 0);
+				Emit(Mul(position,res,res,IntermediateCode.Immediate(addressType,ToMemoryUnits(system,system.addressSize))));
+				Emit(Add(position,res,res,jmp));
+				IntermediateCode.MakeMemory(res,addressType);
+				Emit(Br(position,res));
+				ReleaseIntermediateOperand(res);
+			ELSE
+				ReuseCopy(res,var.op); (* make sure it is in a register *)
+				ReleaseOperand(var);
+				BrltL(else,res,IntermediateCode.Immediate(res.type,x.min));
+				BrltL(else,IntermediateCode.Immediate(res.type,x.max),res);
+				FOR i := 0 TO x.caseParts.Length()-1 DO (* case parts *)
+					part := x.GetCasePart(i);
+					constant := part.firstConstant;
+					fixups[i] := NewLabel();
+					WHILE(constant # NIL) DO (* case labels for this case part *)
+						IF constant.min = constant.max THEN
+							BreqL(fixups[i], res,IntermediateCode.Immediate(res.type,constant.min));
+						ELSE
+							label := NewLabel();	
+							BrltL(label, res, IntermediateCode.Immediate(res.type,constant.min));
+							BrltL(label, IntermediateCode.Immediate(res.type,constant.max),res);
+							BrL(fixups[i]); 
+							SetLabel(label);
+						END;
+						constant := constant.next;
+					END;
+				END;
+				BrL(else);
+				ReleaseIntermediateOperand(res);
+			END;
 			out := NewLabel();
 			FOR i := 0 TO x.caseParts.Length()-1 DO (* case parts *)
 				part := x.GetCasePart(i);
 				constant := part.firstConstant;
-				label := NewLabel();
-				SetLabel(label);
-				WHILE(constant # NIL) DO (* case labels for this case part *)
-					FOR j := constant.min TO constant.max DO
-						fixups[j-x.min] := label;
+				IF table THEN
+					label := NewLabel();
+					SetLabel(label);
+					WHILE(constant # NIL) DO (* case labels for this case part *)
+						FOR j := constant.min TO constant.max DO
+							fixups[j-x.min] := label;
+						END;
+						constant := constant.next;
 					END;
-					constant := constant.next;
+				ELSE
+					SetLabel(fixups[i]);
 				END;
 				StatementSequence(part.statements);
 				BrL(out);
@@ -10700,9 +10736,11 @@ TYPE
 				EmitTrap(position,CaseTrap);
 			END;
 			SetLabel(out);
-			FOR i := 0 TO size-1 DO
-				IntermediateCode.InitAddress(op, addressType, fixups[i].section.name, GetFingerprint(fixups[i].section.symbol), fixups[i].pc);
-				section.Emit(Data(position,op));
+			IF table THEN
+				FOR i := 0 TO size-1 DO
+					IntermediateCode.InitAddress(op, addressType, fixups[i].section.name, GetFingerprint(fixups[i].section.symbol), fixups[i].pc);
+					section.Emit(Data(position,op));
+				END;
 			END;
 			IF Trace THEN TraceExit("VisitCaseStatement") END;
 		END VisitCaseStatement;

+ 0 - 7
source/FoxSemanticChecker.Mod

@@ -7910,13 +7910,6 @@ TYPE
 			FOR i := 0 TO caseStatement.CaseParts()-1 DO
 				CasePart(caseStatement.GetCasePart(i),type,caseList,min,max);
 			END;
-			IF (max - min > 1024) & (100* caseStatement.CaseParts() DIV (max-min) < 10) (* less than ten percent used in a huge case table *) THEN
-				msg := "huge sparse case table ";
-				Strings.AppendInt(msg, max-min);
-				Strings.Append(msg,"/");
-				Strings.AppendInt(msg, caseStatement.CaseParts());
-				Warning(caseStatement.position,msg);
-			END;
 
 			caseStatement.SetMinMax(min,max);
 			StatementSequence(caseStatement.elsePart);