Skip to content

Commit

Permalink
Constant variable names as constant patterns
Browse files Browse the repository at this point in the history
This fixes #3005 by allowing constant identifiers that evaluate to
constant literal expressions of suitable type (boxed, integer, real,
string, boolean, enumeration) to be used in a pattern. For boxed
variables, we replace the pattern expression with a shared literal
and perform valueEq on this. This should prove to be fast especially
if referenceEq holds (such as when passing a constant to a function).
  • Loading branch information
sjoelund committed Feb 25, 2016
1 parent 8b8930d commit 457cabf
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 10 deletions.
99 changes: 94 additions & 5 deletions Compiler/FrontEnd/Patternm.mo
Expand Up @@ -244,6 +244,7 @@ algorithm
DAE.Properties prop;
DAE.Const const;
Values.Value val;
SCode.Variability variability;

case (cache,_,Absyn.INTEGER(i),_,_,_)
equation
Expand Down Expand Up @@ -334,7 +335,17 @@ algorithm
(cache,pattern) = elabPatternCall(cache,env,Absyn.crefToPath(fcr),fargs,utPath,info,lhs);
then (cache,pattern);

case (cache,_,Absyn.CREF(),ty1,_,_) guard Types.isEnumeration(Types.unboxedType(ty1))
case (cache,_,Absyn.CREF(),ty1,_,_)
guard
Types.isBoxedType(ty1) or
(match Types.unboxedType(ty1)
case DAE.T_ENUMERATION() then true;
case DAE.T_INTEGER() then true;
case DAE.T_REAL() then true;
case DAE.T_STRING() then true;
case DAE.T_BOOL() then true;
else false;
end match)
equation
(cache,elabExp,DAE.PROP(type_=ty2, constFlag=const),_) = Static.elabExp(cache,env,inLhs,false,NONE(),false,Prefix.NOPRE(),info);
et = validPatternType(ty1,ty2,inLhs,info);
Expand All @@ -354,11 +365,15 @@ algorithm
then (cache,pattern);

case (cache,_,Absyn.CREF(Absyn.CREF_IDENT(id,{})),ty2,_,_)
equation
(cache,DAE.TYPES_VAR(ty = ty1, attributes = attr),_,_,_,_) = Lookup.lookupIdent(cache,env,id);
algorithm
(cache,DAE.TYPES_VAR(ty = ty1, attributes = attr as DAE.ATTR(variability=variability)),_,_,_,_) := Lookup.lookupIdent(cache,env,id);
if SCode.isParameterOrConst(variability) then
Error.addSourceMessage(Error.PATTERN_VAR_NOT_VARIABLE, {id, SCodeDump.unparseVariability(variability)}, info);
fail();
end if;
Static.checkAssignmentToInput(inLhs, attr, env, false, info);
et = validPatternType(ty2,ty1,inLhs,info);
pattern = if Types.isFunctionType(ty2) then DAE.PAT_AS_FUNC_PTR(id,DAE.PAT_WILD()) else DAE.PAT_AS(id,et,attr,DAE.PAT_WILD());
et := validPatternType(ty2,ty1,inLhs,info);
pattern := if Types.isFunctionType(ty2) then DAE.PAT_AS_FUNC_PTR(id,DAE.PAT_WILD()) else DAE.PAT_AS(id,et,attr,DAE.PAT_WILD());
then (cache,pattern);

case (cache,_,Absyn.AS(id,_),_,_,_)
Expand Down Expand Up @@ -2311,6 +2326,80 @@ algorithm
end matchcontinue;
end fixCaseReturnTypes2;

public function traverseConstantPatternsHelper<T>
input DAE.Exp inExp;
input T inT;
input FuncExpType func;
output DAE.Exp outExp;
output T outT=inT;
partial function FuncExpType
input DAE.Exp inExp;
input T inTypeT;
output DAE.Exp outExp;
output T outT;
end FuncExpType;
algorithm
outExp := match inExp
local
list<DAE.MatchCase> cases, cases2;
DAE.MatchCase case_;
list<DAE.Pattern> patterns;
case outExp as DAE.MATCHEXPRESSION(cases=cases)
algorithm
cases2 := {};
for c in cases loop
case_ := c;
case_ := match case_
case DAE.CASE()
algorithm
(patterns, outT) := traversePatternList(case_.patterns, function traverseConstantPatternsHelper2(func=func), outT);
if not valueEq(case_.patterns, patterns) then
case_.patterns := patterns;
end if;
then case_;
end match;
cases2 := case_::cases2;
end for;
cases2 := Dangerous.listReverseInPlace(cases2);
if not valueEq(cases,cases2) then
outExp.cases := cases2;
end if;
(outExp,outT) := func(outExp,outT);
then outExp;
else
algorithm
(outExp,outT) := func(inExp,outT);
then outExp;
end match;
end traverseConstantPatternsHelper;

function traverseConstantPatternsHelper2<T>
input DAE.Pattern inPattern;
input T inExtra;
input FuncExpType func;
output DAE.Pattern outPattern;
output T extra=inExtra;
partial function FuncExpType
input DAE.Exp inExp;
input T inTypeT;
output DAE.Exp outExp;
output T outT;
end FuncExpType;
algorithm
outPattern := match inPattern
local
DAE.Exp exp;
case outPattern as DAE.PAT_CONSTANT()
algorithm
(exp, extra) := func(outPattern.exp, extra);
if not referenceEq(outPattern.exp, exp) then
outPattern.exp := exp;
end if;
then outPattern;
else inPattern;
end match;
end traverseConstantPatternsHelper2;

public function traverseCases
replaceable type A subtypeof Any;
input list<DAE.MatchCase> inCases;
Expand Down
2 changes: 0 additions & 2 deletions Compiler/FrontEnd/Static.mo
Expand Up @@ -625,13 +625,11 @@ algorithm
(outCache, args, consts, _, tty, _, slots) := elabTypes(outCache, inEnv, pos_args,
named_args, {tty}, true, true, inImplicit, NOT_EXTERNAL_OBJECT_MODEL_SCOPE(),
NONE(), inPrefix, inInfo);

if not Types.isFunctionPointer(tty) then
(outCache, path) := Inst.makeFullyQualified(outCache, inEnv, path);
(outCache, Util.SUCCESS()) := instantiateDaeFunction(outCache, inEnv,
path, false, NONE(), true);
end if;

tty2 := stripExtraArgsFromType(slots, tty);
tty2 := Types.makeFunctionPolymorphicReference(tty2);
ty := Types.simplifyType(tty2);
Expand Down
5 changes: 4 additions & 1 deletion Compiler/SimCode/SimCodeFunctionUtil.mo
Expand Up @@ -54,6 +54,7 @@ import GC;
import Graph;
import List;
import Mod;
import Patternm;
import SCode;

public
Expand Down Expand Up @@ -1147,7 +1148,9 @@ function findLiteralsHelper
algorithm
exp := inExp;
tpl := inTpl;
(exp, tpl) := Expression.traverseExpBottomUp(exp, replaceLiteralExp, tpl);
(exp, tpl) := Expression.traverseExpBottomUp(exp,
function Patternm.traverseConstantPatternsHelper(func=replaceLiteralExp),
tpl);
(exp, tpl) := Expression.traverseExpTopDown(exp, replaceLiteralArrayExp, tpl);
end findLiteralsHelper;

Expand Down
7 changes: 6 additions & 1 deletion Compiler/Template/CodegenCFunctions.tpl
Expand Up @@ -3800,10 +3800,14 @@ template patternMatch(Pattern pat, Text rhs, Text onPatternFail, Text &varDecls,
case c as SCONST(__) then
let escstr = Util.escapeModelicaStringToCString(c.string)
'if (<%unescapedStringLength(escstr)%> != MMC_STRLEN(<%urhs%>) || strcmp("<%escstr%>", MMC_STRINGDATA(<%urhs%>)) != 0) <%onPatternFail%>;<%\n%>'
case c as SHARED_LITERAL(exp=d as SCONST(__)) then
let escstr = Util.escapeModelicaStringToCString(d.string)
'if (<%unescapedStringLength(escstr)%> != MMC_STRLEN(<%urhs%>) || strcmp(MMC_STRINGDATA(_OMC_LIT<%c.index%>), MMC_STRINGDATA(<%urhs%>)) != 0) <%onPatternFail%>;<%\n%>'
case c as BCONST(__) then 'if (<%boolStrC(c.bool)%> != <%urhs%>) <%onPatternFail%>;<%\n%>'
case c as LIST(valList = {}) then 'if (!listEmpty(<%urhs%>)) <%onPatternFail%>;<%\n%>'
case c as META_OPTION(exp = NONE()) then 'if (!optionNone(<%urhs%>)) <%onPatternFail%>;<%\n%>'
case c as ENUM_LITERAL() then 'if (<%c.index%> != <%urhs%>) <%onPatternFail%>;<%\n%>'
case c as SHARED_LITERAL() then 'if (!valueEq(_OMC_LIT<%c.index%>, <%urhs%>)) <%onPatternFail%>;<%\n%>'
else error(sourceInfo(), 'UNKNOWN_CONSTANT_PATTERN <%printExpStr(p.exp)%>')
%>>>
case p as PAT_SOME(__) then
Expand Down Expand Up @@ -6655,7 +6659,8 @@ template switchIndex(Pattern pattern, Integer extraArg)
::=
match pattern
case PAT_CALL(__) then 'case <%getValueCtor(index)%>'
case PAT_CONSTANT(exp=e as SCONST(__)) then 'case <%stringHashDjb2Mod(e.string,extraArg)%> /* <%e.string%> */'
case PAT_CONSTANT(exp=e as SCONST(__))
case PAT_CONSTANT(exp=SHARED_LITERAL(exp=e as SCONST(__))) then 'case <%stringHashDjb2Mod(e.string,extraArg)%> /* <%e.string%> */'
case PAT_CONSTANT(exp=e as ICONST(__)) then 'case <%e.integer%>'
else 'default'
end switchIndex;
Expand Down
2 changes: 2 additions & 0 deletions Compiler/Util/Error.mo
Expand Up @@ -905,6 +905,8 @@ public constant Message META_ALL_EMPTY = MESSAGE(5036, TRANSLATION(), NOTIFICATI
Util.gettext("All patterns in call were empty: %s."));
public constant Message DUPLICATE_DEFINITION = MESSAGE(5037, TRANSLATION(), ERROR(),
Util.gettext("The same variable is being defined twice: %s."));
public constant Message PATTERN_VAR_NOT_VARIABLE = MESSAGE(5038, TRANSLATION(), ERROR(),
Util.gettext("Identifiers need to point to local or output variables. Variable %s is %s."));

public constant Message COMPILER_ERROR = MESSAGE(5999, TRANSLATION(), ERROR(),
Util.notrans("%s"));
Expand Down
1 change: 1 addition & 0 deletions Compiler/boot/Makefile.common
Expand Up @@ -63,6 +63,7 @@ bootstrap-from-tarball: $(PATCHES)
OPENMODELICA_BACKEND_STUBS=1 $(MAKE) -f $(defaultMakefileTarget) generate-files-in-steps OMC=$(BOOTSTRAP_OMC)
# Patch _main.c to avoid a new tarball
$(PATCH_SOURCES)
echo '#include "Patternm.h"' >> build/SimCodeFunctionUtil_includes.h
# We have not compiled OpenModelicaScriptingAPI.mo yet
touch build/OpenModelicaScriptingAPI.h
$(MAKE) -f $(defaultMakefileTarget) install INCLUDESOURCES=1 OMC=$(BOOTSTRAP_OMC)
Expand Down
2 changes: 1 addition & 1 deletion SimulationRuntime/c/meta/meta_modelica.c
Expand Up @@ -134,7 +134,7 @@ modelica_boolean valueEq(modelica_metatype lhs, modelica_metatype rhs)
return d1 == d2;
}
if (MMC_HDRISSTRING(h_lhs)) {
return 0 == strcmp(MMC_STRINGDATA(lhs),MMC_STRINGDATA(rhs));
return MMC_STRLEN(lhs)==MMC_STRLEN(rhs) && 0 == strcmp(MMC_STRINGDATA(lhs),MMC_STRINGDATA(rhs));
}

numslots = MMC_HDRSLOTS(h_lhs);
Expand Down

0 comments on commit 457cabf

Please sign in to comment.