From 92aaa8ac514cb8d1d177ef727c5db28b77b00f30 Mon Sep 17 00:00:00 2001
From: Austin Seipp <mad.one@gmail.com>
Date: Sun, 13 Jan 2013 04:34:05 +0000
Subject: [PATCH] Ensure the LLVM codegen correctly handles literals in a
branch. #7571
This was causing a failure to build GHC HEAD on my ODROID-U2 ARM
machine. In general, hand-written C-- like in StgStdThunks.cmm would
have tripped this on any platform, meaning bootstrapping with the
LLVM backend was probably broken before.
In general, we need to be sure that when generating code for literals,
we properly narrow the type of the literal to i1. See Note [Literals
and branch conditions] in the LlvmCodeGen.CodeGen module.
This fixes Trac #7571.
Signed-off-by: Austin Seipp <mad.one@gmail.com>
---
compiler/llvmGen/LlvmCodeGen/CodeGen.hs | 86 +++++++++++++++++++++++++------
1 file changed, 70 insertions(+), 16 deletions(-)
diff --git a/compiler/llvmGen/LlvmCodeGen/CodeGen.hs b/compiler/llvmGen/LlvmCodeGen/CodeGen.hs
index 763656a..f6cd118 100644
|
a
|
b
|
|
| 31 | 31 | import Unique |
| 32 | 32 | import Util |
| 33 | 33 | |
| 34 | | import Data.List ( partition ) |
| 35 | | |
| | 34 | import Data.List ( partition ) |
| | 35 | import Data.Maybe ( fromMaybe ) |
| 36 | 36 | |
| 37 | 37 | type LlvmStatements = OrdList LlvmStatement |
| 38 | 38 | |
| … |
… |
|
| 706 | 706 | genCondBranch env cond idT idF = do |
| 707 | 707 | let labelT = blockIdToLlvm idT |
| 708 | 708 | let labelF = blockIdToLlvm idF |
| | 709 | -- See Note [Literals and branch conditions] |
| 709 | 710 | (env', vc, stmts, top) <- exprToVarOpt env i1Option cond |
| 710 | 711 | if getVarType vc == i1 |
| 711 | 712 | then do |
| … |
… |
|
| 714 | 715 | else |
| 715 | 716 | panic $ "genCondBranch: Cond expr not bool! (" ++ show vc ++ ")" |
| 716 | 717 | |
| | 718 | {- Note [Literals and branch conditions] |
| | 719 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | 720 | |
| | 721 | It is important that whenever we generate branch conditions for |
| | 722 | literals like '1', they are properly narrowed to an LLVM expression of |
| | 723 | type 'i1' (for bools.) Otherwise, nobody is happy. So when we convert |
| | 724 | a CmmExpr to an LLVM expression for a branch conditional, exprToVarOpt |
| | 725 | must be certain to return a properly narrowed type. genLit is |
| | 726 | responsible for this, in the case of literal integers. |
| | 727 | |
| | 728 | Often, we won't see direct statements like: |
| | 729 | |
| | 730 | if(1) { |
| | 731 | ... |
| | 732 | } else { |
| | 733 | ... |
| | 734 | } |
| | 735 | |
| | 736 | at this point in the pipeline, because the Glorious Code Generator |
| | 737 | will do trivial branch elimination in the sinking pass (among others,) |
| | 738 | which will eliminate the expression entirely. |
| | 739 | |
| | 740 | However, it's certainly possible and reasonable for this to occur in |
| | 741 | hand-written C-- code. Consider something like: |
| | 742 | |
| | 743 | #ifndef SOME_CONDITIONAL |
| | 744 | #define CHECK_THING(x) 1 |
| | 745 | #else |
| | 746 | #define CHECK_THING(x) some_operation((x)) |
| | 747 | #endif |
| | 748 | |
| | 749 | f() { |
| | 750 | |
| | 751 | if (CHECK_THING(xyz)) { |
| | 752 | ... |
| | 753 | } else { |
| | 754 | ... |
| | 755 | } |
| | 756 | |
| | 757 | } |
| | 758 | |
| | 759 | In such an instance, CHECK_THING might result in an *expression* in |
| | 760 | one case, and a *literal* in the other, depending on what in |
| | 761 | particular was #define'd. So we must be sure to properly narrow the |
| | 762 | literal in this case to i1 as it won't be eliminated beforehand. |
| | 763 | |
| | 764 | For a real example of this, see ./rts/StgStdThunks.cmm |
| | 765 | |
| | 766 | -} |
| | 767 | |
| | 768 | |
| 717 | 769 | |
| 718 | 770 | -- | Switch branch |
| 719 | 771 | -- |
| … |
… |
|
| 770 | 822 | exprToVarOpt env opt e = case e of |
| 771 | 823 | |
| 772 | 824 | CmmLit lit |
| 773 | | -> genLit env lit |
| | 825 | -> genLit opt env lit -- See Note [Literals and branch conditions] |
| 774 | 826 | |
| 775 | 827 | CmmLoad e' ty |
| 776 | 828 | -> genLoad env e' ty |
| … |
… |
|
| 1206 | 1258 | |
| 1207 | 1259 | |
| 1208 | 1260 | -- | Generate code for a literal |
| 1209 | | genLit :: LlvmEnv -> CmmLit -> UniqSM ExprData |
| 1210 | | genLit env (CmmInt i w) |
| 1211 | | = return (env, mkIntLit (LMInt $ widthInBits w) i, nilOL, []) |
| | 1261 | genLit :: EOption -> LlvmEnv -> CmmLit -> UniqSM ExprData |
| | 1262 | genLit (EOption opt) env (CmmInt i w) |
| | 1263 | -- See Note [Literals and branch conditions] |
| | 1264 | = let width = fromMaybe (LMInt $ widthInBits w) opt |
| | 1265 | in return (env, mkIntLit width i, nilOL, []) |
| 1212 | 1266 | |
| 1213 | | genLit env (CmmFloat r w) |
| | 1267 | genLit _ env (CmmFloat r w) |
| 1214 | 1268 | = return (env, LMLitVar $ LMFloatLit (fromRational r) (widthToLlvmFloat w), |
| 1215 | 1269 | nilOL, []) |
| 1216 | 1270 | |
| 1217 | | genLit env cmm@(CmmLabel l) |
| | 1271 | genLit _ env cmm@(CmmLabel l) |
| 1218 | 1272 | = let dflags = getDflags env |
| 1219 | 1273 | label = strCLabel_llvm env l |
| 1220 | 1274 | ty = funLookup label env |
| … |
… |
|
| 1236 | 1290 | (v1, s1) <- doExpr lmty $ Cast LM_Ptrtoint var (llvmWord dflags) |
| 1237 | 1291 | return (env, v1, unitOL s1, []) |
| 1238 | 1292 | |
| 1239 | | genLit env (CmmLabelOff label off) = do |
| | 1293 | genLit opt env (CmmLabelOff label off) = do |
| 1240 | 1294 | let dflags = getDflags env |
| 1241 | | (env', vlbl, stmts, stat) <- genLit env (CmmLabel label) |
| | 1295 | (env', vlbl, stmts, stat) <- genLit opt env (CmmLabel label) |
| 1242 | 1296 | let voff = toIWord dflags off |
| 1243 | 1297 | (v1, s1) <- doExpr (getVarType vlbl) $ LlvmOp LM_MO_Add vlbl voff |
| 1244 | 1298 | return (env', v1, stmts `snocOL` s1, stat) |
| 1245 | 1299 | |
| 1246 | | genLit env (CmmLabelDiffOff l1 l2 off) = do |
| | 1300 | genLit opt env (CmmLabelDiffOff l1 l2 off) = do |
| 1247 | 1301 | let dflags = getDflags env |
| 1248 | | (env1, vl1, stmts1, stat1) <- genLit env (CmmLabel l1) |
| 1249 | | (env2, vl2, stmts2, stat2) <- genLit env1 (CmmLabel l2) |
| | 1302 | (env1, vl1, stmts1, stat1) <- genLit opt env (CmmLabel l1) |
| | 1303 | (env2, vl2, stmts2, stat2) <- genLit opt env1 (CmmLabel l2) |
| 1250 | 1304 | let voff = toIWord dflags off |
| 1251 | 1305 | let ty1 = getVarType vl1 |
| 1252 | 1306 | let ty2 = getVarType vl2 |
| … |
… |
|
| 1262 | 1316 | else |
| 1263 | 1317 | panic "genLit: CmmLabelDiffOff encountered with different label ty!" |
| 1264 | 1318 | |
| 1265 | | genLit env (CmmBlock b) |
| 1266 | | = genLit env (CmmLabel $ infoTblLbl b) |
| | 1319 | genLit opt env (CmmBlock b) |
| | 1320 | = genLit opt env (CmmLabel $ infoTblLbl b) |
| 1267 | 1321 | |
| 1268 | | genLit _ CmmHighStackMark |
| | 1322 | genLit _ _ CmmHighStackMark |
| 1269 | 1323 | = panic "genStaticLit - CmmHighStackMark unsupported!" |
| 1270 | 1324 | |
| 1271 | 1325 | |