diff options
Diffstat (limited to 'utils/debugNCG/Diff_Gcc_Nat.hs')
-rw-r--r-- | utils/debugNCG/Diff_Gcc_Nat.hs | 380 |
1 files changed, 380 insertions, 0 deletions
diff --git a/utils/debugNCG/Diff_Gcc_Nat.hs b/utils/debugNCG/Diff_Gcc_Nat.hs new file mode 100644 index 0000000000..02b642821e --- /dev/null +++ b/utils/debugNCG/Diff_Gcc_Nat.hs @@ -0,0 +1,380 @@ + +module Main where +import List +import System +import Char +import Array + +--import IOExts(trace) + +type Label = String +type Code = [String] + +pzipWith f [] [] = [] +pzipWith f (a:as) (b:bs) = (f a b) : pzipWith f as bs +pzipWith f _ _ = error "pzipWith: unbalanced list" + +main + = getArgs >>= \args -> + --return ["/home/v-julsew/SOLARIS/NCG/fpt/ghc/tests/codeGen/should_run/cg001.s"] + -- >>= \args -> + if length args /= 1 + then putStr ("\ndiff_gcc_nat:\n" ++ + " usage: create File.s-gcc and File.s-nat\n" ++ + " then do: diff_gcc_nat File.s > synth.S\n" ++ + " and compile synth.S into your program.\n" ++ + "diff_gcc_nat is to help debug GHC's native code generator;\n" ++ + "it is quite useless for any other purpose. For details, see\n" ++ + " fptools/ghc/utils/debugNCG/README.\n"++ + "\n" + ) + else + do + let [f_root] = args + f_gcc <- readFile (f_root ++ "-gcc") + f_nat <- readFile (f_root ++ "-nat") + + let split_nat0 = breakOn is_split_line (lines f_nat) + split_nat = filter (not.null.getLabels) split_nat0 + + split_markers_present + = any is_split_line (lines f_nat) + + labels_nat = map getLabels split_nat + labels_cls = map (map breakLabel) labels_nat + + labels_merged :: [(Label, [LabelKind])] + labels_merged = map mergeBroken labels_cls + + classified :: [(Label, [LabelKind], [String])] + classified + = pzipWith (\ merged text -> (fst merged, snd merged, text)) + labels_merged split_nat + + lines_gcc = lines f_gcc + + (syncd, gcc_unused) + = find_correspondings classified lines_gcc + (ok_syncs, nat_unused) + = check_syncs syncd + + num_ok = length ok_syncs + + preamble + = map (\i -> "#define NATIVE_" ++ show i ++ " 0") [1 .. num_ok] + ++ ["", + "#define UNMATCHED_NAT 0", + "#define UNMATCHED_GCC 1", + ""] + + final + = preamble + ++ concat (pzipWith pp_ok_sync ok_syncs [1 .. num_ok]) + ++ ["", + "//============== unmatched NAT =================", + "#if UNMATCHED_NAT", + ""] + ++ nat_unused + ++ ["", + "#endif", + "", + "//============== unmatched GCC =================", + "#if UNMATCHED_GCC"] + ++ gcc_unused + ++ ["#endif" + ] + + if split_markers_present + then putStr (unlines final) + else putStr ("\ndiff_gcc_nat:\n" + ++ " fatal error: NCG output doesn't contain any\n" + ++ " ___ncg_debug_marker marks. Can't continue!\n" + ++ " To fix: enable these markers in\n" + ++ " fptools/ghc/compiler/nativeGen/AsmCodeGen.lhs,\n" + ++ " recompile the compiler, and regenerate the assembly.\n\n") + + +pp_ok_sync :: (Label, [LabelKind], [String], [String]) + -> Int + -> [String] +pp_ok_sync (lbl, kinds, nat_code, gcc_code) number + = reconstruct number nat_code gcc_code + + +check_syncs :: [(Label, [LabelKind], [String], Maybe [String])] -- raw syncd + -> ( [(Label, [LabelKind], [String], [String])], -- ok syncs + [String] ) -- nat unsyncd + +check_syncs [] = ([],[]) +check_syncs (sync:syncs) + = let (syncs_ok, syncs_uu) = check_syncs syncs + in case sync of + (lbl, kinds, nat, Nothing) + -> (syncs_ok, nat ++ syncs_uu) + (lbl, kinds, nat, Just gcc_code) + -> ((lbl,kinds,nat,gcc_code):syncs_ok, syncs_uu) + + +find_correspondings :: [(Label, [LabelKind], [String])] -- native info + -> [String] -- gcc initial + -> ( [(Label, [LabelKind], [String], Maybe [String])], + [String] ) + -- ( native info + found gcc stuff, + -- unused gcc stuff ) + +find_correspondings native gcc_init + = f native gcc_init + where + wurble x (xs, gcc_final) = (x:xs, gcc_final) + + f [] gcc_uu = ( [], gcc_uu ) + f (nat:nats) gcc_uu + = case nat of { (lbl, kinds, nat_code) -> + case find_corresponding lbl kinds gcc_uu of + Just (gcc_code, gcc_uu2) + | gcc_code == gcc_code + -> --gcc_code `seq` gcc_uu2 `seq` + wurble (lbl, kinds, nat_code, Just gcc_code) (f nats gcc_uu2) + Nothing + -> gcc_uu `seq` + wurble (lbl, kinds, nat_code, Nothing) (f nats gcc_uu) + } + + +find_corresponding :: Label -- root + -> [LabelKind] -- kinds + -> [String] -- gcc text + -> Maybe ([String],[String]) -- (found text, gcc leftovers) + +find_corresponding root kinds gcc_lines + = -- Enable the following trace in order to debug pattern matching problems. + --trace ( + -- case result of + -- Nothing -> show (root,kinds) ++ "\nNothing\n\n" + -- Just (found,uu) + -- -> show (root, kinds) ++ "\n" ++ unlines found ++ "\n\n" + --) + result + where + + arr = listArray (1, length gcc_lines) gcc_lines + pfxMatch ss t + = let clean_t = filter (not.isSpace) t + in any (`isPrefixOf` clean_t) ss + + result + = case kinds of + + [Vtbl] + -> let lbl_i = find_label arr (reconstruct_label root Vtbl) + fst_i = search_back arr lbl_i (pfxMatch [".text"]) + in + splice arr fst_i lbl_i + + [Closure] + -> let lbl_i = find_label arr (reconstruct_label root Closure) + fst_i = search_back arr lbl_i (pfxMatch [".data"]) + lst_i = search_fwds arr (lbl_i+1) + (not . pfxMatch [".long",".uaword",".uahalf"]) + in + splice arr fst_i (lst_i-1) + + [Alt] + -> let lbl_i = find_label arr (reconstruct_label root Alt) + fst_i = search_back arr lbl_i (pfxMatch ["."]) + lst_i = search_fwds arr lbl_i (pfxMatch [".d", ".t", ".r", ".g"]) + in + splice arr fst_i (lst_i-1) + + [Dflt] + -> let lbl_i = find_label arr (reconstruct_label root Dflt) + fst_i = search_back arr lbl_i (pfxMatch ["."]) + lst_i = search_fwds arr lbl_i (pfxMatch [".d", ".t", ".r", ".g"]) + in + splice arr fst_i (lst_i-1) + + [Info,Entry] + -> let info_i = find_label arr (reconstruct_label root Info) + fst_i = search_back arr info_i (pfxMatch [".text"]) + entry_i = find_label arr (reconstruct_label root Entry) + lst_i = search_fwds arr entry_i (pfxMatch [".d", ".t", ".r", ".g"]) + in + splice arr fst_i (lst_i-1) + + [Info,Entry,Fast k] + -> let info_i = find_label arr (reconstruct_label root Info) + fst_i = search_back arr info_i (pfxMatch [".text"]) + fast_i = find_label arr (reconstruct_label root (Fast k)) + lst_i = search_fwds arr fast_i (pfxMatch [".d", ".t", ".r", ".g"]) + in + splice arr fst_i (lst_i-1) + + [Info,Ret] + -> let info_i = find_label arr (reconstruct_label root Info) + fst_i = search_back arr info_i (pfxMatch [".text"]) + ret_i = find_label arr (reconstruct_label root Ret) + lst_i = search_fwds arr ret_i (pfxMatch [".d", ".t", ".r", ".g"]) + in + splice arr fst_i (lst_i-1) + + [Srt] + -> let lbl_i = find_label arr (reconstruct_label root Srt) + fst_i = search_back arr lbl_i (pfxMatch [".text",".data"]) + lst_i = search_fwds arr (lbl_i+1) + (not . pfxMatch [".long",".uaword",".uahalf"]) + in + splice arr fst_i (lst_i-1) + + [CTbl] + -> let lbl_i = find_label arr (reconstruct_label root CTbl) + fst_i = search_back arr lbl_i (pfxMatch [".text"]) + lst_i = search_fwds arr (lbl_i+1) + (not . pfxMatch [".long",".uaword",".uahalf"]) + in + splice arr fst_i (lst_i-1) + + [Init] + -> let lbl_i = find_label arr (reconstruct_label root Init) + fst_i = search_back arr lbl_i (pfxMatch [".data"]) + lst_i = search_fwds arr lbl_i (pfxMatch [".d", ".t", ".r", ".g"]) + in + splice arr fst_i (lst_i-1) + other + -> error ("find_corresponding: " ++ show kinds) + + +search_back :: Array Int String -> Int -> (String -> Bool) -> Int +search_back code start_ix pred + = let test_ixs = [start_ix, start_ix-1 .. fst (bounds code)] + in case dropWhile (not . pred . (code !)) test_ixs of + (ok:_) -> ok + [] -> fst (bounds code) - 1 + +search_fwds :: Array Int String -> Int -> (String -> Bool) -> Int +search_fwds code start_ix pred + = let test_ixs = [start_ix .. snd (bounds code)] + in case dropWhile (not . pred . (code !)) test_ixs of + (ok:_) -> ok + [] -> snd (bounds code) + 1 + + +find_label :: Array Int String -> Label -> Int +find_label code lbl + = --trace (unlines (map show (assocs code))) ( + case [idx | (idx, lbl2) <- assocs code, lbl == lbl2] of + [idx] -> idx + other -> error ("find_label `" ++ lbl ++ "'\n") + --) + +reconstruct_label :: Label -> LabelKind -> Label +reconstruct_label root Init + = "__stginit_" ++ root ++ ":" +reconstruct_label root kind + = root ++ "_" ++ pp kind ++ ":" + where + pp Info = "info" + pp Entry = "entry" + pp Closure = "closure" + pp Alt = "alt" + pp Vtbl = "vtbl" + pp Default = "dflt" + pp (Fast i) = "fast" ++ show i + pp Dflt = "dflt" + pp Srt = "srt" + pp Ret = "ret" + pp CTbl = "tbl" + +splice :: Array Int String -> Int -> Int -> Maybe ([String],[String]) +splice gcc_code lo hi + | lo <= hi && clo <= lo && hi <= chi + = Just (map (gcc_code !) ix_used, + map (gcc_code !) (low_ix_uu ++ high_ix_uu)) + | otherwise + = error "splice" + where + (clo,chi) = bounds gcc_code + low_ix_uu = [clo .. lo-1] + high_ix_uu = [hi+1 .. chi] + ix_used = [lo .. hi] + +------------------------------------ + +getLabels :: [Label] -> [Label] +getLabels = sort . nub . filter is_interesting_label + +data LabelKind + = Info | Entry | Fast Int | Closure | Alt | Vtbl | Default + | Dflt | Srt | Ret | CTbl | Init + deriving (Eq, Ord, Show) + +breakLabel :: Label -> (Label,LabelKind) +breakLabel s + = let sr = reverse s + kr = takeWhile (/= '_') sr + mr = drop (1 + length kr) sr + m = reverse mr + k = reverse kr + kind + | take 4 k == "fast" + = Fast (read (takeWhile isDigit (drop 4 k))) + | otherwise + = case k of + "info:" -> Info + "entry:" -> Entry + "closure:" -> Closure + "alt:" -> Alt + "vtbl:" -> Vtbl + "dflt:" -> Dflt + "srt:" -> Srt + "ret:" -> Ret + "tbl:" -> CTbl + _ -> error ("breakLabel: " ++ show (s,k,m)) + in + if head m == '_' && dropWhile (== '_') m == "stginit" + then (init k, Init) + else (m, kind) + +mergeBroken :: [(Label,LabelKind)] -> (Label, [LabelKind]) +mergeBroken pairs + = let (roots, kinds) = unzip pairs + ok = all (== (head roots)) (tail roots) + && length kinds == length (nub kinds) + in + if ok + then (head roots, sort kinds) + else error ("mergeBroken: " ++ show pairs) + + +reconstruct :: Int -> Code -> Code -> Code +reconstruct number nat_code gcc_code + = ["", + "//------------------------------------------"] + ++ map (comment ("//-- ")) (getLabels gcc_code) + ++ ["", "#if NATIVE_" ++ show number, "//nat version", ""] + ++ nat_code + ++ ["", "#else", "//gcc version", ""] + ++ gcc_code + ++ ["", "#endif"] + +comment str x = str ++ x + +----------------------------------------------------- +split_marker = "___ncg_debug_marker" + +is_split_line s + = let m = split_marker + in take 19 s == m || take 19 (drop 2 s) == m + +is_interesting_label s + = not (null s) + && not (any isSpace s) + && last s == ':' + && '_' `elem` s + +breakOn :: (a -> Bool) -> [a] -> [[a]] +breakOn p [] = [] +breakOn p xs + = let ys = takeWhile (not . p) xs + rest = drop (1 + length ys) xs + in + if null ys then breakOn p rest else ys : breakOn p rest |