diff options
24 files changed, 979 insertions, 240 deletions
diff --git a/gcc/doc/gm2.texi b/gcc/doc/gm2.texi index ae87434..8d5d95f 100644 --- a/gcc/doc/gm2.texi +++ b/gcc/doc/gm2.texi @@ -664,6 +664,17 @@ issue a warning if a variable is used before it is initialized. The checking only occurs in the first basic block in each procedure. It does not check parameters, array types or set types. +@item -Wuninit-variable-checking=all,known,cond +issue a warning if a variable is used before it is initialized. +The checking will only occur in the first basic block in each +procedure if @samp{known} is specified. If @samp{cond} or @samp{all} +is specified then checking continues into conditional branches of the +flow graph. All checking will stop when a procedure call is invoked +or the top of a loop is encountered. +The option @samp{-Wall} will turn on this flag with +@samp{-Wuninit-variable-checking=known}. +The @samp{-Wuninit-variable-checking=all} will increase compile time. + @c the following warning options are complete but need to be @c regression tested against all other front ends @c to ensure the options do not conflict. diff --git a/gcc/m2/gm2-compiler/M2BasicBlock.def b/gcc/m2/gm2-compiler/M2BasicBlock.def index 44606dd..3a67ea6 100644 --- a/gcc/m2/gm2-compiler/M2BasicBlock.def +++ b/gcc/m2/gm2-compiler/M2BasicBlock.def @@ -60,7 +60,8 @@ PROCEDURE InitBasicBlocks (sb: ScopeBlock) : BasicBlock ; reachable are removed. *) -PROCEDURE InitBasicBlocksFromRange (start, end: CARDINAL) : BasicBlock ; +PROCEDURE InitBasicBlocksFromRange (ScopeSym: CARDINAL; + start, end: CARDINAL) : BasicBlock ; (* diff --git a/gcc/m2/gm2-compiler/M2BasicBlock.mod b/gcc/m2/gm2-compiler/M2BasicBlock.mod index 1d005f6..d3eb135 100644 --- a/gcc/m2/gm2-compiler/M2BasicBlock.mod +++ b/gcc/m2/gm2-compiler/M2BasicBlock.mod @@ -35,12 +35,15 @@ FROM M2Quads IMPORT IsReferenced, IsConditional, IsUnConditional, IsCall, IsInitialisingConst, IsPseudoQuad, IsDefOrModFile, GetNextQuad, GetQuad, QuadOperator, - SubQuad ; + SubQuad, DisplayQuadRange ; FROM M2Scope IMPORT ScopeBlock, ForeachScopeBlockDo ; FROM M2GenGCC IMPORT ConvertQuadsToTree ; +CONST + Debugging = FALSE ; + TYPE BasicBlock = POINTER TO RECORD StartQuad : CARDINAL ; (* First Quad in Basic Block *) @@ -77,10 +80,15 @@ END InitBasicBlocks ; reachable are removed. *) -PROCEDURE InitBasicBlocksFromRange (start, end: CARDINAL) : BasicBlock ; +PROCEDURE InitBasicBlocksFromRange (ScopeSym: CARDINAL; + start, end: CARDINAL) : BasicBlock ; BEGIN HeadOfBasicBlock := NIL ; - ConvertQuads2BasicBlock(start, end) ; + ConvertQuads2BasicBlock (ScopeSym, start, end) ; + IF Debugging + THEN + DisplayBasicBlocks (HeadOfBasicBlock) + END ; RETURN( HeadOfBasicBlock ) END InitBasicBlocksFromRange ; @@ -144,7 +152,7 @@ END New ; which has only has one entry and exit point. *) -PROCEDURE ConvertQuads2BasicBlock (Start, End: CARDINAL) ; +PROCEDURE ConvertQuads2BasicBlock (ScopeSym: CARDINAL; Start, End: CARDINAL) ; VAR LastQuadDefMod, LastQuadConditional, @@ -154,6 +162,10 @@ VAR CurrentBB : BasicBlock ; LastBB : BasicBlock ; BEGIN + IF Debugging + THEN + DisplayQuadRange (ScopeSym, Start, End) + END ; (* Algorithm to perform Basic Block: @@ -323,7 +335,6 @@ END Sub ; DisplayBasicBlocks - displays the basic block data structure. *) -(* PROCEDURE DisplayBasicBlocks (bb: BasicBlock) ; VAR b: BasicBlock ; @@ -347,7 +358,6 @@ BEGIN WriteString(' end ') ; WriteCard(EndQuad, 6) ; END END DisplayBlock ; -*) BEGIN diff --git a/gcc/m2/gm2-compiler/M2Code.mod b/gcc/m2/gm2-compiler/M2Code.mod index c4069e9..d2ace72 100644 --- a/gcc/m2/gm2-compiler/M2Code.mod +++ b/gcc/m2/gm2-compiler/M2Code.mod @@ -45,7 +45,7 @@ FROM M2Quads IMPORT CountQuads, GetFirstQuad, DisplayQuadList, DisplayQuadRange, BackPatchSubrangesAndOptParam, LoopAnalysis, ForLoopAnalysis, GetQuad, QuadOperator ; -FROM M2SymInit IMPORT VariableAnalysis ; +FROM M2SymInit IMPORT ScopeBlockVariableAnalysis ; FROM M2Pass IMPORT SetPassToNoPass, SetPassToCodeGeneration ; @@ -293,16 +293,16 @@ END Code ; InitialDeclareAndCodeBlock - declares all objects within scope, *) -PROCEDURE InitialDeclareAndOptimize (start, end: CARDINAL) ; +PROCEDURE InitialDeclareAndOptimize (scope: CARDINAL; start, end: CARDINAL) ; BEGIN - Count := CountQuads() ; - FreeBasicBlocks(InitBasicBlocksFromRange(start, end)) ; - BasicB := Count - CountQuads() ; - Count := CountQuads() ; - - FoldBranches(start, end) ; - Jump := Count - CountQuads() ; - Count := CountQuads() + Count := CountQuads () ; + FreeBasicBlocks (InitBasicBlocksFromRange (scope, start, end)) ; + BasicB := Count - CountQuads () ; + Count := CountQuads () ; + + FoldBranches (start, end) ; + Jump := Count - CountQuads () ; + Count := CountQuads () END InitialDeclareAndOptimize ; @@ -310,24 +310,25 @@ END InitialDeclareAndOptimize ; DeclareAndCodeBlock - declares all objects within scope, *) -PROCEDURE SecondDeclareAndOptimize (start, end: CARDINAL) ; +PROCEDURE SecondDeclareAndOptimize (scope: CARDINAL; + start, end: CARDINAL) ; BEGIN REPEAT FoldConstants(start, end) ; DeltaConst := Count - CountQuads () ; Count := CountQuads () ; - FreeBasicBlocks(InitBasicBlocksFromRange (start, end)) ; + FreeBasicBlocks(InitBasicBlocksFromRange (scope, start, end)) ; DeltaBasicB := Count - CountQuads () ; Count := CountQuads () ; - FreeBasicBlocks (InitBasicBlocksFromRange (start, end)) ; + FreeBasicBlocks (InitBasicBlocksFromRange (scope, start, end)) ; FoldBranches(start, end) ; DeltaJump := Count - CountQuads () ; Count := CountQuads () ; - FreeBasicBlocks(InitBasicBlocksFromRange (start, end)) ; + FreeBasicBlocks(InitBasicBlocksFromRange (scope, start, end)) ; INC (DeltaBasicB, Count - CountQuads ()) ; Count := CountQuads () ; @@ -375,20 +376,6 @@ END Init ; (* - BasicBlockVariableAnalysis - -*) - -PROCEDURE BasicBlockVariableAnalysis (start, end: CARDINAL) ; -VAR - bb: BasicBlock ; -BEGIN - bb := InitBasicBlocksFromRange(start, end) ; - ForeachBasicBlockDo (bb, VariableAnalysis) ; - KillBasicBlocks (bb) -END BasicBlockVariableAnalysis ; - - -(* DisplayQuadsInScope - *) @@ -416,7 +403,7 @@ BEGIN OptimTimes := 1 ; Current := CountQuads () ; ForeachScopeBlockDo (sb, InitialDeclareAndOptimize) ; - ForeachScopeBlockDo (sb, BasicBlockVariableAnalysis) ; + ForeachScopeBlockDo (sb, ScopeBlockVariableAnalysis) ; REPEAT ForeachScopeBlockDo (sb, SecondDeclareAndOptimize) ; Previous := Current ; diff --git a/gcc/m2/gm2-compiler/M2GCCDeclare.mod b/gcc/m2/gm2-compiler/M2GCCDeclare.mod index c502726..eaa3255 100644 --- a/gcc/m2/gm2-compiler/M2GCCDeclare.mod +++ b/gcc/m2/gm2-compiler/M2GCCDeclare.mod @@ -1610,13 +1610,13 @@ BEGIN THEN InternalError ('trying to declare the NulSym') END ; - IF IsConstructor(sym) AND (NOT GccKnowsAbout(sym)) + IF IsConstructor (sym) AND (NOT GccKnowsAbout (sym)) THEN - WalkConstructor(sym, TraverseDependants) ; - DeclareTypesConstantsProceduresInRange(quad, quad) ; - Assert(IsConstructorDependants(sym, IsFullyDeclared)) ; - PushValue(sym) ; - DeclareConstantFromTree(sym, PopConstructorTree(tokenno)) + WalkConstructor (sym, TraverseDependants) ; + DeclareTypesConstantsProceduresInRange (GetScope (sym), quad, quad) ; + Assert (IsConstructorDependants (sym, IsFullyDeclared)) ; + PushValue (sym) ; + DeclareConstantFromTree (sym, PopConstructorTree (tokenno)) END END DeclareConstructor ; @@ -2539,24 +2539,24 @@ END FoldConstants ; DeclareTypesConstantsProceduresInRange - *) -PROCEDURE DeclareTypesConstantsProceduresInRange (start, end: CARDINAL) ; +PROCEDURE DeclareTypesConstantsProceduresInRange (scope, start, end: CARDINAL) ; VAR n, m: CARDINAL ; BEGIN IF DisplayQuadruples THEN - DisplayQuadRange(start, end) + DisplayQuadRange (scope, start, end) END ; REPEAT n := NoOfElementsInSet(ToDoList) ; - WHILE ResolveConstantExpressions(DeclareConstFully, start, end) DO + WHILE ResolveConstantExpressions (DeclareConstFully, start, end) DO END ; (* we need to evaluate some constant expressions to resolve these types *) IF DeclaredOutstandingTypes (FALSE) THEN END ; m := NoOfElementsInSet(ToDoList) - UNTIL (NOT ResolveConstantExpressions(DeclareConstFully, start, end)) AND + UNTIL (NOT ResolveConstantExpressions (DeclareConstFully, start, end)) AND (n=m) END DeclareTypesConstantsProceduresInRange ; @@ -2620,16 +2620,16 @@ VAR s, t: CARDINAL ; sb : ScopeBlock ; BEGIN - sb := InitScopeBlock(scope) ; - PushBinding(scope) ; + sb := InitScopeBlock (scope) ; + PushBinding (scope) ; REPEAT - s := NoOfElementsInSet(ToDoList) ; + s := NoOfElementsInSet (ToDoList) ; (* ForeachLocalSymDo(scope, DeclareTypeInfo) ; *) - ForeachScopeBlockDo(sb, DeclareTypesConstantsProceduresInRange) ; - t := NoOfElementsInSet(ToDoList) ; + ForeachScopeBlockDo (sb, DeclareTypesConstantsProceduresInRange) ; + t := NoOfElementsInSet (ToDoList) ; UNTIL s=t ; - PopBinding(scope) ; - KillScopeBlock(sb) + PopBinding (scope) ; + KillScopeBlock (sb) END DeclareTypesConstantsProcedures ; @@ -2691,7 +2691,7 @@ BEGIN WalkTypesInProcedure(scope) ; DeclareProcedure(scope) ; ForeachInnerModuleDo(scope, WalkTypesInModule) ; - DeclareTypesConstantsProcedures(scope) ; + DeclareTypesConstantsProcedures (scope) ; ForeachInnerModuleDo(scope, DeclareTypesConstantsProcedures) ; DeclareLocalVariables(scope) ; ForeachInnerModuleDo(scope, DeclareModuleVariables) ; diff --git a/gcc/m2/gm2-compiler/M2GenGCC.def b/gcc/m2/gm2-compiler/M2GenGCC.def index 646e09e..b132bf0 100644 --- a/gcc/m2/gm2-compiler/M2GenGCC.def +++ b/gcc/m2/gm2-compiler/M2GenGCC.def @@ -45,7 +45,7 @@ EXPORT QUALIFIED ConvertQuadsToTree, ResolveConstantExpressions, the GCC tree structure. *) -PROCEDURE ConvertQuadsToTree (Start, End: CARDINAL) ; +PROCEDURE ConvertQuadsToTree (Scope: CARDINAL; Start, End: CARDINAL) ; (* diff --git a/gcc/m2/gm2-compiler/M2GenGCC.mod b/gcc/m2/gm2-compiler/M2GenGCC.mod index 8b877e2..0955106 100644 --- a/gcc/m2/gm2-compiler/M2GenGCC.mod +++ b/gcc/m2/gm2-compiler/M2GenGCC.mod @@ -395,7 +395,7 @@ BEGIN THEN RETURN FALSE END ; - scope := GetScope(scope) + scope := GetScope (scope) END ; InternalError ('expecting scope to eventually reach a module or defimp symbol') ELSE @@ -410,7 +410,7 @@ END IsExportedGcc ; the GCC tree structure. *) -PROCEDURE ConvertQuadsToTree (Start, End: CARDINAL) ; +PROCEDURE ConvertQuadsToTree (Scope: CARDINAL; Start, End: CARDINAL) ; BEGIN REPEAT CodeStatement (Start) ; diff --git a/gcc/m2/gm2-compiler/M2Optimize.mod b/gcc/m2/gm2-compiler/M2Optimize.mod index 416eb42..408e958 100644 --- a/gcc/m2/gm2-compiler/M2Optimize.mod +++ b/gcc/m2/gm2-compiler/M2Optimize.mod @@ -351,7 +351,8 @@ BEGIN END RemoveProcedures ; -PROCEDURE KnownReachable (Start, End: CARDINAL) ; +PROCEDURE KnownReachable (Scope: CARDINAL; + Start, End: CARDINAL) ; VAR Op : QuadOperator ; Op1, Op2, Op3: CARDINAL ; diff --git a/gcc/m2/gm2-compiler/M2Options.def b/gcc/m2/gm2-compiler/M2Options.def index 722e56c..d8d3845 100644 --- a/gcc/m2/gm2-compiler/M2Options.def +++ b/gcc/m2/gm2-compiler/M2Options.def @@ -73,6 +73,7 @@ EXPORT QUALIFIED SetReturnCheck, SetNilCheck, SetCaseCheck, VariantValueChecking, UnusedVariableChecking, UnusedParameterChecking, UninitVariableChecking, SetUninitVariableChecking, + UninitVariableConditionalChecking, SetUnusedVariableChecking, SetUnusedParameterChecking, Quiet, LineDirectives, StrictTypeChecking, CPreProcessor, Xcode, ExtendedOpaque, @@ -162,6 +163,10 @@ VAR UnusedParameterChecking, (* Should we warn about unused parameters? *) UninitVariableChecking, (* Should we warn about accessing *) (* uninitialized variables in the first bb? *) + UninitVariableConditionalChecking, + (* Should we warn about accessing *) + (* uninitialized variables in subsequent *) + (* basic blocks? *) LowerCaseKeywords, (* Should keywords in errors be in lower? *) DebugBuiltins, (* Should we always call a real function? *) AutoInit, (* -fauto-init assigns pointers to NIL. *) @@ -922,10 +927,13 @@ PROCEDURE SetShared (value: BOOLEAN) ; (* - SetUninitVariableChecking - sets the UninitVariableChecking flag to value. + SetUninitVariableChecking - sets the UninitVariableChecking flag to value + or UninitVariableConditionalChecking to value. + Arg can be "known", "known,cond", "cond,known" + or "all". *) -PROCEDURE SetUninitVariableChecking (value: BOOLEAN) ; +PROCEDURE SetUninitVariableChecking (value: BOOLEAN; arg: ADDRESS) : INTEGER ; (* diff --git a/gcc/m2/gm2-compiler/M2Options.mod b/gcc/m2/gm2-compiler/M2Options.mod index 84fcb57..1174a0d 100644 --- a/gcc/m2/gm2-compiler/M2Options.mod +++ b/gcc/m2/gm2-compiler/M2Options.mod @@ -28,7 +28,7 @@ FROM M2Search IMPORT SetDefExtension, SetModExtension ; FROM PathName IMPORT DumpPathName, AddInclude ; FROM M2Printf IMPORT printf0, printf1, fprintf1 ; FROM FIO IMPORT StdErr ; -FROM libc IMPORT exit ; +FROM libc IMPORT exit, printf ; FROM Debug IMPORT Halt ; FROM m2linemap IMPORT location_t ; FROM m2configure IMPORT FullPathCPP ; @@ -1369,84 +1369,114 @@ END SetShared ; SetUninitVariableChecking - sets the UninitVariableChecking flag to value. *) -PROCEDURE SetUninitVariableChecking (value: BOOLEAN) ; +PROCEDURE SetUninitVariableChecking (value: BOOLEAN; arg: ADDRESS) : INTEGER ; +VAR + s: String ; BEGIN - UninitVariableChecking := value + IF Debugging + THEN + IF value + THEN + printf ("SetUninitVariableChecking (TRUE, %s)\n", arg) + ELSE + printf ("SetUninitVariableChecking (FALSE, %s)\n", arg) + END + END ; + s := InitStringCharStar (arg) ; + IF EqualArray (s, "all") OR + EqualArray (s, "known,cond") OR + EqualArray (s, "cond,known") OR + EqualArray (s, "cond") + THEN + UninitVariableChecking := value ; + UninitVariableConditionalChecking := value ; + s := KillString (s) ; + RETURN 1 + ELSIF EqualArray (s, "known") + THEN + UninitVariableChecking := value ; + UninitVariableConditionalChecking := NOT value ; + s := KillString (s) ; + RETURN 1 + ELSE + s := KillString (s) ; + RETURN 0 + END END SetUninitVariableChecking ; - BEGIN - cflag := FALSE ; (* -c. *) - RuntimeModuleOverride := InitString (DefaultRuntimeModuleOverride) ; - CppArgs := InitString ('') ; - Pim := TRUE ; - Pim2 := FALSE ; - Pim3 := FALSE ; - Pim4 := TRUE ; - PositiveModFloorDiv := FALSE ; - Iso := FALSE ; - SeenSources := FALSE ; - Statistics := FALSE ; - StyleChecking := FALSE ; - CompilerDebugging := FALSE ; - GenerateDebugging := FALSE ; - Optimizing := FALSE ; - Pedantic := FALSE ; - Verbose := FALSE ; - Quiet := TRUE ; - CC1Quiet := TRUE ; - Profiling := FALSE ; - DisplayQuadruples := FALSE ; - OptimizeBasicBlock := FALSE ; - OptimizeUncalledProcedures := FALSE ; - OptimizeCommonSubExpressions := FALSE ; - NilChecking := FALSE ; - WholeDivChecking := FALSE ; - WholeValueChecking := FALSE ; - FloatValueChecking := FALSE ; - IndexChecking := FALSE ; - RangeChecking := FALSE ; - ReturnChecking := FALSE ; - CaseElseChecking := FALSE ; - CPreProcessor := FALSE ; - LineDirectives := FALSE ; - ExtendedOpaque := FALSE ; - UnboundedByReference := FALSE ; - VerboseUnbounded := FALSE ; - PedanticParamNames := FALSE ; - PedanticCast := FALSE ; - Xcode := FALSE ; - DumpSystemExports := FALSE ; - GenerateSwig := FALSE ; - Exceptions := TRUE ; - DebugBuiltins := FALSE ; - ForcedLocation := FALSE ; - WholeProgram := FALSE ; - DebugTraceQuad := FALSE ; - DebugTraceAPI := FALSE ; - DebugFunctionLineNumbers := FALSE ; - GenerateStatementNote := FALSE ; - LowerCaseKeywords := FALSE ; - UnusedVariableChecking := FALSE ; - UnusedParameterChecking := FALSE ; - StrictTypeChecking := TRUE ; - AutoInit := FALSE ; - SaveTemps := FALSE ; - ScaffoldDynamic := TRUE ; - ScaffoldStatic := FALSE ; - ScaffoldMain := FALSE ; - UselistFilename := NIL ; - GenModuleList := FALSE ; - GenModuleListFilename := NIL ; - SharedFlag := FALSE ; - Barg := NIL ; - MDarg := NIL ; - MMDarg := NIL ; - MQarg := NIL ; - SaveTempsDir := NIL ; - DumpDir := NIL ; - UninitVariableChecking := FALSE ; - M2Prefix := InitString ('') ; - M2PathName := InitString ('') + cflag := FALSE ; (* -c. *) + RuntimeModuleOverride := InitString (DefaultRuntimeModuleOverride) ; + CppArgs := InitString ('') ; + Pim := TRUE ; + Pim2 := FALSE ; + Pim3 := FALSE ; + Pim4 := TRUE ; + PositiveModFloorDiv := FALSE ; + Iso := FALSE ; + SeenSources := FALSE ; + Statistics := FALSE ; + StyleChecking := FALSE ; + CompilerDebugging := FALSE ; + GenerateDebugging := FALSE ; + Optimizing := FALSE ; + Pedantic := FALSE ; + Verbose := FALSE ; + Quiet := TRUE ; + CC1Quiet := TRUE ; + Profiling := FALSE ; + DisplayQuadruples := FALSE ; + OptimizeBasicBlock := FALSE ; + OptimizeUncalledProcedures := FALSE ; + OptimizeCommonSubExpressions := FALSE ; + NilChecking := FALSE ; + WholeDivChecking := FALSE ; + WholeValueChecking := FALSE ; + FloatValueChecking := FALSE ; + IndexChecking := FALSE ; + RangeChecking := FALSE ; + ReturnChecking := FALSE ; + CaseElseChecking := FALSE ; + CPreProcessor := FALSE ; + LineDirectives := FALSE ; + ExtendedOpaque := FALSE ; + UnboundedByReference := FALSE ; + VerboseUnbounded := FALSE ; + PedanticParamNames := FALSE ; + PedanticCast := FALSE ; + Xcode := FALSE ; + DumpSystemExports := FALSE ; + GenerateSwig := FALSE ; + Exceptions := TRUE ; + DebugBuiltins := FALSE ; + ForcedLocation := FALSE ; + WholeProgram := FALSE ; + DebugTraceQuad := FALSE ; + DebugTraceAPI := FALSE ; + DebugFunctionLineNumbers := FALSE ; + GenerateStatementNote := FALSE ; + LowerCaseKeywords := FALSE ; + UnusedVariableChecking := FALSE ; + UnusedParameterChecking := FALSE ; + StrictTypeChecking := TRUE ; + AutoInit := FALSE ; + SaveTemps := FALSE ; + ScaffoldDynamic := TRUE ; + ScaffoldStatic := FALSE ; + ScaffoldMain := FALSE ; + UselistFilename := NIL ; + GenModuleList := FALSE ; + GenModuleListFilename := NIL ; + SharedFlag := FALSE ; + Barg := NIL ; + MDarg := NIL ; + MMDarg := NIL ; + MQarg := NIL ; + SaveTempsDir := NIL ; + DumpDir := NIL ; + UninitVariableChecking := FALSE ; + UninitVariableConditionalChecking := FALSE ; + M2Prefix := InitString ('') ; + M2PathName := InitString ('') END M2Options. diff --git a/gcc/m2/gm2-compiler/M2Quads.def b/gcc/m2/gm2-compiler/M2Quads.def index ef6c06c..cd011ba 100644 --- a/gcc/m2/gm2-compiler/M2Quads.def +++ b/gcc/m2/gm2-compiler/M2Quads.def @@ -106,6 +106,7 @@ EXPORT QUALIFIED StartBuildDefFile, StartBuildModFile, EndBuildFile, IsBackReference, IsUnConditional, IsConditional, IsBackReferenceConditional, + IsGoto, IsCall, IsReturn, IsProcedureScope, @@ -250,6 +251,13 @@ PROCEDURE IsBackReferenceConditional (q: CARDINAL) : BOOLEAN ; (* + IsGoto - returns true if QuadNo is a goto operation. +*) + +PROCEDURE IsGoto (QuadNo: CARDINAL) : BOOLEAN ; + + +(* IsCall - returns true if QuadNo is a call operation. *) @@ -382,7 +390,7 @@ PROCEDURE DisplayQuadList ; DisplayQuadRange - displays all quads in list range, start..end. *) -PROCEDURE DisplayQuadRange (start, end: CARDINAL) ; +PROCEDURE DisplayQuadRange (scope: CARDINAL; start, end: CARDINAL) ; (* @@ -2591,7 +2599,7 @@ PROCEDURE BuildStmtNote (offset: INTEGER) ; LoopAnalysis - checks whether an infinite loop exists. *) -PROCEDURE LoopAnalysis (Current, End: CARDINAL) ; +PROCEDURE LoopAnalysis (Scope: CARDINAL; Current, End: CARDINAL) ; (* diff --git a/gcc/m2/gm2-compiler/M2Quads.mod b/gcc/m2/gm2-compiler/M2Quads.mod index dc73265..5ed2252 100644 --- a/gcc/m2/gm2-compiler/M2Quads.mod +++ b/gcc/m2/gm2-compiler/M2Quads.mod @@ -126,6 +126,7 @@ FROM SymbolTable IMPORT ModeOfAddr, GetMode, PutMode, GetSymName, IsUnknown, GetUnboundedRecordType, GetUnboundedAddressOffset, GetUnboundedHighOffset, + PutVarArrayRef, ForeachFieldEnumerationDo, ForeachLocalSymDo, GetExported, PutImported, GetSym, GetLibName, @@ -588,6 +589,7 @@ BEGIN RETURN( TRUE ) END + ELSE END ; i := GetNextQuad (i) END ; @@ -712,6 +714,16 @@ END IsQuadA ; (* + IsGoto - returns true if QuadNo is a goto operation. +*) + +PROCEDURE IsGoto (QuadNo: CARDINAL) : BOOLEAN ; +BEGIN + RETURN( IsQuadA (QuadNo, GotoOp) ) +END IsGoto ; + + +(* IsCall - returns true if QuadNo is a call operation. *) @@ -10667,7 +10679,7 @@ END IsInfiniteLoop ; LoopAnalysis - checks whether an infinite loop exists. *) -PROCEDURE LoopAnalysis (Current, End: CARDINAL) ; +PROCEDURE LoopAnalysis (Scope: CARDINAL; Current, End: CARDINAL) ; VAR op : QuadOperator ; op1, op2, op3: CARDINAL ; @@ -10683,10 +10695,18 @@ BEGIN (* found a loop - ie a branch which goes back in quadruple numbers *) IF IsInfiniteLoop(Current) THEN + MetaErrorT1 (QuadToTokenNo(op3), + 'it is very likely (although not absolutely certain) that the top of an infinite loop exists here in {%1Wad}', + Scope) ; + MetaErrorT1 (QuadToTokenNo(Current), + 'and the bottom of the infinite loop is ends here in {%1Wad} or alternatively a component of this loop is never executed', + Scope) ; +(* WarnStringAt(InitString('it is very likely (although not absolutely certain) that the top of an infinite loop is here'), QuadToTokenNo(op3)) ; WarnStringAt(InitString('and the bottom of the infinite loop is ends here or alternatively a component of this loop is never executed'), QuadToTokenNo(Current)) +*) END END END ; @@ -11216,6 +11236,7 @@ BEGIN (* BuildDesignatorArray may have detected des is a constant. *) PutVarConst (Adr, IsVarConst (Array)) END ; + PutVarArrayRef (Adr, TRUE) ; (* From now on it must reference the array element by its lvalue - so we create the type of the referenced entity @@ -11246,15 +11267,15 @@ BEGIN THEN (* ti has no type since constant *) ti := MakeTemporary (tok, ImmediateValue) ; - PutVar(ti, Cardinal) ; + PutVar (ti, Cardinal) ; GenQuadO (tok, ElementSizeOp, ti, arrayType, 1, TRUE) ELSE INC(dim) ; tk := MakeTemporary (tok, RightValue) ; - PutVar(tk, Cardinal) ; + PutVar (tk, Cardinal) ; GenHigh (tok, tk, dim, arraySym) ; tl := MakeTemporary (tok, RightValue) ; - PutVar(tl, Cardinal) ; + PutVar (tl, Cardinal) ; GenQuadO (tok, AddOp, tl, tk, MakeConstLit (tok, MakeKey ('1'), Cardinal), TRUE) ; tj := calculateMultipicand (tok, arraySym, arrayType, dim) ; ti := MakeTemporary (tok, RightValue) ; @@ -11385,6 +11406,7 @@ BEGIN GenQuad (MultOp, tk, ti, tj) ; Adr := MakeTemporary (combinedTok, LeftValue) ; + PutVarArrayRef (Adr, TRUE) ; (* Ok must reference by address - but we contain the type of the referenced entity @@ -13168,14 +13190,14 @@ END DisplayQuadList ; DisplayQuadRange - displays all quads in list range, start..end. *) -PROCEDURE DisplayQuadRange (start, end: CARDINAL) ; +PROCEDURE DisplayQuadRange (scope: CARDINAL; start, end: CARDINAL) ; VAR f: QuadFrame ; BEGIN - printf0('Quadruples:\n') ; - WHILE (start<=end) AND (start#0) DO - DisplayQuad(start) ; - f := GetQF(start) ; + printf0 ('Quadruples for scope: ') ; WriteOperand (scope) ; printf0 ('\n') ; + WHILE (start <= end) AND (start # 0) DO + DisplayQuad (start) ; + f := GetQF (start) ; start := f^.Next END END DisplayQuadRange ; @@ -13194,10 +13216,10 @@ BEGIN IF QuadrupleGeneration THEN WHILE QuadNo#0 DO - f := GetQF(QuadNo) ; + f := GetQF (QuadNo) ; WITH f^ DO i := Operand3 ; (* Next Link along the BackPatch *) - ManipulateReference(QuadNo, Value) (* Filling in the BackPatch. *) + ManipulateReference (QuadNo, Value) (* Filling in the BackPatch. *) END ; QuadNo := i END @@ -13596,17 +13618,17 @@ PROCEDURE WriteOperand (Sym: CARDINAL) ; VAR n: Name ; BEGIN - IF Sym=NulSym + IF Sym = NulSym THEN - printf0('<nulsym>') + printf0 ('<nulsym>') ELSE - n := GetSymName(Sym) ; - printf1('%a', n) ; - IF IsVar(Sym) OR IsConst(Sym) + n := GetSymName (Sym) ; + printf1 ('%a', n) ; + IF IsVar (Sym) OR IsConst (Sym) THEN - printf0('[') ; WriteMode(GetMode(Sym)) ; printf0(']') + printf0 ('[') ; WriteMode (GetMode (Sym)) ; printf0(']') END ; - printf1('(%d)', Sym) + printf1 ('(%d)', Sym) END END WriteOperand ; @@ -13666,7 +13688,15 @@ BEGIN LogicalOrOp : RETURN InitString ('{%kOR}') | LogicalAndOp: RETURN InitString ('{%kAND}') | InclOp : RETURN InitString ('{%kINCL}') | - ExclOp : RETURN InitString ('{%kEXCL}') + ExclOp : RETURN InitString ('{%kEXCL}') | + IfEquOp : RETURN InitString ('=') | + IfLessEquOp : RETURN InitString ('<=') | + IfGreEquOp : RETURN InitString ('>=') | + IfGreOp : RETURN InitString ('>') | + IfLessOp : RETURN InitString ('<') | + IfNotEquOp : RETURN InitString ('#') | + IfInOp : RETURN InitString ('IN') | + IfNotInOp : RETURN InitString ('NOT IN') ELSE RETURN NIL diff --git a/gcc/m2/gm2-compiler/M2Scope.def b/gcc/m2/gm2-compiler/M2Scope.def index 9aed024..c1b684e 100644 --- a/gcc/m2/gm2-compiler/M2Scope.def +++ b/gcc/m2/gm2-compiler/M2Scope.def @@ -37,7 +37,7 @@ EXPORT QUALIFIED ScopeBlock, ScopeProcedure, TYPE ScopeBlock ; - ScopeProcedure = PROCEDURE (CARDINAL, CARDINAL) ; + ScopeProcedure = PROCEDURE (CARDINAL, CARDINAL, CARDINAL) ; (* diff --git a/gcc/m2/gm2-compiler/M2Scope.mod b/gcc/m2/gm2-compiler/M2Scope.mod index d840bf5..106c2a8 100644 --- a/gcc/m2/gm2-compiler/M2Scope.mod +++ b/gcc/m2/gm2-compiler/M2Scope.mod @@ -349,7 +349,7 @@ BEGIN END ; printf0 ("\n") ; - DisplayQuadRange (low, high) ; + DisplayQuadRange (scopeSym, low, high) ; IF next#NIL THEN DisplayScope (next) @@ -428,7 +428,7 @@ BEGIN enter (sb) ; IF (low # 0) AND (high # 0) THEN - p (low, high) + p (scopeSym, low, high) END ; leave (sb) END ; diff --git a/gcc/m2/gm2-compiler/M2SymInit.def b/gcc/m2/gm2-compiler/M2SymInit.def index 2ea6bfc..d0e39fb 100644 --- a/gcc/m2/gm2-compiler/M2SymInit.def +++ b/gcc/m2/gm2-compiler/M2SymInit.def @@ -45,12 +45,11 @@ PROCEDURE GetFieldInitialized (desc: InitDesc; fieldlist: List) : BOOLEAN ; (* - VariableAnalysis - checks to see whether a variable is: - - read before it has been initialized + ScopeBlockVariableAnalysis - checks to see whether a variable is + read before it has been initialized. *) -PROCEDURE VariableAnalysis (Start, End: CARDINAL) ; +PROCEDURE ScopeBlockVariableAnalysis (Scope: CARDINAL; Start, End: CARDINAL) ; PROCEDURE PrintSymInit (desc: InitDesc) ; diff --git a/gcc/m2/gm2-compiler/M2SymInit.mod b/gcc/m2/gm2-compiler/M2SymInit.mod index 18200af..a5457ec 100644 --- a/gcc/m2/gm2-compiler/M2SymInit.mod +++ b/gcc/m2/gm2-compiler/M2SymInit.mod @@ -23,17 +23,28 @@ IMPLEMENTATION MODULE M2SymInit ; FROM Storage IMPORT ALLOCATE, DEALLOCATE ; FROM M2Debug IMPORT Assert ; +FROM M2Printf IMPORT printf0, printf1, printf2, printf3, printf4 ; FROM libc IMPORT printf ; FROM NameKey IMPORT Name, NulName, KeyToCharStar ; -FROM M2Options IMPORT UninitVariableChecking ; -FROM M2MetaError IMPORT MetaErrorT1 ; + +FROM M2Options IMPORT UninitVariableChecking, UninitVariableConditionalChecking, + CompilerDebugging ; + +FROM M2MetaError IMPORT MetaErrorT1, MetaErrorStringT1, MetaErrorStringT2 ; FROM M2LexBuf IMPORT UnknownTokenNo ; +FROM DynamicStrings IMPORT String, InitString, Mark, ConCat, InitString ; +FROM M2Error IMPORT InternalError ; + +FROM M2BasicBlock IMPORT BasicBlock, + InitBasicBlocks, InitBasicBlocksFromRange, + KillBasicBlocks, FreeBasicBlocks, + ForeachBasicBlockDo ; IMPORT Indexing ; FROM Lists IMPORT List, InitList, GetItemFromList, PutItemIntoList, IsItemInList, IncludeItemIntoList, NoOfItemsInList, - RemoveItemFromList, ForeachItemInListDo, KillList ; + RemoveItemFromList, ForeachItemInListDo, KillList, DuplicateList ; FROM SymbolTable IMPORT NulSym, ModeOfAddr, IsVar, IsRecord, GetSType, GetNth, IsRecordField, IsSet, IsArray, IsProcedure, @@ -43,10 +54,14 @@ FROM SymbolTable IMPORT NulSym, ModeOfAddr, IsVar, IsRecord, GetSType, IsConst, IsConstString, NoOfParam, IsVarParam, ForeachLocalSymDo, IsTemporary, ModeOfAddr, IsReallyPointer, IsUnbounded, - IsVarient, IsFieldVarient, GetVarient ; + IsVarient, IsFieldVarient, GetVarient, + IsVarArrayRef ; + +FROM M2Quads IMPORT QuadOperator, GetQuadOtok, GetQuad, GetNextQuad, + IsNewLocalVar, IsReturn, IsKillLocalVar, IsConditional, + IsUnConditional, IsBackReference, IsCall, IsGoto, + GetM2OperatorDesc, Opposite, DisplayQuadRange ; -FROM M2Quads IMPORT QuadOperator, GetQuadOtok, GetQuad, GetNextQuad ; -FROM M2Options IMPORT CompilerDebugging ; FROM M2Printf IMPORT printf0, printf1, printf2 ; FROM M2GCCDeclare IMPORT PrintSym ; @@ -78,9 +93,32 @@ TYPE next : symAlias ; END ; + bbEntry = POINTER TO RECORD + start, end: CARDINAL ; + (* Is this the first bb? *) + first, + (* Does it end with a call? *) + endCall, + (* Does it end with a goto? *) + endGoto, + (* Does it end with a conditional? *) + endCond, + (* Does it form part of a loop? *) + topOfLoop: BOOLEAN ; + indexBB, + nextQuad, + condQuad, + nextBB, + condBB : CARDINAL ; + next : bbEntry ; + END ; + VAR aliasArray: Indexing.Index ; freeList : symAlias ; + bbArray : Indexing.Index ; + bbFreeList: bbEntry ; + errorList : List ; (* Ensure that we only generate one set of warnings per token. *) (* @@ -427,11 +465,115 @@ END ContainsVariant ; (* + IssueConditional - +*) + +PROCEDURE IssueConditional (quad: CARDINAL; conditional: BOOLEAN) ; +VAR + op : QuadOperator ; + op1, op2, op3 : CARDINAL ; + op1tok, op2tok, op3tok, qtok: CARDINAL ; + overflowChecking : BOOLEAN ; + s : String ; +BEGIN + GetQuadOtok (quad, qtok, op, op1, op2, op3, overflowChecking, + op1tok, op2tok, op3tok) ; + IF IsUniqueWarning (qtok) + THEN + op1tok := DefaultTokPos (op1tok, qtok) ; + op2tok := DefaultTokPos (op2tok, qtok) ; + op3tok := DefaultTokPos (op3tok, qtok) ; + IF NOT conditional + THEN + op := Opposite (op) + END ; + s := InitString ('depending upon the result of {%1Oad} ') ; + s := ConCat (s, Mark (GetM2OperatorDesc (op))) ; + s := ConCat (s, InitString (' {%2ad}')) ; + MetaErrorStringT2 (qtok, s, op1, op2) + END +END IssueConditional ; + + +(* + GenerateNoteFlow - +*) + +PROCEDURE GenerateNoteFlow (lst: List; n: CARDINAL; warning: BOOLEAN) ; +VAR + i : CARDINAL ; + ip1Ptr, + iPtr : bbEntry ; +BEGIN + IF NOT warning + THEN + (* Only issue flow messages for non warnings. *) + i := 1 ; + WHILE i <= n DO + iPtr := Indexing.GetIndice (bbArray, i) ; + IF iPtr^.endCond + THEN + IF i < n + THEN + ip1Ptr := Indexing.GetIndice (bbArray, i+1) ; + IssueConditional (iPtr^.end, iPtr^.condBB = ip1Ptr^.indexBB) + END + END ; + INC (i) + END + END +END GenerateNoteFlow ; + + +(* + IssueWarning - issue a warning or note at tok location. +*) + +PROCEDURE IssueWarning (tok: CARDINAL; + before, after: ARRAY OF CHAR; + sym: CARDINAL; warning: BOOLEAN) ; +VAR + s: String ; +BEGIN + s := InitString (before) ; + IF warning + THEN + s := ConCat (s, Mark (InitString ('{%1Wad}'))) + ELSE + s := ConCat (s, Mark (InitString ('{%1Oad}'))) + END ; + s := ConCat (s, Mark (InitString (after))) ; + MetaErrorStringT1 (tok, s, sym) +END IssueWarning ; + + +(* + IsUniqueWarning - return TRUE if a warning has not been issued at tok. + It remembers tok and subsequent calls will always return FALSE. +*) + +PROCEDURE IsUniqueWarning (tok: CARDINAL) : BOOLEAN ; +BEGIN + IF NOT IsItemInList (errorList, tok) + THEN + IncludeItemIntoList (errorList, tok) ; + RETURN TRUE + ELSE + RETURN FALSE + END +END IsUniqueWarning ; + + +(* CheckDeferredRecordAccess - *) PROCEDURE CheckDeferredRecordAccess (procsym: CARDINAL; tok: CARDINAL; - sym: CARDINAL; canDereference: BOOLEAN) ; + sym: CARDINAL; + canDereference, warning: BOOLEAN; + lst: List; i: CARDINAL) ; +VAR + unique: BOOLEAN ; BEGIN IF IsVar (sym) THEN @@ -459,32 +601,49 @@ BEGIN ELSIF IsComponent (sym) THEN Trace ("checkReadInit IsComponent (%d) is true)", sym) ; - IF NOT GetVarComponentInitialized (sym) + IF (NOT GetVarComponentInitialized (sym)) AND IsUniqueWarning (tok) THEN - MetaErrorT1 (tok, - 'attempting to access {%1Wad} before it has been initialized', - sym) + GenerateNoteFlow (lst, i, warning) ; + IssueWarning (tok, + 'attempting to access ', + ' before it has been initialized', + sym, warning) END ELSIF (GetMode (sym) = LeftValue) AND canDereference THEN Trace ("checkReadInit GetMode (%d) = LeftValue and canDereference (LeftValue and RightValue VarCheckReadInit)", sym) ; + unique := TRUE ; IF NOT VarCheckReadInit (sym, LeftValue) THEN - MetaErrorT1 (tok, - 'attempting to access the address of {%1Wad} before it has been initialized', - sym) + unique := IsUniqueWarning (tok) ; + IF unique + THEN + GenerateNoteFlow (lst, i, warning) ; + IssueWarning (tok, + 'attempting to access the address of ', + ' before it has been initialized', + sym, warning) + END END ; IF NOT VarCheckReadInit (sym, RightValue) THEN - MetaErrorT1 (tok, - 'attempting to access {%1Wad} before it has been initialized', sym) + IF unique + THEN + GenerateNoteFlow (lst, i, warning) ; + IssueWarning (tok, + 'attempting to access ', ' before it has been initialized', + sym, warning) + END END ELSE Trace ("checkReadInit call VarCheckReadInit using GetMode (%d)", sym) ; - IF NOT VarCheckReadInit (sym, GetMode (sym)) + IF (NOT VarCheckReadInit (sym, GetMode (sym))) AND IsUniqueWarning (tok) THEN - MetaErrorT1 (tok, - 'attempting to access {%1Wad} before it has been initialized', sym) + GenerateNoteFlow (lst, i, warning) ; + IssueWarning (tok, + 'attempting to access ', + ' before it has been initialized', + sym, warning) END END END @@ -757,7 +916,7 @@ BEGIN (IsGlobalVar (sym) OR IsVarAParam (sym) OR ContainsVariant (GetSType (sym)) OR IsArray (GetSType (sym)) OR IsSet (GetSType (sym)) OR - IsUnbounded (GetSType (sym))) + IsUnbounded (GetSType (sym)) OR IsVarArrayRef (sym)) END IsExempt ; @@ -768,10 +927,11 @@ END IsExempt ; PROCEDURE CheckBinary (procSym, op1tok, op1, op2tok, op2, - op3tok, op3: CARDINAL) ; + op3tok, op3: CARDINAL; warning: BOOLEAN; + lst: List; i: CARDINAL) ; BEGIN - CheckDeferredRecordAccess (procSym, op2tok, op2, FALSE) ; - CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE) ; + CheckDeferredRecordAccess (procSym, op2tok, op2, FALSE, warning, lst, i) ; + CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE, warning, lst, i) ; SetVarInitialized (op1, FALSE) END CheckBinary ; @@ -782,9 +942,10 @@ END CheckBinary ; PROCEDURE CheckUnary (procSym, lhstok, lhs, - rhstok, rhs: CARDINAL) ; + rhstok, rhs: CARDINAL; warning: BOOLEAN; + lst: List; i: CARDINAL) ; BEGIN - CheckDeferredRecordAccess (procSym, rhstok, rhs, FALSE) ; + CheckDeferredRecordAccess (procSym, rhstok, rhs, FALSE, warning, lst, i) ; SetVarInitialized (lhs, FALSE) END CheckUnary ; @@ -793,13 +954,15 @@ END CheckUnary ; CheckXIndr - *) -PROCEDURE CheckXIndr (procSym, lhstok, lhs, type, rhstok, rhs: CARDINAL) ; +PROCEDURE CheckXIndr (procSym, lhstok, lhs, type, + rhstok, rhs: CARDINAL; warning: BOOLEAN; + bblst: List; i: CARDINAL) ; VAR lst : List ; vsym: CARDINAL ; BEGIN - CheckDeferredRecordAccess (procSym, rhstok, rhs, FALSE) ; - CheckDeferredRecordAccess (procSym, lhstok, lhs, FALSE) ; + CheckDeferredRecordAccess (procSym, rhstok, rhs, FALSE, warning, bblst, i) ; + CheckDeferredRecordAccess (procSym, lhstok, lhs, FALSE, warning, bblst, i) ; (* Now see if we know what lhs is pointing to and set fields if necessary. *) vsym := getAlias (lhs) ; IF (vsym # lhs) AND (GetSType (vsym) = type) @@ -824,11 +987,13 @@ END CheckXIndr ; CheckIndrX - *) -PROCEDURE CheckIndrX (procSym, lhstok, lhs, type, rhstok, rhs: CARDINAL) ; +PROCEDURE CheckIndrX (procSym, lhstok, lhs, type, rhstok, rhs: CARDINAL; + warning: BOOLEAN; + lst: List; i: CARDINAL) ; BEGIN - CheckDeferredRecordAccess (procSym, rhstok, rhs, FALSE) ; - CheckDeferredRecordAccess (procSym, rhstok, rhs, TRUE) ; - SetVarInitialized (lhs, FALSE) + CheckDeferredRecordAccess (procSym, rhstok, rhs, FALSE, warning, lst, i) ; + CheckDeferredRecordAccess (procSym, rhstok, rhs, TRUE, warning, lst, i) ; + SetVarInitialized (lhs, IsVarAParam (rhs)) END CheckIndrX ; @@ -846,12 +1011,13 @@ END CheckRecordField ; CheckBecomes - *) -PROCEDURE CheckBecomes (procSym, destok, des, exprtok, expr: CARDINAL) ; +PROCEDURE CheckBecomes (procSym, destok, des, exprtok, expr: CARDINAL; + warning: BOOLEAN; bblst: List; i: CARDINAL) ; VAR lst : List ; vsym: CARDINAL ; BEGIN - CheckDeferredRecordAccess (procSym, exprtok, expr, FALSE) ; + CheckDeferredRecordAccess (procSym, exprtok, expr, FALSE, warning, bblst, i) ; SetupAlias (des, expr) ; SetVarInitialized (des, FALSE) ; (* Now see if we know what lhs is pointing to and set fields if necessary. *) @@ -872,10 +1038,11 @@ END CheckBecomes ; CheckComparison - *) -PROCEDURE CheckComparison (procSym, op1tok, op1, op2tok, op2: CARDINAL) ; +PROCEDURE CheckComparison (procSym, op1tok, op1, op2tok, op2: CARDINAL; + warning: BOOLEAN; lst: List; i: CARDINAL) ; BEGIN - CheckDeferredRecordAccess (procSym, op1tok, op1, FALSE) ; - CheckDeferredRecordAccess (procSym, op2tok, op2, FALSE) + CheckDeferredRecordAccess (procSym, op1tok, op1, FALSE, warning, lst, i) ; + CheckDeferredRecordAccess (procSym, op2tok, op2, FALSE, warning, lst, i) END CheckComparison ; @@ -916,7 +1083,8 @@ END stop ; CheckReadBeforeInitQuad - *) -PROCEDURE CheckReadBeforeInitQuad (procSym: CARDINAL; quad: CARDINAL) : BOOLEAN ; +PROCEDURE CheckReadBeforeInitQuad (procSym: CARDINAL; quad: CARDINAL; + warning: BOOLEAN; lst: List; i: CARDINAL) : BOOLEAN ; VAR op : QuadOperator ; op1, op2, op3 : CARDINAL ; @@ -949,7 +1117,7 @@ BEGIN IfLessOp, IfLessEquOp, IfGreOp, - IfGreEquOp : CheckComparison (procSym, op1tok, op1, op2tok, op2) | + IfGreEquOp : CheckComparison (procSym, op1tok, op1, op2tok, op2, warning, lst, i) | TryOp, ReturnOp, CallOp, @@ -960,26 +1128,27 @@ BEGIN (* Variable references. *) InclOp, - ExclOp : CheckDeferredRecordAccess (procSym, op1tok, op1, FALSE) ; - CheckDeferredRecordAccess (procSym, op1tok, op1, TRUE) ; - CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE) | - NegateOp : CheckUnary (procSym, op1tok, op1, op3tok, op3) | - BecomesOp : CheckBecomes (procSym, op1tok, op1, op3tok, op3) | + ExclOp : CheckDeferredRecordAccess (procSym, op1tok, op1, FALSE, warning, lst, i) ; + CheckDeferredRecordAccess (procSym, op1tok, op1, TRUE, warning, lst, i) ; + CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE, warning, lst, i) | + NegateOp : CheckUnary (procSym, op1tok, op1, op3tok, op3, warning, lst, i) | + BecomesOp : CheckBecomes (procSym, op1tok, op1, op3tok, op3, warning, lst, i) | UnboundedOp, FunctValueOp, + StandardFunctionOp, HighOp, SizeOp : SetVarInitialized (op1, FALSE) | AddrOp : CheckAddr (procSym, op1tok, op1, op3tok, op3) | ReturnValueOp : SetVarInitialized (op1, FALSE) | NewLocalVarOp : | - ParamOp : CheckDeferredRecordAccess (procSym, op2tok, op2, FALSE) ; - CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE) ; + ParamOp : CheckDeferredRecordAccess (procSym, op2tok, op2, FALSE, warning, lst, i) ; + CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE, warning, lst, i) ; IF (op1 > 0) AND (op1 <= NoOfParam (op2)) AND IsVarParam (op2, op1) THEN SetVarInitialized (op3, TRUE) END | - ArrayOp : CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE) ; + ArrayOp : CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE, warning, lst, i) ; SetVarInitialized (op1, TRUE) | RecordFieldOp : CheckRecordField (procSym, op1tok, op1, op2tok, op2) | LogicalShiftOp, @@ -1002,14 +1171,43 @@ BEGIN DivFloorOp, ModTruncOp, DivTruncOp : CheckBinary (procSym, - op1tok, op1, op2tok, op2, op3tok, op3) | - XIndrOp : CheckXIndr (procSym, op1tok, op1, op2, op3tok, op3) | - IndrXOp : CheckIndrX (procSym, op1tok, op1, op2, op3tok, op3) | - RangeCheckOp : | + op1tok, op1, op2tok, op2, op3tok, op3, warning, lst, i) | + XIndrOp : CheckXIndr (procSym, op1tok, op1, op2, op3tok, op3, warning, lst, i) | + IndrXOp : CheckIndrX (procSym, op1tok, op1, op2, op3tok, op3, warning, lst, i) | SaveExceptionOp : SetVarInitialized (op1, FALSE) | - RestoreExceptionOp: CheckDeferredRecordAccess (procSym, op1tok, op1, FALSE) + RestoreExceptionOp: CheckDeferredRecordAccess (procSym, op1tok, op1, FALSE, warning, lst, i) | + + SubrangeLowOp, + SubrangeHighOp : InternalError ('quadruples should have been resolved') | + ElementSizeOp, + BuiltinConstOp, (* Nothing to do, it is assigning a constant to op1 (also a const). *) + BuiltinTypeInfoOp, (* Likewise assigning op1 (const) with a type. *) + ProcedureScopeOp, + InitEndOp, + InitStartOp, + FinallyStartOp, + FinallyEndOp, + CatchBeginOp, + CatchEndOp, + ThrowOp, + StartDefFileOp, + StartModFileOp, + EndFileOp, + CodeOnOp, + CodeOffOp, + ProfileOnOp, + ProfileOffOp, + OptimizeOnOp, + OptimizeOffOp, + InlineOp, + LineNumberOp, + StatementNoteOp, + SavePriorityOp, + RestorePriorityOp, + RangeCheckOp, + ModuleScopeOp, + ErrorOp : | - ELSE END ; RETURN FALSE END CheckReadBeforeInitQuad ; @@ -1019,7 +1217,9 @@ END CheckReadBeforeInitQuad ; FilterCheckReadBeforeInitQuad - *) -PROCEDURE FilterCheckReadBeforeInitQuad (procSym: CARDINAL; start: CARDINAL) : BOOLEAN ; +PROCEDURE FilterCheckReadBeforeInitQuad (procSym: CARDINAL; start: CARDINAL; + warning: BOOLEAN; + lst: List; i: CARDINAL) : BOOLEAN ; VAR Op : QuadOperator ; Op1, Op2, Op3: CARDINAL ; @@ -1027,7 +1227,7 @@ BEGIN GetQuad (start, Op, Op1, Op2, Op3) ; IF (Op # RangeCheckOp) AND (Op # StatementNoteOp) THEN - RETURN CheckReadBeforeInitQuad (procSym, start) + RETURN CheckReadBeforeInitQuad (procSym, start, warning, lst, i) END ; RETURN FALSE END FilterCheckReadBeforeInitQuad ; @@ -1038,43 +1238,366 @@ END FilterCheckReadBeforeInitQuad ; *) PROCEDURE CheckReadBeforeInitFirstBasicBlock (procSym: CARDINAL; - start, end: CARDINAL) ; + start, end: CARDINAL; + warning: BOOLEAN; + lst: List; i: CARDINAL) ; BEGIN - ForeachLocalSymDo (procSym, SetVarUninitialized) ; LOOP - IF FilterCheckReadBeforeInitQuad (procSym, start) OR (start = end) + IF FilterCheckReadBeforeInitQuad (procSym, start, warning, lst, i) THEN - RETURN END ; - start := GetNextQuad (start) + IF start = end + THEN + RETURN + ELSE + start := GetNextQuad (start) + END END END CheckReadBeforeInitFirstBasicBlock ; (* - VariableAnalysis - checks to see whether a variable is: + bbArrayKill - +*) + +PROCEDURE bbArrayKill ; +VAR + i, h : CARDINAL ; + bbPtr: bbEntry ; +BEGIN + h := Indexing.HighIndice (bbArray) ; + i := 1 ; + WHILE i <= h DO + bbPtr := Indexing.GetIndice (bbArray, i) ; + bbPtr^.next := bbFreeList ; + bbFreeList := bbPtr ; + INC (i) + END ; + bbArray := Indexing.KillIndex (bbArray) +END bbArrayKill ; - read before it has been initialized + +(* + DumpBBEntry - *) -PROCEDURE VariableAnalysis (Start, End: CARDINAL) ; +PROCEDURE DumpBBEntry (bbPtr: bbEntry; procSym: CARDINAL) ; +BEGIN + printf4 ("bb %d: scope %d: quads: %d .. %d", + bbPtr^.indexBB, procSym, bbPtr^.start, bbPtr^.end) ; + IF bbPtr^.first + THEN + printf0 (" first") + END ; + IF bbPtr^.endCall + THEN + printf0 (" endcall") + END ; + IF bbPtr^.endGoto + THEN + printf0 (" endgoto") + END ; + IF bbPtr^.endCond + THEN + printf0 (" endcond") + END ; + IF bbPtr^.topOfLoop + THEN + printf0 (" topofloop") + END ; + IF bbPtr^.condBB # 0 + THEN + printf1 (" cond %d", bbPtr^.condBB) + END ; + IF bbPtr^.nextBB # 0 + THEN + printf1 (" next %d", bbPtr^.nextBB) + END ; + printf0 ("\n") +END DumpBBEntry ; + + +(* + DumpBBArray - +*) + +PROCEDURE DumpBBArray (procSym: CARDINAL) ; VAR - Op : QuadOperator ; - Op1, Op2, Op3: CARDINAL ; + bbPtr: bbEntry ; + i, n : CARDINAL ; BEGIN - IF UninitVariableChecking + i := 1 ; + n := Indexing.HighIndice (bbArray) ; + WHILE i <= n DO + bbPtr := Indexing.GetIndice (bbArray, i) ; + DumpBBEntry (bbPtr, procSym) ; + INC (i) + END ; + i := 1 ; + WHILE i <= n DO + bbPtr := Indexing.GetIndice (bbArray, i) ; + printf4 ("bb %d: scope %d: quads: %d .. %d\n", + bbPtr^.indexBB, procSym, bbPtr^.start, bbPtr^.end) ; + DisplayQuadRange (procSym, bbPtr^.start, bbPtr^.end) ; + INC (i) + END +END DumpBBArray ; + + +(* + DumpBBSequence - +*) + +PROCEDURE DumpBBSequence (procSym: CARDINAL; lst: List) ; +VAR + arrayindex, + listindex, n: CARDINAL ; +BEGIN + n := NoOfItemsInList (lst) ; + listindex := 1 ; + printf0 ("=============\n"); + printf0 (" checking sequence:"); + WHILE listindex <= n DO + arrayindex := GetItemFromList (lst, listindex) ; + printf1 (" [%d]", listindex) ; + INC (listindex) + END ; + printf0 ("\n") +END DumpBBSequence ; + + +(* + TestBBSequence - +*) + +PROCEDURE TestBBSequence (procSym: CARDINAL; lst: List) ; +VAR + bbPtr : bbEntry ; + bbi, + i, n : CARDINAL ; + warning: BOOLEAN ; (* Should we issue a warning rather than a note? *) +BEGIN + IF Debugging THEN - GetQuad (Start, Op, Op1, Op2, Op3) ; - CASE Op OF + DumpBBSequence (procSym, lst) + END ; + ForeachLocalSymDo (procSym, SetVarUninitialized) ; + initBlock ; + n := NoOfItemsInList (lst) ; + i := 1 ; + warning := TRUE ; + WHILE i <= n DO + bbi := GetItemFromList (lst, i) ; + bbPtr := Indexing.GetIndice (bbArray, bbi) ; + CheckReadBeforeInitFirstBasicBlock (procSym, bbPtr^.start, bbPtr^.end, warning, lst, i) ; + IF bbPtr^.endCond + THEN + (* Check to see if we are moving into an conditional block in which case + we will issue a note. *) + warning := FALSE + END ; + INC (i) + END ; + killBlock +END TestBBSequence ; - NewLocalVarOp: initBlock ; - CheckReadBeforeInitFirstBasicBlock (Op3, Start, End) ; - killBlock +(* + CreateBBPermultations - +*) + +PROCEDURE CreateBBPermultations (procSym: CARDINAL; i: CARDINAL; lst: List) ; +VAR + duplst: List ; + iPtr : bbEntry ; +BEGIN + IF i = 0 + THEN + TestBBSequence (procSym, lst) + ELSE + iPtr := Indexing.GetIndice (bbArray, i) ; + IF iPtr^.topOfLoop + THEN + TestBBSequence (procSym, lst) ELSE + duplst := DuplicateList (lst) ; + IncludeItemIntoList (duplst, i) ; + IF iPtr^.endCall + THEN + TestBBSequence (procSym, duplst) + ELSIF iPtr^.endGoto + THEN + CreateBBPermultations (procSym, iPtr^.nextBB, duplst) + ELSIF UninitVariableConditionalChecking AND iPtr^.endCond + THEN + CreateBBPermultations (procSym, iPtr^.nextBB, duplst) ; + CreateBBPermultations (procSym, iPtr^.condBB, duplst) + ELSIF iPtr^.endCond + THEN + TestBBSequence (procSym, duplst) + ELSE + (* Fall through. *) + CreateBBPermultations (procSym, iPtr^.nextBB, duplst) + END ; + KillList (duplst) END END -END VariableAnalysis ; +END CreateBBPermultations ; + + +(* + ScopeBlockVariableAnalysis - checks to see whether a variable is + read before it has been initialized. +*) + +PROCEDURE ScopeBlockVariableAnalysis (Scope: CARDINAL; + Start, End: CARDINAL) ; +VAR + bb : BasicBlock ; + lst: List ; +BEGIN + IF UninitVariableChecking + THEN + bbArray := Indexing.InitIndex (1) ; + bb := InitBasicBlocksFromRange (Scope, Start, End) ; + ForeachBasicBlockDo (bb, AppendEntry) ; + KillBasicBlocks (bb) ; + GenerateCFG ; + IF Scope # NulSym + THEN + InitList (lst) ; + IF Debugging + THEN + DumpBBArray (Scope) ; + IF UninitVariableConditionalChecking + THEN + printf0 ("UninitVariableConditionalChecking is TRUE\n") + END + END ; + CreateBBPermultations (Scope, 1, lst) ; + KillList (lst) + END ; + bbArrayKill + END +END ScopeBlockVariableAnalysis ; + + +(* + GetOp3 - +*) + +PROCEDURE GetOp3 (quad: CARDINAL) : CARDINAL ; +VAR + op: QuadOperator ; + op1, op2, op3: CARDINAL ; +BEGIN + GetQuad (quad, op, op1, op2, op3) ; + RETURN op3 +END GetOp3 ; + + +(* + getBBindex - return the basic block index which starts with quad. +*) + +PROCEDURE getBBindex (quad: CARDINAL) : CARDINAL ; +VAR + iPtr : bbEntry ; + i, high: CARDINAL ; +BEGIN + i := 1 ; + high := Indexing.HighIndice (bbArray) ; + WHILE i <= high DO + iPtr := Indexing.GetIndice (bbArray, i) ; + IF iPtr^.start = quad + THEN + RETURN iPtr^.indexBB + END ; + INC (i) + END ; + RETURN 0 +END getBBindex ; + + +(* + GenerateCFG - +*) + +PROCEDURE GenerateCFG ; +VAR + iPtr : bbEntry ; + next, + i, high: CARDINAL ; +BEGIN + i := 1 ; + high := Indexing.HighIndice (bbArray) ; + WHILE i <= high DO + iPtr := Indexing.GetIndice (bbArray, i) ; + IF IsKillLocalVar (iPtr^.end) OR IsReturn (iPtr^.end) + THEN + (* Nothing to do as we have reached the end of this scope. *) + ELSE + next := GetNextQuad (iPtr^.end) ; + iPtr^.nextQuad := next ; + iPtr^.nextBB := getBBindex (next) ; + IF iPtr^.endCond + THEN + iPtr^.condQuad := GetOp3 (iPtr^.end) ; + iPtr^.condBB := getBBindex (iPtr^.condQuad) + END + END ; + INC (i) + END +END GenerateCFG ; + + +(* + NewEntry - +*) + +PROCEDURE NewEntry () : bbEntry ; +VAR + bbPtr: bbEntry ; +BEGIN + IF bbFreeList = NIL + THEN + NEW (bbPtr) + ELSE + bbPtr := bbFreeList ; + bbFreeList := bbFreeList^.next + END ; + RETURN bbPtr +END NewEntry ; + + +(* + AppendEntry - +*) + +PROCEDURE AppendEntry (Start, End: CARDINAL) ; +VAR + bbPtr: bbEntry ; + high : CARDINAL ; +BEGIN + high := Indexing.HighIndice (bbArray) ; + bbPtr := NewEntry () ; + WITH bbPtr^ DO + start := Start ; + end := End ; + first := high = 0 ; + endCall := IsCall (End) ; + endGoto := IsGoto (End) ; + endCond := IsConditional (End) ; + topOfLoop := IsBackReference (Start) ; + indexBB := high + 1 ; + nextQuad := 0 ; + condQuad := 0 ; + nextBB := 0 ; + condBB := 0 ; + next := NIL + END ; + Indexing.PutIndice (bbArray, high + 1, bbPtr) +END AppendEntry ; (* @@ -1298,7 +1821,9 @@ END SetupAlias ; PROCEDURE init ; BEGIN - freeList := NIL + freeList := NIL ; + bbFreeList := NIL ; + InitList (errorList) END init ; diff --git a/gcc/m2/gm2-compiler/SymbolTable.def b/gcc/m2/gm2-compiler/SymbolTable.def index c861cff..8c4feed 100644 --- a/gcc/m2/gm2-compiler/SymbolTable.def +++ b/gcc/m2/gm2-compiler/SymbolTable.def @@ -158,6 +158,7 @@ EXPORT QUALIFIED NulSym, PutDefLink, PutModLink, PutModuleBuiltin, + PutVarArrayRef, IsVarArrayRef, PutConstSet, PutConstructor, @@ -3562,6 +3563,20 @@ PROCEDURE PutModuleBuiltin (sym: CARDINAL; value: BOOLEAN) ; (* + PutVarArrayRef - assigns ArrayRef field with value. +*) + +PROCEDURE PutVarArrayRef (sym: CARDINAL; value: BOOLEAN) ; + + +(* + IsVarArrayRef - returns ArrayRef field value. +*) + +PROCEDURE IsVarArrayRef (sym: CARDINAL) : BOOLEAN ; + + +(* VarCheckReadInit - returns TRUE if sym has been initialized. *) diff --git a/gcc/m2/gm2-compiler/SymbolTable.mod b/gcc/m2/gm2-compiler/SymbolTable.mod index c10e20c..73528b5 100644 --- a/gcc/m2/gm2-compiler/SymbolTable.mod +++ b/gcc/m2/gm2-compiler/SymbolTable.mod @@ -525,6 +525,8 @@ TYPE IsWritten : BOOLEAN ; (* Is variable written to? *) IsSSA : BOOLEAN ; (* Is variable a SSA? *) IsConst : BOOLEAN ; (* Is variable read/only? *) + ArrayRef : BOOLEAN ; (* Is variable used to point *) + (* to an array? *) InitState : LRInitDesc ; (* Initialization state. *) At : Where ; (* Where was sym declared/used *) ReadUsageList, (* list of var read quads *) @@ -4260,6 +4262,7 @@ BEGIN IsWritten := FALSE ; IsSSA := FALSE ; IsConst := FALSE ; + ArrayRef := FALSE ; InitWhereDeclaredTok(tok, At) ; InitWhereFirstUsedTok(tok, At) ; (* Where symbol first used. *) InitList(ReadUsageList[RightValue]) ; @@ -6905,6 +6908,48 @@ END PutConst ; (* + PutVarArrayRef - assigns ArrayRef field with value. +*) + +PROCEDURE PutVarArrayRef (sym: CARDINAL; value: BOOLEAN) ; +VAR + pSym: PtrToSymbol ; +BEGIN + pSym := GetPsym(sym) ; + WITH pSym^ DO + CASE SymbolType OF + + VarSym: Var.ArrayRef := value + + ELSE + InternalError ('expecting VarSym') + END + END +END PutVarArrayRef ; + + +(* + IsVarArrayRef - returns ArrayRef field value. +*) + +PROCEDURE IsVarArrayRef (sym: CARDINAL) : BOOLEAN ; +VAR + pSym: PtrToSymbol ; +BEGIN + pSym := GetPsym(sym) ; + WITH pSym^ DO + CASE SymbolType OF + + VarSym: RETURN (Var.ArrayRef) + + ELSE + InternalError ('expecting VarSym') + END + END +END IsVarArrayRef ; + + +(* PutFieldRecord - places a field, FieldName and FieldType into a record, Sym. VarSym is a optional varient symbol which can be returned by a call to GetVarient(fieldsymbol). The created field diff --git a/gcc/m2/gm2-gcc/init.cc b/gcc/m2/gm2-gcc/init.cc index 834a84e..7bf79cc 100644 --- a/gcc/m2/gm2-gcc/init.cc +++ b/gcc/m2/gm2-gcc/init.cc @@ -103,6 +103,7 @@ EXTERN void _M2_dtoa_init (int argc, char *argv[], char *envp[]); EXTERN void _M2_ldtoa_init (int argc, char *argv[], char *envp[]); EXTERN void _M2_M2Check_init (int argc, char *argv[], char *envp[]); EXTERN void _M2_M2SSA_init (int argc, char *argv[], char *envp[]); +EXTERN void _M2_M2SymInit_init (int argc, char *argv[], char *envp[]); EXTERN void exit (int); EXTERN void M2Comp_compile (const char *filename); EXTERN void RTExceptions_DefaultErrorCatch (void); @@ -195,6 +196,7 @@ init_PerCompilationInit (const char *filename) _M2_PCBuild_init (0, NULL, NULL); _M2_Sets_init (0, NULL, NULL); _M2_M2SSA_init (0, NULL, NULL); + _M2_M2SymInit_init (0, NULL, NULL); _M2_M2Check_init (0, NULL, NULL); M2Comp_compile (filename); } diff --git a/gcc/m2/gm2-gcc/m2options.h b/gcc/m2/gm2-gcc/m2options.h index e203fce4..dd79509 100644 --- a/gcc/m2/gm2-gcc/m2options.h +++ b/gcc/m2/gm2-gcc/m2options.h @@ -136,7 +136,7 @@ EXTERN void M2Options_SetM2Prefix (const char *arg); EXTERN char *M2Options_GetM2Prefix (void); EXTERN void M2Options_SetM2PathName (const char *arg); EXTERN char *M2Options_GetM2PathName (void); -EXTERN void M2Options_SetUninitVariableChecking (bool value); +EXTERN int M2Options_SetUninitVariableChecking (bool value, const char *arg); #undef EXTERN diff --git a/gcc/m2/gm2-lang.cc b/gcc/m2/gm2-lang.cc index ae999a3..c21d29b 100644 --- a/gcc/m2/gm2-lang.cc +++ b/gcc/m2/gm2-lang.cc @@ -470,8 +470,9 @@ gm2_langhook_handle_option ( M2Options_SetUnusedParameterChecking (value); return 1; case OPT_Wuninit_variable_checking: - M2Options_SetUninitVariableChecking (value); - return 1; + return M2Options_SetUninitVariableChecking (value, "known"); + case OPT_Wuninit_variable_checking_: + return M2Options_SetUninitVariableChecking (value, arg); case OPT_fm2_strict_type: M2Options_SetStrictTypeChecking (value); return 1; diff --git a/gcc/m2/lang.opt b/gcc/m2/lang.opt index 6dbdf9d..730a1a2 100644 --- a/gcc/m2/lang.opt +++ b/gcc/m2/lang.opt @@ -297,6 +297,10 @@ Wuninit-variable-checking Modula-2 turns on compile time analysis in the first basic block of a procedure detecting access to uninitialized data. +Wuninit-variable-checking= +Modula-2 Joined +turns on compile time analysis to detect access to uninitialized variables, the checking can be specified by: known,cond,all. + B Modula-2 ; Documented in c.opt diff --git a/gcc/testsuite/gm2/switches/uninit-variable-checking/cascade/fail/cascadedif.mod b/gcc/testsuite/gm2/switches/uninit-variable-checking/cascade/fail/cascadedif.mod new file mode 100644 index 0000000..4468ce0 --- /dev/null +++ b/gcc/testsuite/gm2/switches/uninit-variable-checking/cascade/fail/cascadedif.mod @@ -0,0 +1,25 @@ +MODULE cascadedif ; + + +PROCEDURE test ; +VAR + i: CARDINAL ; + p: CARDINAL ; +BEGIN + i := 1 ; + IF i = 1 + THEN + IF p = 1 + THEN + END + ELSE + IF p = 2 + THEN + END + END +END test ; + + +BEGIN + test +END cascadedif. diff --git a/gcc/testsuite/gm2/switches/uninit-variable-checking/cascade/fail/switches-uninit-variable-checking-cascade-fail.exp b/gcc/testsuite/gm2/switches/uninit-variable-checking/cascade/fail/switches-uninit-variable-checking-cascade-fail.exp new file mode 100644 index 0000000..f5e0c07 --- /dev/null +++ b/gcc/testsuite/gm2/switches/uninit-variable-checking/cascade/fail/switches-uninit-variable-checking-cascade-fail.exp @@ -0,0 +1,37 @@ +# Expect driver script for GCC Regression Tests +# Copyright (C) 2023 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# This file was written by Gaius Mulley (gaius.mulley@southwales.ac.uk) +# for GNU Modula-2. + +if $tracelevel then { + strace $tracelevel +} + +# load support procs +load_lib gm2-torture.exp + +gm2_init_pim "${srcdir}/gm2/switches/uninit-variable-checking/cascade/fail" -Wuninit-variable-checking=all + +foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.mod]] { + # If we're only testing specific files and this isn't one of them, skip it. + if ![runtest_file_p $runtests $testcase] then { + continue + } + + gm2-torture-fail $testcase +} |