-
Notifications
You must be signed in to change notification settings - Fork 745
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
Add nontrapping-fptoint lowering pass #7016
base: main
Are you sure you want to change the base?
Changes from 6 commits
be05442
90bd6d5
ea01454
7df947b
f3eff06
9810d17
d1db88e
925d34a
07dd028
ab7431a
d3ae179
0ed5b59
9bbd758
16285bb
47dc98f
c373c13
46aaa06
8c74874
d0f3c87
914def0
c758b5f
02201ef
2854ff3
3ccb64f
573275f
8eaebf6
6f29023
d735093
f6483d1
e7c50cf
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 | ||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,150 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
#include "pass.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
#include "wasm-builder.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
#include "wasm.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <limits> | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
// By default LLVM emits nontrapping float-to-int instructions to implement its | ||||||||||||||||||||||||||||||||||||||||||||||||||||
// fptoui/fptosi conversion instructions. This pass replaces these instructions | ||||||||||||||||||||||||||||||||||||||||||||||||||||
// with code sequences which also implement LLVM's fptoui/fptosi, but which are | ||||||||||||||||||||||||||||||||||||||||||||||||||||
// not semantically equivalent in wasm. This is because out-of-range inputs to | ||||||||||||||||||||||||||||||||||||||||||||||||||||
// these instructions produce poison values. So we need only ensure that there | ||||||||||||||||||||||||||||||||||||||||||||||||||||
// is no trap, but need not ensure any particular result. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
dschuff marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
namespace wasm { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
struct LLVMNonTrappingFPToIntLowering | ||||||||||||||||||||||||||||||||||||||||||||||||||||
: public WalkerPass<PostWalker<LLVMNonTrappingFPToIntLowering>> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
dschuff marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
UnaryOp getReplacementOp(UnaryOp op) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
switch (op) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatSFloat32ToInt32: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return UnaryOp::TruncSFloat32ToInt32; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+35
to
+36
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. Nit: It'd be better to be consistent whether or not we use |
||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatUFloat32ToInt32: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return UnaryOp::TruncUFloat32ToInt32; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatSFloat64ToInt32: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return UnaryOp::TruncSFloat64ToInt32; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatUFloat64ToInt32: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return UnaryOp::TruncUFloat64ToInt32; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatSFloat32ToInt64: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return UnaryOp::TruncSFloat32ToInt64; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatUFloat32ToInt64: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return UnaryOp::TruncUFloat32ToInt64; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatSFloat64ToInt64: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return UnaryOp::TruncSFloat64ToInt64; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatUFloat64ToInt64: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return UnaryOp::TruncUFloat64ToInt64; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
default: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
WASM_UNREACHABLE("Unexpected opcode"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
template<typename From, typename To> void ReplaceSigned(Unary* curr) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
dschuff marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
BinaryOp ltOp; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
UnaryOp absOp; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
switch (curr->op) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatSFloat32ToInt32: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatSFloat32ToInt64: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ltOp = BinaryOp::LtFloat32; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
absOp = UnaryOp::AbsFloat32; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatSFloat64ToInt32: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatSFloat64ToInt64: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ltOp = BinaryOp::LtFloat64; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
absOp = UnaryOp::AbsFloat64; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
default: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
WASM_UNREACHABLE("Unexpected opcode"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
Builder builder(*getModule()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
replaceCurrent(builder.makeIf( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
builder.makeBinary( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ltOp, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
builder.makeUnary(absOp, curr->value), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
builder.makeConst(static_cast<From>(std::numeric_limits<To>::max()))), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
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. Separate question: Do you know why LLVM's code adds Also, does this handle when the input value is greater than INT_MIN and less than or equal to INT_MIN+1? INT_MIN's abs value would be greater than INT_MAX but it's still in the int range. (in case of int) |
||||||||||||||||||||||||||||||||||||||||||||||||||||
builder.makeUnary(getReplacementOp(curr->op), curr->value), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
dschuff marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
builder.makeConst(std::numeric_limits<To>::min()))); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
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. Are this value and '0' in And these values don't seem to conform to the real "saturating" spec, because we don't check whether the value overflows or underflows and just use a single substitute value. Is this the reason why this pass is LLVM-specific? Then what is the reason for not making pass a generic conversion pass by implementing the real saturation behavior? (I guess performance?) |
||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
template<typename From, typename To> void ReplaceUnsigned(Unary* curr) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
dschuff marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
BinaryOp ltOp, geOp; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
switch (curr->op) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatUFloat32ToInt32: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ltOp = BinaryOp::LtFloat32; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
geOp = BinaryOp::GeFloat32; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatUFloat64ToInt32: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ltOp = BinaryOp::LtFloat64; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
geOp = BinaryOp::GeFloat64; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatUFloat32ToInt64: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ltOp = BinaryOp::LtFloat32; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
geOp = BinaryOp::GeFloat32; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatUFloat64ToInt64: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ltOp = BinaryOp::LtFloat64; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
geOp = BinaryOp::GeFloat64; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+93
to
+108
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.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
default: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
WASM_UNREACHABLE("Unexpected opcode"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
Builder builder(*getModule()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
replaceCurrent(builder.makeIf( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
builder.makeBinary( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
BinaryOp::AndInt32, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
builder.makeBinary( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ltOp, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
curr->value, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
builder.makeConst(static_cast<From>(std::numeric_limits<To>::max()))), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
builder.makeBinary( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
geOp, curr->value, builder.makeConst(static_cast<From>(0.0)))), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
builder.makeUnary(getReplacementOp(curr->op), curr->value), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
builder.makeConst(static_cast<To>(0)))); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
void visitUnary(Unary* curr) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
switch (curr->op) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatSFloat32ToInt32: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ReplaceSigned<float, int32_t>(curr); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatSFloat64ToInt32: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ReplaceSigned<double, int32_t>(curr); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatSFloat32ToInt64: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ReplaceSigned<float, int64_t>(curr); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatSFloat64ToInt64: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ReplaceSigned<double, int64_t>(curr); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatUFloat32ToInt32: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ReplaceUnsigned<float, uint32_t>(curr); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatUFloat64ToInt32: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ReplaceUnsigned<double, uint32_t>(curr); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatUFloat32ToInt64: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ReplaceUnsigned<float, uint64_t>(curr); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
case TruncSatUFloat64ToInt64: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ReplaceUnsigned<double, uint64_t>(curr); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
default: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
WASM_UNREACHABLE("Unexpected opcode"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
void run(Module* module) override { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!module->features.hasTruncSat()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
Super::run(module); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
module->features.disable(FeatureSet::TruncSat); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
Pass* createLLVMNonTrappingFPToIntLoweringPass() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return new LLVMNonTrappingFPToIntLowering(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
} // namespace wasm |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -330,6 +330,10 @@ void PassRegistry::registerPasses() { | |||||
registerPass("no-partial-inline", | ||||||
"mark functions as no-inline (for partial inlining only)", | ||||||
createNoPartialInlinePass); | ||||||
registerPass("llvm-nontrapping-fptoint-lowering", | ||||||
"lower nontrapping float-to-int operations to wasm mvp and" | ||||||
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.
Suggested change
|
||||||
"disable the nontrapping fptoint feature", | ||||||
createLLVMNonTrappingFPToIntLoweringPass); | ||||||
registerPass("once-reduction", | ||||||
"reduces calls to code that only runs once", | ||||||
createOnceReductionPass); | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -230,6 +230,11 @@ | |||||
;; CHECK-NEXT: --limit-segments attempt to merge segments to fit | ||||||
;; CHECK-NEXT: within web limits | ||||||
;; CHECK-NEXT: | ||||||
;; CHECK-NEXT: --llvm-nontrapping-fptoint-lowering lower nontrapping float-to-int | ||||||
;; CHECK-NEXT: operations to wasm mvp | ||||||
;; CHECK-NEXT: anddisable the nontrapping | ||||||
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.
Suggested change
|
||||||
;; CHECK-NEXT: fptoint feature | ||||||
;; CHECK-NEXT: | ||||||
;; CHECK-NEXT: --local-cse common subexpression elimination | ||||||
;; CHECK-NEXT: inside basic blocks | ||||||
;; CHECK-NEXT: | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -239,6 +239,11 @@ | |||||
;; CHECK-NEXT: --limit-segments attempt to merge segments to fit | ||||||
;; CHECK-NEXT: within web limits | ||||||
;; CHECK-NEXT: | ||||||
;; CHECK-NEXT: --llvm-nontrapping-fptoint-lowering lower nontrapping float-to-int | ||||||
;; CHECK-NEXT: operations to wasm mvp | ||||||
;; CHECK-NEXT: anddisable the nontrapping | ||||||
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.
Suggested change
|
||||||
;; CHECK-NEXT: fptoint feature | ||||||
;; CHECK-NEXT: | ||||||
;; CHECK-NEXT: --local-cse common subexpression elimination | ||||||
;; CHECK-NEXT: inside basic blocks | ||||||
;; CHECK-NEXT: | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -193,6 +193,11 @@ | |||||
;; CHECK-NEXT: --limit-segments attempt to merge segments to fit | ||||||
;; CHECK-NEXT: within web limits | ||||||
;; CHECK-NEXT: | ||||||
;; CHECK-NEXT: --llvm-nontrapping-fptoint-lowering lower nontrapping float-to-int | ||||||
;; CHECK-NEXT: operations to wasm mvp | ||||||
;; CHECK-NEXT: anddisable the nontrapping | ||||||
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.
Suggested change
|
||||||
;; CHECK-NEXT: fptoint feature | ||||||
;; CHECK-NEXT: | ||||||
;; CHECK-NEXT: --local-cse common subexpression elimination | ||||||
;; CHECK-NEXT: inside basic blocks | ||||||
;; CHECK-NEXT: | ||||||
|
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.
We didn't put LLVM in the name of the bulk memory pass IIRC - should we match the two? I don't feel strongly either way.
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.
Ah yeah my original intention was that it should lower just memory.copy and memory.fill (not all of bulk memory) but that part wouldn't need to be LLVM-specific. But then I made it have the same undefined behavior LLVM does, so I think it does make sense to put LLVM in the name. I'll do that in a separate PR.
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.
Done in #7082