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