From 622e2b82223777c28037680db76457f4554f9809 Mon Sep 17 00:00:00 2001 From: Alastair Donaldson Date: Fri, 26 Oct 2018 14:06:29 +0100 Subject: [PATCH] Fix generator (#86) * Fixed some problems related to the handling of structs in the generator. --- .../com/graphicsfuzz/common/typing/Scope.java | 37 +++++++++ .../common/typing/ScopeTreeBuilder.java | 4 +- .../common/util/StripUnusedGlobals.java | 37 ++++++++- .../common/util/StripUnusedGlobalsTest.java | 18 +++-- .../graphicsfuzz/generator/fuzzer/Fuzzer.java | 13 +++ .../graphicsfuzz/generator/tool/Generate.java | 10 +++ .../transformation/donation/DonateCode.java | 24 ++++-- .../donation/DonateDeadCode.java | 10 ++- .../donation/DonateLiveCode.java | 2 +- .../donation/DonationContext.java | 15 +++- .../donation/DonationContexts.java | 14 +++- .../injection/AvailableStructsCollector.java | 53 +++++++++++++ .../injection/FreeVariablesCollector.java | 5 +- .../generator/fuzzer/FuzzerTest.java | 79 +++++++++++++++++++ .../donation/DonateLiveCodeTest.java | 4 +- ...tructifiedFieldReductionOpportunities.java | 5 +- ...moveStructFieldReductionOpportunities.java | 5 +- .../tester/GeneratorUnitTest.java | 6 ++ 18 files changed, 308 insertions(+), 33 deletions(-) create mode 100644 generator/src/main/java/com/graphicsfuzz/generator/transformation/injection/AvailableStructsCollector.java create mode 100644 generator/src/test/java/com/graphicsfuzz/generator/fuzzer/FuzzerTest.java diff --git a/ast/src/main/java/com/graphicsfuzz/common/typing/Scope.java b/ast/src/main/java/com/graphicsfuzz/common/typing/Scope.java index 4bd4fb3db..a2da35256 100644 --- a/ast/src/main/java/com/graphicsfuzz/common/typing/Scope.java +++ b/ast/src/main/java/com/graphicsfuzz/common/typing/Scope.java @@ -19,6 +19,7 @@ import com.graphicsfuzz.common.ast.decl.ParameterDecl; import com.graphicsfuzz.common.ast.decl.VariableDeclInfo; import com.graphicsfuzz.common.ast.decl.VariablesDeclaration; +import com.graphicsfuzz.common.ast.type.StructDefinitionType; import com.graphicsfuzz.common.ast.type.Type; import java.util.ArrayList; import java.util.Collections; @@ -31,10 +32,12 @@ public class Scope { private final Map variableMapping; + private final Map structMapping; private final Scope parent; public Scope(Scope parent) { this.variableMapping = new HashMap<>(); + this.structMapping = new HashMap<>(); this.parent = parent; } @@ -50,6 +53,26 @@ public void add(String name, Type type, Optional parameterDecl) { variableMapping.put(name, new ScopeEntry(type, parameterDecl)); } + public void addStructDefinition(StructDefinitionType sdt) { + assert sdt.hasStructNameType(); + structMapping.put(sdt.getStructNameType().getName(), sdt); + } + + /** + * Look in current scope to see whether we have a struct definition type matching the struct name. + * @param structName Name of struct type. + * @return Corresponding struct definition, if found, otherwise null. + */ + public StructDefinitionType lookupStructName(String structName) { + if (structMapping.containsKey(structName)) { + return structMapping.get(structName); + } + if (hasParent()) { + return getParent().lookupStructName(structName); + } + return null; + } + private void checkNameTypeAndParam(String name, Type type, Optional parameterDecl) { if (type == null) { @@ -97,6 +120,17 @@ public List namesOfAllVariablesInScope() { return Collections.unmodifiableList(result); } + public List namesOfAllStructDefinitionsInScope() { + List result = new ArrayList<>(); + Scope scope = this; + while (scope != null) { + result.addAll(scope.structMapping.keySet()); + scope = scope.parent; + } + result.sort(String::compareTo); + return Collections.unmodifiableList(result); + } + public List keys() { List result = new ArrayList<>(); result.addAll(variableMapping.keySet()); @@ -117,6 +151,9 @@ public Scope shallowClone() { for (Entry entry : variableMapping.entrySet()) { result.variableMapping.put(entry.getKey(), entry.getValue()); } + for (Entry entry : structMapping.entrySet()) { + result.structMapping.put(entry.getKey(), entry.getValue()); + } return result; } diff --git a/ast/src/main/java/com/graphicsfuzz/common/typing/ScopeTreeBuilder.java b/ast/src/main/java/com/graphicsfuzz/common/typing/ScopeTreeBuilder.java index e06f06bc8..df60c39af 100644 --- a/ast/src/main/java/com/graphicsfuzz/common/typing/ScopeTreeBuilder.java +++ b/ast/src/main/java/com/graphicsfuzz/common/typing/ScopeTreeBuilder.java @@ -39,7 +39,6 @@ public abstract class ScopeTreeBuilder extends StandardVisitor { - protected final Map structDeclarations; protected Scope currentScope; private Deque enclosingBlocks; private boolean addEncounteredParametersToScope; @@ -47,7 +46,6 @@ public abstract class ScopeTreeBuilder extends StandardVisitor { private List encounteredFunctionPrototypes; protected ScopeTreeBuilder() { - this.structDeclarations = new HashMap<>(); this.currentScope = new Scope(null); this.enclosingBlocks = new LinkedList<>(); this.addEncounteredParametersToScope = false; @@ -59,7 +57,7 @@ protected ScopeTreeBuilder() { public void visitStructDefinitionType(StructDefinitionType structDefinitionType) { super.visitStructDefinitionType(structDefinitionType); if (structDefinitionType.hasStructNameType()) { - structDeclarations.put(structDefinitionType.getStructNameType(), structDefinitionType); + currentScope.addStructDefinition(structDefinitionType); } } diff --git a/common/src/main/java/com/graphicsfuzz/common/util/StripUnusedGlobals.java b/common/src/main/java/com/graphicsfuzz/common/util/StripUnusedGlobals.java index bc3fc8b58..c7a7c3605 100644 --- a/common/src/main/java/com/graphicsfuzz/common/util/StripUnusedGlobals.java +++ b/common/src/main/java/com/graphicsfuzz/common/util/StripUnusedGlobals.java @@ -21,6 +21,9 @@ import com.graphicsfuzz.common.ast.decl.VariableDeclInfo; import com.graphicsfuzz.common.ast.decl.VariablesDeclaration; import com.graphicsfuzz.common.ast.expr.VariableIdentifierExpr; +import com.graphicsfuzz.common.ast.type.StructDefinitionType; +import com.graphicsfuzz.common.ast.type.StructNameType; +import com.graphicsfuzz.common.ast.type.Type; import com.graphicsfuzz.common.typing.ScopeEntry; import com.graphicsfuzz.common.typing.ScopeTreeBuilder; import com.graphicsfuzz.util.Constants; @@ -35,14 +38,35 @@ public static void strip(TranslationUnit tu) { new StripUnusedGlobals(tu); } - private Set unusedGlobals; + private final Set unusedGlobals; + private final Set unusedStructs; private StripUnusedGlobals(TranslationUnit tu) { this.unusedGlobals = new HashSet<>(); + this.unusedStructs = new HashSet<>(); visit(tu); sweep(tu); } + @Override + public void visitVariablesDeclaration(VariablesDeclaration variablesDeclaration) { + if (variablesDeclaration.getBaseType().getWithoutQualifiers() instanceof StructDefinitionType) { + final StructDefinitionType sdt = + (StructDefinitionType) variablesDeclaration.getBaseType().getWithoutQualifiers(); + if (sdt.hasStructNameType()) { + // Initially, assume it is unused + unusedStructs.add(sdt); + } + } + super.visitVariablesDeclaration(variablesDeclaration); + } + + @Override + public void visitStructNameType(StructNameType structNameType) { + super.visitStructNameType(structNameType); + unusedStructs.remove(currentScope.lookupStructName(structNameType.getName())); + } + @Override public void visitVariableDeclInfo(VariableDeclInfo variableDeclInfo) { super.visitVariableDeclInfo(variableDeclInfo); @@ -78,10 +102,19 @@ private void sweep(TranslationUnit tu) { index++; } } - if (variablesDeclaration.getNumDecls() == 0) { + if (variablesDeclaration.getNumDecls() == 0 + && !isUsedStructType(variablesDeclaration.getBaseType())) { tu.removeTopLevelDeclaration(variablesDeclaration); } } } + private boolean isUsedStructType(Type type) { + if (!(type.getWithoutQualifiers() instanceof StructDefinitionType)) { + return false; + } + final StructDefinitionType sdt = (StructDefinitionType) type.getWithoutQualifiers(); + return !unusedStructs.contains(sdt); + } + } diff --git a/common/src/test/java/com/graphicsfuzz/common/util/StripUnusedGlobalsTest.java b/common/src/test/java/com/graphicsfuzz/common/util/StripUnusedGlobalsTest.java index 904132749..5c00747ef 100644 --- a/common/src/test/java/com/graphicsfuzz/common/util/StripUnusedGlobalsTest.java +++ b/common/src/test/java/com/graphicsfuzz/common/util/StripUnusedGlobalsTest.java @@ -16,10 +16,7 @@ package com.graphicsfuzz.common.util; -import static org.junit.Assert.assertEquals; - import com.graphicsfuzz.common.ast.TranslationUnit; -import com.graphicsfuzz.common.tool.PrettyPrinterVisitor; import org.junit.Test; public class StripUnusedGlobalsTest { @@ -55,8 +52,19 @@ public void testStripUnusedGlobals() throws Exception { + "}"; final TranslationUnit tu = ParseHelper.parse(original); StripUnusedGlobals.strip(tu); - assertEquals(PrettyPrinterVisitor.prettyPrintAsString(ParseHelper.parse(expected)), - PrettyPrinterVisitor.prettyPrintAsString(tu)); + CompareAsts.assertEqualAsts(expected, tu); + } + + @Test + public void testDoNotStripStruct() throws Exception { + final String original = "" + + "struct S { int a; };" + + "void main() {" + + " S myS;" + + "}"; + final TranslationUnit tu = ParseHelper.parse(original); + StripUnusedGlobals.strip(tu); + CompareAsts.assertEqualAsts(original, tu); } } \ No newline at end of file diff --git a/generator/src/main/java/com/graphicsfuzz/generator/fuzzer/Fuzzer.java b/generator/src/main/java/com/graphicsfuzz/generator/fuzzer/Fuzzer.java index f445c665d..ef32786ef 100755 --- a/generator/src/main/java/com/graphicsfuzz/generator/fuzzer/Fuzzer.java +++ b/generator/src/main/java/com/graphicsfuzz/generator/fuzzer/Fuzzer.java @@ -27,6 +27,7 @@ import com.graphicsfuzz.common.ast.decl.VariablesDeclaration; import com.graphicsfuzz.common.ast.expr.ArrayConstructorExpr; import com.graphicsfuzz.common.ast.expr.Expr; +import com.graphicsfuzz.common.ast.expr.TypeConstructorExpr; import com.graphicsfuzz.common.ast.stmt.BlockStmt; import com.graphicsfuzz.common.ast.stmt.BreakStmt; import com.graphicsfuzz.common.ast.stmt.ContinueStmt; @@ -184,6 +185,18 @@ private Expr makeExpr(Type targetType, boolean isLValue, boolean constContext, f throw new FuzzedIntoACornerException(); } } + if (targetType instanceof StructNameType) { + final String structName = ((StructNameType) targetType).getName(); + final StructDefinitionType sdt = + fuzzingContext.getCurrentScope().lookupStructName(structName); + if (sdt == null) { + throw new RuntimeException("Could not find a struct named " + structName + " in scope."); + } + assert sdt.getStructNameType().getName().equals(structName); + return new TypeConstructorExpr(structName, sdt.getFieldTypes() + .stream().map(item -> makeExpr(item, false, constContext, depth + 1)) + .collect(Collectors.toList())); + } throw new RuntimeException("Do not yet know how to make expr of type " + targetType.getClass()); } diff --git a/generator/src/main/java/com/graphicsfuzz/generator/tool/Generate.java b/generator/src/main/java/com/graphicsfuzz/generator/tool/Generate.java index 29162af52..755824662 100755 --- a/generator/src/main/java/com/graphicsfuzz/generator/tool/Generate.java +++ b/generator/src/main/java/com/graphicsfuzz/generator/tool/Generate.java @@ -24,6 +24,7 @@ import com.graphicsfuzz.common.ast.type.TypeQualifier; import com.graphicsfuzz.common.glslversion.ShadingLanguageVersion; import com.graphicsfuzz.common.transformreduce.ShaderJob; +import com.graphicsfuzz.common.typing.Typer; import com.graphicsfuzz.common.util.IRandom; import com.graphicsfuzz.common.util.IdGenerator; import com.graphicsfuzz.common.util.ParseTimeoutException; @@ -380,6 +381,7 @@ private static String applyTransformationsMultiPass(GeneratorArguments args, // Keep the size down by stripping unused stuff. StripUnusedFunctions.strip(reference); StripUnusedGlobals.strip(reference); + assert canTypeCheckWithoutFailure(reference, args.getShadingLanguageVersion()); done.add(transformation); if (transformations.isEmpty()) { transformations = done; @@ -389,6 +391,14 @@ private static String applyTransformationsMultiPass(GeneratorArguments args, return result; } + private static boolean canTypeCheckWithoutFailure(TranslationUnit reference, + ShadingLanguageVersion shadingLanguageVersion) { + // Debugging aid: fail early if we end up messing up the translation unit so that type checking + // does not work. + new Typer(reference, shadingLanguageVersion); + return true; + } + private static boolean shaderLargeEnough(TranslationUnit tu, IRandom generator) { final StatsVisitor statsVisitor = new StatsVisitor(tu); diff --git a/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonateCode.java b/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonateCode.java index cd9ccf3f4..3b5ddc144 100755 --- a/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonateCode.java +++ b/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonateCode.java @@ -39,6 +39,7 @@ import com.graphicsfuzz.common.ast.type.TypeQualifier; import com.graphicsfuzz.common.ast.visitors.StandardVisitor; import com.graphicsfuzz.common.glslversion.ShadingLanguageVersion; +import com.graphicsfuzz.common.typing.Scope; import com.graphicsfuzz.common.typing.ScopeTreeBuilder; import com.graphicsfuzz.common.typing.Typer; import com.graphicsfuzz.common.util.IRandom; @@ -284,15 +285,28 @@ Map getGlobalsFromShader(TranslationUnit shader) { }.getGlobalsFromShader(shader); } - final ScalarInitializer getScalarInitializer(IInjectionPoint injectionPoint, Type type, - boolean restrictToConst, IRandom generator, ShadingLanguageVersion shadingLanguageVersion) { - final boolean isConst = type instanceof QualifiedType && ((QualifiedType) type) - .hasQualifier(TypeQualifier.CONST); + final ScalarInitializer getScalarInitializer(IInjectionPoint injectionPoint, + DonationContext donationContext, + Type type, + boolean restrictToConst, + IRandom generator, + ShadingLanguageVersion shadingLanguageVersion) { + final boolean isConst = type.hasQualifier(TypeQualifier.CONST); try { + + // We may need to generate an initializer for a free variable of struct type. The struct + // will be present in the donor but not yet added to the recipient. We thus make a + // temporary scope identical to the scope at the injection point, but with all of the + // structs from the donation context added. + final Scope scopeForFuzzing = injectionPoint.scopeAtInjectionPoint().shallowClone(); + for (StructDefinitionType sdt : donationContext.getAvailableStructs()) { + scopeForFuzzing.addStructDefinition(sdt); + } + return new ScalarInitializer( new OpaqueExpressionGenerator(generator, generationParams, shadingLanguageVersion) .fuzzedConstructor( - new Fuzzer(new FuzzingContext(injectionPoint.scopeAtInjectionPoint()), + new Fuzzer(new FuzzingContext(scopeForFuzzing), shadingLanguageVersion, generator, generationParams) diff --git a/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonateDeadCode.java b/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonateDeadCode.java index 89397edf2..00acad553 100755 --- a/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonateDeadCode.java +++ b/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonateDeadCode.java @@ -95,10 +95,14 @@ Stmt prepareStatementToDonate(IInjectionPoint injectionPoint, DonationContext do String newName = "donor_replacement" + name; substitution.put(name, newName); - final ScalarInitializer initializer = getScalarInitializer(injectionPoint, type, - type instanceof QualifiedType && ((QualifiedType) type) + final ScalarInitializer initializer = getScalarInitializer( + injectionPoint, + donationContext, + type, + type instanceof QualifiedType && ((QualifiedType) type) .hasQualifier(TypeQualifier.CONST), - generator, shadingLanguageVersion); + generator, + shadingLanguageVersion); donatedStmts.add(new DeclarationStmt( new VariablesDeclaration(dropQualifiersThatCannotBeUsedForLocalVariable(type), diff --git a/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonateLiveCode.java b/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonateLiveCode.java index eca48517c..427a5f5f8 100755 --- a/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonateLiveCode.java +++ b/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonateLiveCode.java @@ -73,7 +73,7 @@ Stmt prepareStatementToDonate(IInjectionPoint injectionPoint, if (isLoopLimiter(vars.getKey(), type.getWithoutQualifiers())) { initializer = new ScalarInitializer(new IntConstantExpr("0")); } else { - initializer = getScalarInitializer(injectionPoint, type, true, + initializer = getScalarInitializer(injectionPoint, donationContext, type, true, generator, shadingLanguageVersion); } donatedStmts.add(new DeclarationStmt( diff --git a/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonationContext.java b/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonationContext.java index 00acf85f0..e895b72a6 100644 --- a/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonationContext.java +++ b/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonationContext.java @@ -22,24 +22,29 @@ import com.graphicsfuzz.common.ast.expr.ArrayIndexExpr; import com.graphicsfuzz.common.ast.expr.VariableIdentifierExpr; import com.graphicsfuzz.common.ast.stmt.Stmt; +import com.graphicsfuzz.common.ast.type.StructDefinitionType; import com.graphicsfuzz.common.ast.type.Type; import com.graphicsfuzz.common.ast.visitors.StandardVisitor; import com.graphicsfuzz.common.typing.ScopeTreeBuilder; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; class DonationContext { - private Stmt donorFragment; - private Map freeVariables; - private FunctionDefinition enclosingFunction; + private final Stmt donorFragment; + private final Map freeVariables; + private final List availableStructs; + private final FunctionDefinition enclosingFunction; DonationContext(Stmt donorFragment, Map freeVariables, + List availableStructs, FunctionDefinition enclosingFunction) { this.donorFragment = donorFragment; this.freeVariables = freeVariables; + this.availableStructs = availableStructs; this.enclosingFunction = enclosingFunction; } @@ -51,6 +56,10 @@ Map getFreeVariables() { return Collections.unmodifiableMap(freeVariables); } + List getAvailableStructs() { + return Collections.unmodifiableList(availableStructs); + } + FunctionDefinition getEnclosingFunction() { return enclosingFunction; } diff --git a/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonationContexts.java b/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonationContexts.java index bfb0bde4e..d5af5255f 100644 --- a/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonationContexts.java +++ b/generator/src/main/java/com/graphicsfuzz/generator/transformation/donation/DonationContexts.java @@ -26,6 +26,7 @@ import com.graphicsfuzz.common.ast.stmt.WhileStmt; import com.graphicsfuzz.common.ast.visitors.StandardVisitor; import com.graphicsfuzz.common.util.IRandom; +import com.graphicsfuzz.generator.transformation.injection.AvailableStructsCollector; import com.graphicsfuzz.generator.transformation.injection.FreeVariablesCollector; import java.util.ArrayList; import java.util.HashMap; @@ -92,16 +93,21 @@ public void visitForStmt(ForStmt forStmt) { } DonationContext getDonationContext() { - Stmt donorFragment = donorFragments.get(generator.nextInt(donorFragments.size())); - FreeVariablesCollector collector = new FreeVariablesCollector(donor, donorFragment); - Stmt clonedDonorFragment = donorFragment.clone(); + final Stmt donorFragment = donorFragments.get(generator.nextInt(donorFragments.size())); + final FreeVariablesCollector fvCollector = new FreeVariablesCollector(donor, donorFragment); + final AvailableStructsCollector asCollector = + new AvailableStructsCollector(donor, donorFragment); + + + final Stmt clonedDonorFragment = donorFragment.clone(); if (clonedDonorFragment instanceof BlockStmt) { // If we got the donor fragment from a function body, it may not introduce a new scope. // We ensure that the donor fragment to be used in the // com.graphicsfuzz.generator.transformation.donation context does. ((BlockStmt) clonedDonorFragment).setIntroducesNewScope(true); } - return new DonationContext(clonedDonorFragment, collector.getFreeVariables(), + return new DonationContext(clonedDonorFragment, fvCollector.getFreeVariables(), + asCollector.getStructDefinitionTypes(), enclosingFunction.get(donorFragment)); } diff --git a/generator/src/main/java/com/graphicsfuzz/generator/transformation/injection/AvailableStructsCollector.java b/generator/src/main/java/com/graphicsfuzz/generator/transformation/injection/AvailableStructsCollector.java new file mode 100644 index 000000000..f9476539e --- /dev/null +++ b/generator/src/main/java/com/graphicsfuzz/generator/transformation/injection/AvailableStructsCollector.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 The GraphicsFuzz Project Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.graphicsfuzz.generator.transformation.injection; + +import com.graphicsfuzz.common.ast.IAstNode; +import com.graphicsfuzz.common.ast.TranslationUnit; +import com.graphicsfuzz.common.ast.type.StructDefinitionType; +import com.graphicsfuzz.common.typing.ScopeTreeBuilder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class AvailableStructsCollector extends ScopeTreeBuilder { + + private final List structDefinitionTypes; + private final IAstNode donorFragment; + + public AvailableStructsCollector(TranslationUnit donor, IAstNode donorFragment) { + this.structDefinitionTypes = new ArrayList<>(); + this.donorFragment = donorFragment; + visit(donor); + } + + @Override + public void visit(IAstNode node) { + if (node == donorFragment) { + assert structDefinitionTypes.isEmpty(); + for (String structName : currentScope.namesOfAllStructDefinitionsInScope()) { + structDefinitionTypes.add(currentScope.lookupStructName(structName)); + } + } + super.visit(node); + } + + public List getStructDefinitionTypes() { + return Collections.unmodifiableList(structDefinitionTypes); + } + +} diff --git a/generator/src/main/java/com/graphicsfuzz/generator/transformation/injection/FreeVariablesCollector.java b/generator/src/main/java/com/graphicsfuzz/generator/transformation/injection/FreeVariablesCollector.java index 725f7b21c..1dd5577bf 100644 --- a/generator/src/main/java/com/graphicsfuzz/generator/transformation/injection/FreeVariablesCollector.java +++ b/generator/src/main/java/com/graphicsfuzz/generator/transformation/injection/FreeVariablesCollector.java @@ -20,6 +20,7 @@ import com.graphicsfuzz.common.ast.TranslationUnit; import com.graphicsfuzz.common.ast.expr.VariableIdentifierExpr; import com.graphicsfuzz.common.ast.stmt.Stmt; +import com.graphicsfuzz.common.ast.type.StructDefinitionType; import com.graphicsfuzz.common.ast.type.Type; import com.graphicsfuzz.common.typing.Scope; import com.graphicsfuzz.common.typing.ScopeTreeBuilder; @@ -29,9 +30,9 @@ public class FreeVariablesCollector extends ScopeTreeBuilder { - private Stmt donorFragment; + private final Stmt donorFragment; private Scope enclosingScope; - private Map freeVariables; + private final Map freeVariables; public FreeVariablesCollector(TranslationUnit donor, Stmt donorFragment) { this.donorFragment = donorFragment; diff --git a/generator/src/test/java/com/graphicsfuzz/generator/fuzzer/FuzzerTest.java b/generator/src/test/java/com/graphicsfuzz/generator/fuzzer/FuzzerTest.java new file mode 100644 index 000000000..ec25f8220 --- /dev/null +++ b/generator/src/test/java/com/graphicsfuzz/generator/fuzzer/FuzzerTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2018 The GraphicsFuzz Project Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.graphicsfuzz.generator.fuzzer; + +import com.graphicsfuzz.common.ast.TranslationUnit; +import com.graphicsfuzz.common.ast.expr.Expr; +import com.graphicsfuzz.common.ast.expr.TypeConstructorExpr; +import com.graphicsfuzz.common.ast.expr.VariableIdentifierExpr; +import com.graphicsfuzz.common.ast.type.StructNameType; +import com.graphicsfuzz.common.ast.visitors.StandardVisitor; +import com.graphicsfuzz.common.glslversion.ShadingLanguageVersion; +import com.graphicsfuzz.common.typing.ScopeTreeBuilder; +import com.graphicsfuzz.common.util.ParseHelper; +import com.graphicsfuzz.common.util.ShaderKind; +import com.graphicsfuzz.common.util.ZeroCannedRandom; +import com.graphicsfuzz.generator.util.GenerationParams; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class FuzzerTest { + + @Test + public void testStructExprFuzzing() throws Exception { + + final String shader = "" + + "struct A {" + + " int f1;" + + " int f2;" + + "};\n" + + "struct B {" + + " A f1;" + + " A f2;" + + "};" + + "void main() {" + + " int doitWhenYouReachMyUse;" + + " doitWhenYouReachMyUse;" + + "}"; + + TranslationUnit tu = ParseHelper.parse(shader); + + new ScopeTreeBuilder() { + @Override + public void visitVariableIdentifierExpr(VariableIdentifierExpr variableIdentifierExpr) { + super.visitVariableIdentifierExpr(variableIdentifierExpr); + if (variableIdentifierExpr.getName().equals("doitWhenYouReachMyUse")) { + Expr expr = new Fuzzer(new FuzzingContext(currentScope), ShadingLanguageVersion.ESSL_100, + new ZeroCannedRandom(), GenerationParams.normal(ShaderKind.FRAGMENT), "prefix") + .fuzzExpr(new StructNameType("B"), false, false, 0); + assertTrue(expr instanceof TypeConstructorExpr); + // Sanity check a few things about the result + final TypeConstructorExpr outer = (TypeConstructorExpr) expr; + assertTrue(outer.getTypename().equals("B")); + assertTrue(outer.getArg(0) instanceof TypeConstructorExpr); + assertTrue(outer.getArg(1) instanceof TypeConstructorExpr); + final TypeConstructorExpr inner0 = (TypeConstructorExpr) outer.getArg(0); + final TypeConstructorExpr inner1 = (TypeConstructorExpr) outer.getArg(1); + assertTrue(inner0.getTypename().equals("A")); + assertTrue(inner1.getTypename().equals("A")); + } + } + }.visit(tu); + } + +} \ No newline at end of file diff --git a/generator/src/test/java/com/graphicsfuzz/generator/transformation/donation/DonateLiveCodeTest.java b/generator/src/test/java/com/graphicsfuzz/generator/transformation/donation/DonateLiveCodeTest.java index 1a7200be4..78f35ea18 100755 --- a/generator/src/test/java/com/graphicsfuzz/generator/transformation/donation/DonateLiveCodeTest.java +++ b/generator/src/test/java/com/graphicsfuzz/generator/transformation/donation/DonateLiveCodeTest.java @@ -65,7 +65,8 @@ public void prepareStatementToDonate() throws Exception { new DonateLiveCode(IRandom::nextBoolean, testFolder.getRoot(), GenerationParams.normal(ShaderKind.FRAGMENT), false); - DonationContext dc = new DonationContext(DiscardStmt.INSTANCE, new HashMap<>(), null); + DonationContext dc = new DonationContext(DiscardStmt.INSTANCE, new HashMap<>(), + new ArrayList<>(), null); Stmt donated = dlc.prepareStatementToDonate(null, dc, TransformationProbabilities.DEFAULT_PROBABILITIES, new RandomWrapper(0), ShadingLanguageVersion.ESSL_100); @@ -158,6 +159,7 @@ BlockInjectionPoint getBlockInjectionPoint(TranslationUnit tu) { new DonationContext( declarationStmt, freeVariables, + new ArrayList<>(), new FunctionDefinition(new FunctionPrototype("foo", VoidType.VOID, new ArrayList()), null)), TransformationProbabilities.onlyLiveCodeAlwaysSubstitute(), diff --git a/reducer/src/main/java/com/graphicsfuzz/reducer/reductionopportunities/InlineStructifiedFieldReductionOpportunities.java b/reducer/src/main/java/com/graphicsfuzz/reducer/reductionopportunities/InlineStructifiedFieldReductionOpportunities.java index 7a2695e25..04e39cd53 100755 --- a/reducer/src/main/java/com/graphicsfuzz/reducer/reductionopportunities/InlineStructifiedFieldReductionOpportunities.java +++ b/reducer/src/main/java/com/graphicsfuzz/reducer/reductionopportunities/InlineStructifiedFieldReductionOpportunities.java @@ -70,7 +70,8 @@ public void visitDeclarationStmt(DeclarationStmt declarationStmt) { public void findInliningOpportunities(StructNameType structType) { assert structType.getName().startsWith(Constants.STRUCTIFICATION_STRUCT_PREFIX); - final StructDefinitionType structDefinitionType = structDeclarations.get(structType); + final StructDefinitionType structDefinitionType = + currentScope.lookupStructName(structType.getName()); for (String f : structDefinitionType.getFieldNames()) { if (!f.startsWith(Constants.STRUCTIFICATION_FIELD_PREFIX)) { continue; @@ -80,7 +81,7 @@ public void findInliningOpportunities(StructNameType structType) { final StructNameType innerStructType = (StructNameType) structDefinitionType.getFieldType(f).getWithoutQualifiers(); opportunities.add(new InlineStructifiedFieldReductionOpportunity( - structDefinitionType, structDeclarations.get(innerStructType), f, tu, + structDefinitionType, currentScope.lookupStructName(innerStructType.getName()), f, tu, getVistitationDepth())); findInliningOpportunities(innerStructType); } diff --git a/reducer/src/main/java/com/graphicsfuzz/reducer/reductionopportunities/RemoveStructFieldReductionOpportunities.java b/reducer/src/main/java/com/graphicsfuzz/reducer/reductionopportunities/RemoveStructFieldReductionOpportunities.java index 5b22abb28..11d2ee2cc 100755 --- a/reducer/src/main/java/com/graphicsfuzz/reducer/reductionopportunities/RemoveStructFieldReductionOpportunities.java +++ b/reducer/src/main/java/com/graphicsfuzz/reducer/reductionopportunities/RemoveStructFieldReductionOpportunities.java @@ -75,7 +75,8 @@ private void getOpportunitiesForStruct(StructNameType structType, return; } - final StructDefinitionType structDefinitionType = structDeclarations.get(structType); + final StructDefinitionType structDefinitionType = + currentScope.lookupStructName(structType.getName()); for (String field : structDefinitionType.getFieldNames()) { if (!reachesOriginalVariable(structDefinitionType, field) @@ -108,7 +109,7 @@ private boolean reachesOriginalVariable(StructDefinitionType structDefinitionTyp final StructNameType fieldType = (StructNameType) structDefinitionType.getFieldType(field).getWithoutQualifiers(); final StructDefinitionType nestedStruct = - structDeclarations.get(fieldType); + currentScope.lookupStructName(fieldType.getName()); return nestedStruct.getFieldNames().stream() .anyMatch(item -> reachesOriginalVariable(nestedStruct, item)); } diff --git a/tester/src/test/java/com/graphicsfuzz/tester/GeneratorUnitTest.java b/tester/src/test/java/com/graphicsfuzz/tester/GeneratorUnitTest.java index 218ede884..deafb1640 100755 --- a/tester/src/test/java/com/graphicsfuzz/tester/GeneratorUnitTest.java +++ b/tester/src/test/java/com/graphicsfuzz/tester/GeneratorUnitTest.java @@ -104,6 +104,12 @@ public void testRenderBlackImage() throws Exception { } } + @Test + public void testStructify() throws Exception { + testTransformationMultiVersions(() -> new Structification(), TransformationProbabilities.DEFAULT_PROBABILITIES, + "structs.frag"); + } + @Test public void testDeadJumps() throws Exception { testTransformationMultiVersions(() -> new AddJumpStmts(), TransformationProbabilities.onlyAddJumps(),