}
}
// Is e an application of a saturated constructor?
ConstructorOpTuple constructorOpTuple = ConstructorOpTuple.isConstructorOp(e, false);
if (constructorOpTuple != null) {
DataConstructor dc = constructorOpTuple.getDataConstructor ();
boolean[] fieldStrictness = new boolean [dc.getArity()];
boolean dcHasStrictFields = false;
for (int i = 0; i < dc.getArity(); ++i) {
fieldStrictness[i] = dc.isArgStrict(i);
if (fieldStrictness[i]) {
dcHasStrictFields = true;
}
}
// If there are no strict arguments we can simply create an instance of the DC class.
// The simplest way to do this is to treat this DC application as if it were in a strict context.
if (!dcHasStrictFields) {
return true;
} else {
// If all strict arguments are already evaluated, or we consider them safe to evaluate (i.e. cheap and
// with no side effects) we can treat this as strict.
boolean allOK = true;
for (int i = 0; i < dc.getArity(); ++i) {
if (dc.getArgStrictness()[i] && !canIgnoreLaziness(constructorOpTuple.getArgument(i), env)) {
allOK = false;
break;
}
}
if (allOK) {
return true;
}
}
}
// We can shortcut a basic op if it is marked as allowed to
// be eagerly evaluated and all arguments can all be shortcut.
// Also if the op is Prelude.eager we can shortcut.
BasicOpTuple basicOpExpressions = BasicOpTuple.isBasicOp(e);
if (basicOpExpressions != null) {
if (basicOpExpressions.getPrimitiveOp() == PrimOps.PRIMOP_EAGER) {
return true;
}
QualifiedName opName = basicOpExpressions.getName();
MachineFunction mf = currentModule.getFunction(opName);
if (mf == null) {
return false;
}
if (mf.canFunctionBeEagerlyEvaluated()) {
int nArgs = basicOpExpressions.getNArguments();
int nWHNFArgs = 0;
for (int i = 0; i < nArgs; ++i) {
Expression eArg = basicOpExpressions.getArgument(i);
if (canIgnoreLaziness(eArg, env)) {
nWHNFArgs++;
}
}
if (nArgs == nWHNFArgs) {
// All the args are in WHNF so ideally we can ignore laziness for
// this primitive operation. However, there are some primitive
// ops where an additional condition, that the second argument is
// known to not be zero, is required.
String unqualifiedOpName = opName.getUnqualifiedName();
if (opName.getModuleName().equals(CAL_Prelude.MODULE_NAME) &&
(unqualifiedOpName.equals("divideLong") ||
unqualifiedOpName.equals("remainderLong") ||
unqualifiedOpName.equals("divideInt") ||
unqualifiedOpName.equals("remainderInt") ||
unqualifiedOpName.equals("divideShort") ||
unqualifiedOpName.equals("remainderShort") ||
unqualifiedOpName.equals("divideByte") ||
unqualifiedOpName.equals("remainderByte"))) {
// Check that the second argument is a non zero literal.
Expression arg = basicOpExpressions.getArgument(1);
if (arg.asLiteral() != null) {
if (unqualifiedOpName.equals("divideLong") || unqualifiedOpName.equals("remainderLong")) {
Long l = (Long)arg.asLiteral().getLiteral();
return l.longValue() != 0;
} else if (unqualifiedOpName.equals("divideInt") || unqualifiedOpName.equals("remainderInt")) {
Integer i = (Integer)arg.asLiteral().getLiteral();
return i.intValue() != 0;
} else if (unqualifiedOpName.equals("divideShort") || unqualifiedOpName.equals("remainderShort")) {
Short shortValue = (Short)arg.asLiteral().getLiteral();
return shortValue.shortValue() != 0;
} else if (unqualifiedOpName.equals("divideByte") || unqualifiedOpName.equals("remainderByte")) {
Byte byteValue = (Byte)arg.asLiteral().getLiteral();
return byteValue.byteValue() != 0;
} else {
throw new IllegalStateException();
}
} else {
return false;
}
} else {
return true;
}
} else {
return false;
}
}
}
basicOpExpressions = BasicOpTuple.isAndOr (e);
if (basicOpExpressions != null) {
// Code a basic operation
int nArgs = basicOpExpressions.getNArguments ();
int nWHNFArgs = 0;
for (int i = 0; i < nArgs; ++i) {
Expression eArg = basicOpExpressions.getArgument(i);
if (canIgnoreLaziness(eArg, env)) {
nWHNFArgs++;
}
}
if (nArgs == nWHNFArgs) {
return true;
}
}
// If e is a fully saturated application of a function tagged for optimization and
// all the arguments are in WHNF or can have laziness ignored we can
// ignore laziness for the application.
if (e.asAppl() != null) {
Expression[] chain = appChain(e.asAppl());
if (chain[0].asVar() != null) {
// Get the supercombinator on the left end of the chain.
Expression.Var scVar = chain[0].asVar();
if (scVar != null) {
// Check if this supercombinator is one we should try to optimize.
MachineFunction mf = currentModule.getFunction(scVar.getName());
if (mf != null && mf.canFunctionBeEagerlyEvaluated()) {
// Now determine the arity of the SC.
int calledArity = mf.getArity();
// Check to see if we can ignore laziness for all the arguments.
if (chain.length - 1 == calledArity) {
int nWHNFArgs = 0;
for (int i = 0; i < calledArity; ++i) {
if (canIgnoreLaziness(chain[i+1], env)) {
nWHNFArgs++;
}
}
if (nWHNFArgs == calledArity) {
return true;
}
}
}
}
}
}
// Is e an application of a zero arity constructor.
if (ConstructorOpTuple.isConstructorOp(e, true) != null) {
ConstructorOpTuple constructorOpExpressions = ConstructorOpTuple.isConstructorOp(e, false);
DataConstructor dc = constructorOpExpressions.getDataConstructor ();
if (dc.getArity() == 0){
return true;
}
}