Skip to content

[SIL] Allow specify_test instructions to take value literals. #68702

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions include/swift/SIL/ParseTestSpecification.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,15 @@ struct UnparsedSpecification {
/// (@{instruction|block|function}) can be parsed in terms of this
/// anchor.
SILInstruction *context;
/// Map from names used in the specification to the corresponding SILValues.
llvm::StringMap<SILValue> values;
};

/// Populates the array \p components with the elements of \p
/// specificationString.
void getTestSpecificationComponents(StringRef specificationString,
SmallVectorImpl<StringRef> &components);

/// Finds and deletes each test_specification instruction in \p function and
/// appends its string payload to the provided vector.
void getTestSpecifications(
Expand Down
4 changes: 4 additions & 0 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/ilist.h"
#include "llvm/ADT/ilist_node.h"
#include "llvm/Support/TrailingObjects.h"
Expand Down Expand Up @@ -5162,6 +5163,7 @@ class TestSpecificationInst final
friend TrailingObjects;
friend SILBuilder;

llvm::StringMap<SILValue> values;
unsigned ArgumentsSpecificationLength;

TestSpecificationInst(SILDebugLocation Loc,
Expand All @@ -5173,6 +5175,8 @@ class TestSpecificationInst final
create(SILDebugLocation Loc, StringRef argumentsSpecification, SILModule &M);

public:
void setValueForName(StringRef name, SILValue value) { values[name] = value; }
llvm::StringMap<SILValue> const &getValues() { return values; }
StringRef getArgumentsSpecification() const {
return StringRef(getTrailingObjects<char>(), ArgumentsSpecificationLength);
}
Expand Down
43 changes: 42 additions & 1 deletion lib/SIL/Parser/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "swift/SIL/AbstractionPattern.h"
#include "swift/SIL/InstructionUtils.h"
#include "swift/SIL/OwnershipUtils.h"
#include "swift/SIL/ParseTestSpecification.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILDebugScope.h"
Expand Down Expand Up @@ -187,6 +188,8 @@ namespace swift {

/// Data structures used to perform name lookup for local values.
llvm::StringMap<ValueBase*> LocalValues;
llvm::StringMap<llvm::SmallVector<TestSpecificationInst *>>
TestSpecsWithRefs;
llvm::StringMap<SourceLoc> ForwardRefLocalValues;

Type performTypeResolution(TypeRepr *TyR, bool IsSILType,
Expand Down Expand Up @@ -799,6 +802,12 @@ void SILParser::setLocalValue(ValueBase *Value, StringRef Name,
Value->getType().getRawASTType());
HadError = true;
} else {
if (TestSpecsWithRefs.find(Name) != TestSpecsWithRefs.end()) {
for (auto *tsi : TestSpecsWithRefs[Name]) {
tsi->setValueForName(Name, Value);
}
}

// Forward references only live here if they have a single result.
Entry->replaceAllUsesWith(Value);
::delete cast<PlaceholderValue>(Entry);
Expand All @@ -807,6 +816,12 @@ void SILParser::setLocalValue(ValueBase *Value, StringRef Name,
return;
}

if (TestSpecsWithRefs.find(Name) != TestSpecsWithRefs.end()) {
for (auto *tsi : TestSpecsWithRefs[Name]) {
tsi->setValueForName(Name, Value);
}
}

// Otherwise, just store it in our map.
Entry = Value;
}
Expand Down Expand Up @@ -3770,7 +3785,33 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
auto ArgumentsSpecification =
P.Tok.getText().drop_front(numQuotes).drop_back(numQuotes).trim();
P.consumeToken(tok::string_literal);
ResultVal = B.createTestSpecificationInst(InstLoc, ArgumentsSpecification);
auto *tsi = B.createTestSpecificationInst(InstLoc, ArgumentsSpecification);
SmallVector<StringRef, 4> components;
test::getTestSpecificationComponents(ArgumentsSpecification, components);
for (auto component : components) {
auto offset = 0;
size_t nameStart = StringRef::npos;
while ((nameStart = component.find_if([](char c) { return c == '%'; },
offset)) != StringRef::npos) {
auto nameEnd = component.find_if_not(
[](char c) { return clang::isAsciiIdentifierContinue(c); },
nameStart + 1);
if (nameEnd == StringRef::npos)
nameEnd = component.size();
auto name = component.substr(nameStart, nameEnd);
component = component.drop_front(nameEnd);
if (nameStart + 1 == nameEnd) {
continue;
}
auto *&entry = LocalValues[name];
if (entry) {
tsi->setValueForName(name, entry);
} else {
TestSpecsWithRefs[name].push_back(tsi);
}
}
}
ResultVal = tsi;
break;
}

Expand Down
70 changes: 58 additions & 12 deletions lib/SIL/Parser/ParseTestSpecification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,16 @@ class ParseArgumentSpecification {
ParseTestSpecification &outer;
StringRef specification;
SILInstruction *context;
llvm::StringMap<SILValue> values;

SILValue getTraceValue(unsigned index, SILFunction *function);

public:
ParseArgumentSpecification(ParseTestSpecification &outer,
StringRef specification, SILInstruction *context)
: outer(outer), specification(specification), context(context) {}
StringRef specification, SILInstruction *context,
llvm::StringMap<SILValue> values)
: outer(outer), specification(specification), context(context),
values(values) {}

Argument parse() {
auto argument = parseArgument();
Expand Down Expand Up @@ -501,6 +504,38 @@ class ParseArgumentSpecification {
llvm_unreachable("unhandled suffix after 'function'!?");
}

SILValue parseValueComponent() {
if (!peekPrefix("%"))
return SILValue();
auto nameEnd = specification.find_if_not(
[](char c) { return clang::isAsciiIdentifierContinue(c); }, 1);
if (nameEnd == StringRef::npos)
nameEnd = specification.size();
auto name = specification.take_front(nameEnd);
specification = specification.drop_front(nameEnd);
if (!empty() && !peekPrefix(".")) {
llvm::errs() << specification << "\n";
llvm::report_fatal_error("bad suffix on value!?");
}
auto value = values[name];
if (!value) {
llvm::errs() << "unknown value '" << name << "'\n"
<< "have the following name->value pairs:\n";
for (auto &pair : values) {
llvm::errs() << pair.getKey() << "->" << pair.getValue() << "\n";
}
llvm::report_fatal_error("unknown value!?");
}
return value;
}

llvm::Optional<Argument> parseValueReference() {
auto value = parseValueComponent();
if (!value)
return llvm::None;
return ValueArgument{value};
}

llvm::Optional<Argument> parseReference() {
if (!consumePrefix("@"))
return llvm::None;
Expand All @@ -525,6 +560,8 @@ class ParseArgumentSpecification {
return *arg;
if (auto arg = parseUInt())
return *arg;
if (auto arg = parseValueReference())
return *arg;
if (auto arg = parseReference())
return *arg;
// Parse strings last--everything parses as a string.
Expand Down Expand Up @@ -563,15 +600,10 @@ class ParseTestSpecification {

void parse(UnparsedSpecification const &specification, Arguments &arguments) {
StringRef specificationString = specification.string;
specificationString.split(components, " ");
for (unsigned long index = 0, size = components.size(); index < size;
++index) {
auto componentString = components[index].trim();
if (componentString.empty())
continue;

ParseArgumentSpecification parser(*this, componentString,
specification.context);
getTestSpecificationComponents(specificationString, components);
for (auto componentString : components) {
ParseArgumentSpecification parser(
*this, componentString, specification.context, specification.values);
auto argument = parser.parse();
arguments.storage.push_back(argument);
}
Expand Down Expand Up @@ -627,6 +659,19 @@ void Argument::print(llvm::raw_ostream &os) {

// API

void swift::test::getTestSpecificationComponents(
StringRef specificationString, SmallVectorImpl<StringRef> &components) {
SmallVector<StringRef, 16> rawComponents;
specificationString.split(rawComponents, " ");
for (unsigned long index = 0, size = rawComponents.size(); index < size;
++index) {
auto componentString = rawComponents[index].trim();
if (componentString.empty())
continue;
components.push_back(componentString);
}
}

void swift::test::getTestSpecifications(
SILFunction *function,
SmallVectorImpl<UnparsedSpecification> &specifications) {
Expand All @@ -635,7 +680,8 @@ void swift::test::getTestSpecifications(
if (auto *tsi = dyn_cast<TestSpecificationInst>(&inst)) {
auto ref = tsi->getArgumentsSpecification();
auto *anchor = findAnchorInstructionAfter(tsi);
specifications.push_back({std::string(ref.begin(), ref.end()), anchor});
specifications.push_back(
{std::string(ref.begin(), ref.end()), anchor, tsi->getValues()});
tsi->eraseFromParent();
}
}
Expand Down
18 changes: 18 additions & 0 deletions test/SILOptimizer/unit_test.sil
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,21 @@ exit:
%retval = tuple ()
return %retval : $()
}

// CHECK-LABEL: begin running test {{.*}} on test_value_literal_parsing: test-specification-parsing with: VVVV, %0, %1, %2, %3
// CHECK: value: %0 = argument of bb0 : $Builtin.Int1
// CHECK: value: %2 = integer_literal $Builtin.Int64, 1
// CHECK: value: %1 = integer_literal $Builtin.Int64, 2
// CHECK: value: %3 = integer_literal $Builtin.Int64, 3
// CHECK-LABEL: end running test {{.*}} on test_value_literal_parsing: test-specification-parsing with: VVVV, %0, %1, %2, %3
sil @test_value_literal_parsing : $(Builtin.Int1) -> () {
entry(%0 : $Builtin.Int1):
%2 = integer_literal $Builtin.Int64, 2
test_specification "test-specification-parsing VVVV %0 %1 %2 %3"
%1 = integer_literal $Builtin.Int64, 1
%3 = integer_literal $Builtin.Int64, 3
apply undef(%2) : $@convention(thin) (Builtin.Int64) -> ()
apply undef(%3) : $@convention(thin) (Builtin.Int64) -> ()
%retval = tuple ()
return %retval : $()
}