Skip to content

Commit af2f3b3

Browse files
authored
Specially handle short strings in the parser (#475)
* Specially handle short strings in the parser These short strings are read using the appropriate constructor, rather than the general buffer constructor. So the empty and singleton constructors are now public. Other changes include optimising foreign lpvm cast instructions applied to constant chars, integers and floats, as they get generated in this case. This avoids several instructions in calling unboxed constructors with constant arguments. Also use the -n wybemk flag in final-dump-test.sh, to turn off colourising, making diffs easier to read. There are numerous code improvements in final dump tests, including allowing specialisation to kick in in many places, since unboxed values cannot be aliased. There's one unfortunate change in output for constant_type_constraint_error.wybe: the error message for ?a = "s":int now complains about a type error in the call to wybe.string.singleton, which doesn't appear on the line. I think this is tolerable for now, as it would be difficult to fix. Closes #473 * Address all review comments
1 parent 17687d8 commit af2f3b3

File tree

123 files changed

+1823
-1852
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

123 files changed

+1823
-1852
lines changed

WYBE.md

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2245,38 +2245,46 @@ Floating point multiplication
22452245
Floating point division
22462246
- `foreign llvm frem(`arg1:float, arg2:float`)`:float
22472247
Floating point remainder
2248-
- `foreign llvm fcmp_ord(`arg1:float, arg2:float`)`:bool
2249-
Floating point ordered (neither is a NaN)
2248+
2249+
2250+
##### Floating point comparisons
2251+
2252+
Floating point comparisons are either *ordered* or *unordered*, the former
2253+
returning false if either comparand is not a number (NaN), while the latter sort
2254+
return true in that case.
2255+
2256+
- `foreign llvm fcmp_false(`arg1:float, arg2:float`)`:bool
2257+
Always returns false with no comparison
22502258
- `foreign llvm fcmp_oeq(`arg1:float, arg2:float`)`:bool
22512259
Floating point equality
2252-
- `foreign llvm fcmp_one(`arg1:float, arg2:float`)`:bool
2253-
Floating point disequality
2254-
- `foreign llvm fcmp_olt(`arg1:float, arg2:float`)`:bool
2255-
Floating point (signed) strictly less
2256-
- `foreign llvm fcmp_ole(`arg1:float, arg2:float`)`:bool
2257-
Floating point (signed) less or equal
22582260
- `foreign llvm fcmp_ogt(`arg1:float, arg2:float`)`:bool
2259-
Floating point (signed) strictly greater
2261+
Floating point strictly greater
22602262
- `foreign llvm fcmp_oge(`arg1:float, arg2:float`)`:bool
2261-
Floating point (signed) greater or equal
2263+
Floating point greater or equal
2264+
- `foreign llvm fcmp_olt(`arg1:float, arg2:float`)`:bool
2265+
Floating point strictly less
2266+
- `foreign llvm fcmp_ole(`arg1:float, arg2:float`)`:bool
2267+
Floating point less or equal
2268+
- `foreign llvm fcmp_one(`arg1:float, arg2:float`)`:bool
2269+
Floating point disequality
22622270
- `foreign llvm fcmp_ord(`arg1:float, arg2:float`)`:bool
2263-
Floating point unordered (either is a NaN)
2271+
Floating point ordered (neither is a NaN)
22642272
- `foreign llvm fcmp_ueq(`arg1:float, arg2:float`)`:bool
22652273
Floating point unordered or equal
2266-
- `foreign llvm fcmp_une(`arg1:float, arg2:float`)`:bool
2267-
Floating point unordered or not equal
2268-
- `foreign llvm fcmp_ult(`arg1:float, arg2:float`)`:bool
2269-
Floating point unordered or strictly less
2270-
- `foreign llvm fcmp_ule(`arg1:float, arg2:float`)`:bool
2271-
Floating point unordered or less or equal
22722274
- `foreign llvm fcmp_ugt(`arg1:float, arg2:float`)`:bool
22732275
Floating point unordered or strictly greater
22742276
- `foreign llvm fcmp_uge(`arg1:float, arg2:float`)`:bool
22752277
Floating point unordered or greater or equal
2278+
- `foreign llvm fcmp_ult(`arg1:float, arg2:float`)`:bool
2279+
Floating point unordered or strictly less
2280+
- `foreign llvm fcmp_ule(`arg1:float, arg2:float`)`:bool
2281+
Floating point unordered or less or equal
2282+
- `foreign llvm fcmp_une(`arg1:float, arg2:float`)`:bool
2283+
Floating point unordered or not equal
2284+
- `foreign llvm fcmp_uno(`arg1:float, arg2:float`)`:bool
2285+
Floating point unordered (either is a NaN)
22762286
- `foreign llvm fcmp_true(`arg1:float, arg2:float`)`:bool
22772287
Always returns true with no comparison
2278-
- `foreign llvm fcmp_false(`arg1:float, arg2:float`)`:bool
2279-
Always returns false with no comparison
22802288
22812289
##### <a name="conversion"></a>Integer/floating point conversion
22822290
@@ -2309,7 +2317,7 @@ treat this as an ordinary pointer.
23092317
- `opaque`
23102318
the type is a machine address, similar to the `void *` type in C. Wybe treats such values as opaque.
23112319
- *n* `bit signed`
2312-
a signed primitive number type comprising *n* bits, where *n* is any non-negative
2320+
a signed primitive number type comprising *n* bits, where *n* is any positive
23132321
integer. Represents integers between -2<sup>*n*-1</sup> and 2<sup>*n*-1</sup>-1 inclusive.
23142322
- *n* `bit unsigned`
23152323
an unsigned primitive number type comprising *n* bits, where *n* is any non-negative

src/BodyBuilder.hs

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import Snippets ( boolType, intType, primMove )
1919
import Util
2020
import Config (minimumSwitchCases, wordSize)
2121
import Options (LogSelection(BodyBuilder))
22+
import Data.Char ( ord )
2223
import Data.Map as Map
2324
import Data.List as List
2425
import Data.Set as Set
@@ -234,11 +235,6 @@ instance Show Constraint where
234235
= show v ++ ":" ++ show t ++ " ~= " ++ show a
235236

236237

237-
-- negateConstraint :: Constraint -> Constraint
238-
-- negateConstraint (Equal v n) = NotEqual v n
239-
-- negateConstraint (NotEqual v n) = Equal v n
240-
241-
242238
----------------------------------------------------------------
243239
-- BodyBuilder Primitive Operations
244240
----------------------------------------------------------------
@@ -954,6 +950,7 @@ updateVariableFlows prim = do
954950
-- performing the operation at compile-time.
955951
simplifyForeign :: String -> ProcName -> [Ident] -> [PrimArg] -> Prim
956952
simplifyForeign "llvm" op flags args = simplifyOp op flags args
953+
simplifyForeign "lpvm" op flags args = simplifyLPVM op flags args
957954
simplifyForeign lang op flags args = PrimForeign lang op flags args
958955

959956

@@ -1130,21 +1127,53 @@ simplifyOp "fdiv" _ [ArgFloat n1 ty, ArgFloat n2 _, output] =
11301127
simplifyOp "fdiv" _ [arg, ArgFloat 1 _, output] =
11311128
primMove arg output
11321129
-- Float comparisons
1130+
simplifyOp "fcmp_false" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
1131+
primMove (boolConstant False) output
11331132
simplifyOp "fcmp_oeq" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
11341133
primMove (boolConstant $ n1==n2) output
1135-
simplifyOp "fcmp_one" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
1136-
primMove (boolConstant $ n1/=n2) output
1134+
simplifyOp "fcmp_ogt" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
1135+
primMove (boolConstant $ n1>n2) output
1136+
simplifyOp "fcmp_oge" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
1137+
primMove (boolConstant $ n1>=n2) output
11371138
simplifyOp "fcmp_olt" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
11381139
primMove (boolConstant $ n1<n2) output
11391140
simplifyOp "fcmp_ole" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
11401141
primMove (boolConstant $ n1<=n2) output
1141-
simplifyOp "fcmp_ogt" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
1142+
simplifyOp "fcmp_one" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
1143+
primMove (boolConstant $ n1/=n2) output
1144+
simplifyOp "fcmp_ord" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
1145+
primMove (boolConstant True) output
1146+
simplifyOp "fcmp_ueq" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
1147+
primMove (boolConstant $ n1==n2) output
1148+
simplifyOp "fcmp_ugt" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
11421149
primMove (boolConstant $ n1>n2) output
1143-
simplifyOp "fcmp_oge" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
1150+
simplifyOp "fcmp_uge" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
11441151
primMove (boolConstant $ n1>=n2) output
1152+
simplifyOp "fcmp_ult" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
1153+
primMove (boolConstant $ n1<n2) output
1154+
simplifyOp "fcmp_ule" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
1155+
primMove (boolConstant $ n1<=n2) output
1156+
simplifyOp "fcmp_une" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
1157+
primMove (boolConstant $ n1/=n2) output
1158+
simplifyOp "fcmp_uno" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
1159+
primMove (boolConstant False) output
1160+
simplifyOp "fcmp_true" _ [ArgFloat n1 _, ArgFloat n2 _, output] =
1161+
primMove (boolConstant True) output
11451162
simplifyOp name flags args = PrimForeign "llvm" name flags args
11461163

11471164

1165+
-- | Simplify and canonicalise llpm instructions where possible. For now, this only
1166+
-- handles cast instructions for constants.
1167+
simplifyLPVM :: ProcName -> [Ident] -> [PrimArg] -> Prim
1168+
simplifyLPVM "cast" _ [ArgInt n _, output] =
1169+
primMove (ArgInt n (argType output)) output
1170+
simplifyLPVM "cast" _ [ArgChar ch _, output] =
1171+
primMove (ArgInt (fromIntegral $ ord ch) (argType output)) output
1172+
simplifyLPVM "cast" _ [ArgFloat n _, output] =
1173+
primMove (ArgFloat n (argType output)) output
1174+
simplifyLPVM name flags args = PrimForeign "lpvm" name flags args
1175+
1176+
11481177
boolConstant :: Bool -> PrimArg
11491178
boolConstant bool = ArgInt (fromIntegral $ fromEnum bool) boolType
11501179

src/Expansion.hs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import Data.Map as Map
2727
import Data.Set as Set
2828
import Data.Maybe as Maybe
2929
import Options (LogSelection (Expansion))
30+
import Distribution.Simple.Setup (emptyGlobalFlags)
31+
import Snippets
3032

3133

3234
-- | Expand the supplied ProcDef, inlining as desired.
@@ -169,6 +171,15 @@ addRenaming var val = do
169171
-- are used to tell which variables shoudn't be renamed.
170172

171173

174+
-- | Generate a fresh CallSiteID.
175+
genCallSiteID :: Expander CallSiteID
176+
genCallSiteID = do
177+
id <- gets nextCallSiteID
178+
modify (\st -> st {nextCallSiteID = id + 1})
179+
return id
180+
181+
182+
-- | Add an instruction to the body, possibly renaming variables
172183
addInstr :: Prim -> OptPos -> Expander ()
173184
addInstr prim pos = do
174185
-- reassign "CallSiteID" if the given prim is inlined from other proc
@@ -177,8 +188,7 @@ addInstr prim pos = do
177188
inlinePos <- gets inlining
178189
if isJust inlinePos
179190
then do
180-
callSiteID <- gets nextCallSiteID
181-
modify (\st -> st {nextCallSiteID = callSiteID + 1})
191+
callSiteID <- genCallSiteID
182192
return $ PrimCall callSiteID pspec impurity args gFlows
183193
else
184194
return prim
@@ -332,6 +342,34 @@ inlineCall proto args body pos = do
332342

333343

334344
expandArg :: PrimArg -> Expander PrimArg
345+
-- termToExp (StringConst pos "" DoubleQuote)
346+
-- = return $ Placed (Fncall ["wybe","string"] "empty" False []) pos
347+
-- termToExp (StringConst pos [chr] DoubleQuote)
348+
-- = return $ Placed (Fncall ["wybe","string"] "singleton" False
349+
-- [Unplaced (CharValue chr)]) pos
350+
expandArg arg@(ArgString "" WybeString ty) = do
351+
logExpansion "Optimising empty string"
352+
newVarName <- lift freshVarName
353+
let defVar = ArgVar newVarName ty FlowOut Ordinary False
354+
let useVar = ArgVar newVarName ty FlowIn Ordinary False
355+
logExpansion $ " Generated fresh name " ++ show newVarName
356+
callID <- genCallSiteID
357+
let emptyStringProc = ProcSpec ["wybe","string"] "empty" 0 Set.empty
358+
expandPrim (PrimCall callID emptyStringProc Pure [defVar] emptyGlobalFlows) Nothing
359+
logExpansion $ "Empty string variable = " ++ show useVar
360+
return useVar
361+
expandArg arg@(ArgString [ch] WybeString ty) = do
362+
logExpansion $ "Optimising singleton string \"" ++ [ch] ++ "\""
363+
newVarName <- lift freshVarName
364+
let defVar = ArgVar newVarName ty FlowOut Ordinary False
365+
let useVar = ArgVar newVarName ty FlowIn Ordinary False
366+
logExpansion $ " Generated fresh name " ++ show newVarName
367+
callID <- genCallSiteID
368+
let emptyStringProc = ProcSpec ["wybe","string"] "singleton" 0 Set.empty
369+
expandPrim (PrimCall callID emptyStringProc Pure
370+
[ArgChar ch charType, defVar] emptyGlobalFlows) Nothing
371+
logExpansion $ "Singleton string variable = " ++ show useVar
372+
return useVar
335373
expandArg arg@(ArgVar var ty flow ft _) = do
336374
renameAll <- isJust <$> gets inlining
337375
if renameAll

src/Parser.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ typeRep = do
171171
-- | Type declaration body where visibility, constructors, and items are given
172172
typeCtors :: Parser (TypeImpln,[Item])
173173
typeCtors = betweenB Brace $ do
174-
vis <- option Private
174+
vis <- option Private
175175
$ try (visibility <* (ident "constructor" <|> ident "constructors"))
176176
ctors <- TypeCtors vis <$> ctorDecls
177177
items <- option [] (separator *> items)
@@ -260,7 +260,7 @@ procOrFuncItem vis = do
260260
Nothing -> do
261261
body <- embracedTerm >>= parseWith termToBody
262262
return $ ProcDecl vis mods proto' body $ Just pos
263-
263+
264264

265265

266266
-- | Parse an optional series of resource flows
@@ -1171,9 +1171,9 @@ termToExp (Call pos [] "@" flow exps) = do
11711171
exps' <- mapM termToExp exps
11721172
case content <$> exps' of
11731173
[] -> return $ Placed (AnonParamVar Nothing flow) pos
1174-
[IntValue i] | i > 0
1174+
[IntValue i] | i > 0
11751175
-> return $ Placed (AnonParamVar (Just i) flow) pos
1176-
[exp]
1176+
[exp]
11771177
-> return $ Placed (AnonFunc $ head exps') pos
11781178
_ -> syntaxError pos "invalid anonymous parameter/function expression"
11791179
termToExp (Call pos [] "|" ParamIn [exp1,exp2]) = do

src/Snippets.hs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
module Snippets (castFromTo, castTo, withType, intType, intCast,
99
tagType, tagCast, phantomType, stringType, cStringType,
10-
isTypeVar,
10+
charType, isTypeVar,
1111
varSet, varGet, varGetSet,
1212
varSetTyped, varGetTyped, varGetSetTyped,
1313
boolType, boolCast, boolTrue, boolFalse, boolBool,
@@ -84,6 +84,10 @@ stringType = TypeSpec ["wybe"] "string" []
8484
cStringType :: TypeSpec
8585
cStringType = TypeSpec ["wybe"] "c_string" []
8686

87+
-- | The char type, a single character constant
88+
charType :: TypeSpec
89+
charType = TypeSpec ["wybe"] "char" []
90+
8791
-- | Is the given string a type variable name
8892
isTypeVar :: String -> Bool
8993
isTypeVar (alpha:digits) | isUpper alpha && all isDigit digits = True

src/Types.hs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,10 +1219,9 @@ typecheckProcDecl' pdef = do
12191219
typeError $ ReasonUndef name callee $ place pcall
12201220
_ -> shouldnt "typecheckProcDecl'"
12211221
) badCalls
1222-
ifOK pdef $ do
1223-
typecheckCalls calls' [] False
1224-
$ List.filter (isForeign . content) calls
1225-
ifOK pdef $ modeCheckProcDecl pdef
1222+
typecheckCalls calls' [] False
1223+
$ List.filter (isForeign . content) calls
1224+
ifOK pdef $ modeCheckProcDecl pdef
12261225

12271226

12281227
-- | If no type errors have been recorded, execute the enclosed code; otherwise

0 commit comments

Comments
 (0)