-
Notifications
You must be signed in to change notification settings - Fork 769
Add support for compilation-hints proposal #2627
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
base: main
Are you sure you want to change the base?
Changes from all commits
d43cd08
869a125
b0acf37
b872002
6ea1e19
9be7e77
0dd0876
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,8 @@ | |
#include "wabt/intrusive-list.h" | ||
#include "wabt/opcode.h" | ||
|
||
#include <optional> | ||
|
||
namespace wabt { | ||
|
||
struct Module; | ||
|
@@ -702,15 +704,92 @@ class CallIndirectExpr : public ExprMixin<ExprType::CallIndirect> { | |
|
||
class CodeMetadataExpr : public ExprMixin<ExprType::CodeMetadata> { | ||
public: | ||
explicit CodeMetadataExpr(std::string_view name, | ||
std::vector<uint8_t> data, | ||
const Location& loc = Location()) | ||
struct CallTarget { | ||
Var func; | ||
uint32_t frequency; | ||
}; | ||
struct CompilationPriority { | ||
uint32_t compilation_priority; | ||
std::optional<uint32_t> optimization_priority; | ||
}; | ||
struct InstructionFrequency { | ||
uint32_t frequency; | ||
}; | ||
|
||
CodeMetadataExpr(std::string_view name, | ||
std::vector<uint8_t> data, | ||
const Location& loc = Location()) | ||
: ExprMixin<ExprType::CodeMetadata>(loc), name(name), type(Type::Binary) { | ||
new (&hint.data) std::vector<uint8_t>(std::move(data)); | ||
} | ||
|
||
CodeMetadataExpr(std::string_view name, | ||
CompilationPriority compilation_priority, | ||
const Location& loc = Location()) | ||
: ExprMixin<ExprType::CodeMetadata>(loc), | ||
name(std::move(name)), | ||
data(std::move(data)) {} | ||
name(name), | ||
type(Type::CompilationHint) { | ||
new (&hint.compilation_priority) CompilationPriority(compilation_priority); | ||
} | ||
|
||
CodeMetadataExpr(std::string_view name, | ||
InstructionFrequency instruction_frequency, | ||
const Location& loc = Location()) | ||
: ExprMixin<ExprType::CodeMetadata>(loc), | ||
name(name), | ||
type(Type::InstructionFrequency) { | ||
new (&hint.instruction_frequency) | ||
InstructionFrequency(instruction_frequency); | ||
} | ||
|
||
CodeMetadataExpr(std::string_view name, | ||
std::vector<CallTarget> targets, | ||
const Location& loc = Location()) | ||
: ExprMixin<ExprType::CodeMetadata>(loc), | ||
name(name), | ||
type(Type::CallTargets) { | ||
new (&hint.call_targets) std::vector<CallTarget>(std::move(targets)); | ||
} | ||
|
||
~CodeMetadataExpr() override { | ||
switch (type) { | ||
case Type::Binary: | ||
hint.data.~vector(); | ||
break; | ||
case Type::CallTargets: | ||
hint.call_targets.~vector(); | ||
break; | ||
default: | ||
// CompilationHint and InstructionFrequency do not allocate memory.; | ||
break; | ||
} | ||
} | ||
|
||
bool is_function_annotation() const { return type == Type::CompilationHint; } | ||
|
||
// convert non-binary hints to binary | ||
std::vector<uint8_t> serialize(const Module&) const; | ||
|
||
std::string_view name; | ||
std::vector<uint8_t> data; | ||
|
||
private: | ||
union Hint { | ||
std::vector<uint8_t> data; | ||
CompilationPriority compilation_priority; | ||
InstructionFrequency instruction_frequency{}; | ||
std::vector<CallTarget> call_targets; | ||
Hint() {} | ||
~Hint() {} | ||
Lukasdoe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} hint; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be an anonymous union? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we need to overwrite the constructor, we need to name the union, afaik. But please correct me if there's a way to define a destructor for an anonymous union in C++. |
||
|
||
enum class Type { | ||
Binary, | ||
CompilationHint, | ||
InstructionFrequency, | ||
CallTargets | ||
}; | ||
|
||
Type type; | ||
}; | ||
|
||
class ReturnCallIndirectExpr : public ExprMixin<ExprType::ReturnCallIndirect> { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you just do
hint.instruction_frequency = instruction_frequency
here instead of the placement new?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since
hint.instruction_frequency
is not a valid C++ object, we're not allowed to use its assignment copy operator. In practice, using it should work as expected, but it is still undefined behavior nevertheless (afaik). That's why I opted for just writing over it, which should definitely be safe.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain why more? Why can't we using the assignment operator here? Surely the LHS doesn't matter here since its being clobbered by the RHS.
Does the compiler complain if you do
hint.instruction_frequency = instruction_frequency
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While the compiler does not catch the undefined behavior, ASAN does:
When using the assignment operator of the LHS, its implementation (in this case of std::vector) wrongfully assumes a valid object state of the LHS and, therefore, accesses uninitialized memory. That's why we're only allowed to call the assignment operator on objects in a proper state, which the LHS is not. Therefore, we use the placement new operator to fully overwrite the memory associated with the (non-existent) LHS object.