[wasm][multi-return][arm64] Pad parameter slots
Stack parameters on arm64 require padding. Since the stack areas for parameters and returns should not overlap, we have to pad the parameters already during the construction of the CallDescriptor so that we can set the correct stack offset for returns. R=mstarzinger@chromium.org Bug: chromium:838098 Change-Id: I23389dc35037054b750e61ea6b1bfdfc4c5bc868 Reviewed-on: https://chromium-review.googlesource.com/1150178 Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Commit-Queue: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#54716}
This commit is contained in:
parent
57253243fc
commit
a2a3817594
@ -5255,7 +5255,11 @@ CallDescriptor* GetWasmCallDescriptor(
|
||||
// Add return location(s).
|
||||
LinkageLocationAllocator rets(wasm::kGpReturnRegisters,
|
||||
wasm::kFpReturnRegisters);
|
||||
rets.SetStackOffset(params.NumStackSlots());
|
||||
|
||||
int parameter_slots = params.NumStackSlots();
|
||||
if (kPadArguments) parameter_slots = RoundUp(parameter_slots, 2);
|
||||
|
||||
rets.SetStackOffset(parameter_slots);
|
||||
|
||||
const int return_count = static_cast<int>(locations.return_count_);
|
||||
for (int i = 0; i < return_count; i++) {
|
||||
@ -5276,19 +5280,19 @@ CallDescriptor* GetWasmCallDescriptor(
|
||||
|
||||
CallDescriptor::Flags flags =
|
||||
use_retpoline ? CallDescriptor::kRetpoline : CallDescriptor::kNoFlags;
|
||||
return new (zone) CallDescriptor( // --
|
||||
kind, // kind
|
||||
target_type, // target MachineType
|
||||
target_loc, // target location
|
||||
locations.Build(), // location_sig
|
||||
params.NumStackSlots(), // stack_parameter_count
|
||||
compiler::Operator::kNoProperties, // properties
|
||||
kCalleeSaveRegisters, // callee-saved registers
|
||||
kCalleeSaveFPRegisters, // callee-saved fp regs
|
||||
flags, // flags
|
||||
"wasm-call", // debug name
|
||||
0, // allocatable registers
|
||||
rets.NumStackSlots() - params.NumStackSlots()); // stack_return_count
|
||||
return new (zone) CallDescriptor( // --
|
||||
kind, // kind
|
||||
target_type, // target MachineType
|
||||
target_loc, // target location
|
||||
locations.Build(), // location_sig
|
||||
parameter_slots, // stack_parameter_count
|
||||
compiler::Operator::kNoProperties, // properties
|
||||
kCalleeSaveRegisters, // callee-saved registers
|
||||
kCalleeSaveFPRegisters, // callee-saved fp regs
|
||||
flags, // flags
|
||||
"wasm-call", // debug name
|
||||
0, // allocatable registers
|
||||
rets.NumStackSlots() - parameter_slots); // stack_return_count
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -135,87 +135,98 @@ std::unique_ptr<wasm::NativeModule> AllocateNativeModule(Isolate* isolate,
|
||||
|
||||
void TestReturnMultipleValues(MachineType type) {
|
||||
const int kMaxCount = 20;
|
||||
for (int count = 0; count < kMaxCount; ++count) {
|
||||
printf("\n==== type = %s, count = %d ====\n\n\n",
|
||||
MachineReprToString(type.representation()), count);
|
||||
v8::internal::AccountingAllocator allocator;
|
||||
Zone zone(&allocator, ZONE_NAME);
|
||||
CallDescriptor* desc = CreateCallDescriptor(&zone, count, 2, type);
|
||||
HandleAndZoneScope handles;
|
||||
RawMachineAssembler m(handles.main_isolate(),
|
||||
new (handles.main_zone()) Graph(handles.main_zone()),
|
||||
desc, MachineType::PointerRepresentation(),
|
||||
InstructionSelector::SupportedMachineOperatorFlags());
|
||||
const int kMaxParamCount = 9;
|
||||
// Use 9 parameters as a regression test or https://crbug.com/838098.
|
||||
for (int param_count : {2, kMaxParamCount}) {
|
||||
for (int count = 0; count < kMaxCount; ++count) {
|
||||
printf("\n==== type = %s, count = %d ====\n\n\n",
|
||||
MachineReprToString(type.representation()), count);
|
||||
v8::internal::AccountingAllocator allocator;
|
||||
Zone zone(&allocator, ZONE_NAME);
|
||||
CallDescriptor* desc =
|
||||
CreateCallDescriptor(&zone, count, param_count, type);
|
||||
HandleAndZoneScope handles;
|
||||
RawMachineAssembler m(
|
||||
handles.main_isolate(),
|
||||
new (handles.main_zone()) Graph(handles.main_zone()), desc,
|
||||
MachineType::PointerRepresentation(),
|
||||
InstructionSelector::SupportedMachineOperatorFlags());
|
||||
|
||||
// m.Parameter(0) is the WasmContext.
|
||||
Node* p0 = m.Parameter(1);
|
||||
Node* p1 = m.Parameter(2);
|
||||
typedef Node* Node_ptr;
|
||||
std::unique_ptr<Node_ptr[]> returns(new Node_ptr[count]);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (i % 3 == 0) returns[i] = Add(m, type, p0, p1);
|
||||
if (i % 3 == 1) returns[i] = Sub(m, type, p0, p1);
|
||||
if (i % 3 == 2) returns[i] = Mul(m, type, p0, p1);
|
||||
}
|
||||
m.Return(count, returns.get());
|
||||
// m.Parameter(0) is the WasmContext.
|
||||
Node* p0 = m.Parameter(1);
|
||||
Node* p1 = m.Parameter(2);
|
||||
typedef Node* Node_ptr;
|
||||
std::unique_ptr<Node_ptr[]> returns(new Node_ptr[count]);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (i % 3 == 0) returns[i] = Add(m, type, p0, p1);
|
||||
if (i % 3 == 1) returns[i] = Sub(m, type, p0, p1);
|
||||
if (i % 3 == 2) returns[i] = Mul(m, type, p0, p1);
|
||||
}
|
||||
m.Return(count, returns.get());
|
||||
|
||||
OptimizedCompilationInfo info(ArrayVector("testing"), handles.main_zone(),
|
||||
Code::WASM_FUNCTION);
|
||||
Handle<Code> code =
|
||||
Pipeline::GenerateCodeForTesting(
|
||||
&info, handles.main_isolate(), desc, m.graph(),
|
||||
AssemblerOptions::Default(handles.main_isolate()), m.Export())
|
||||
.ToHandleChecked();
|
||||
OptimizedCompilationInfo info(ArrayVector("testing"), handles.main_zone(),
|
||||
Code::WASM_FUNCTION);
|
||||
Handle<Code> code =
|
||||
Pipeline::GenerateCodeForTesting(
|
||||
&info, handles.main_isolate(), desc, m.graph(),
|
||||
AssemblerOptions::Default(handles.main_isolate()), m.Export())
|
||||
.ToHandleChecked();
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
if (FLAG_print_code) {
|
||||
StdoutStream os;
|
||||
code->Disassemble("multi_value", os);
|
||||
}
|
||||
if (FLAG_print_code) {
|
||||
StdoutStream os;
|
||||
code->Disassemble("multi_value", os);
|
||||
}
|
||||
#endif
|
||||
|
||||
const int a = 47, b = 12;
|
||||
int expect = 0;
|
||||
for (int i = 0, sign = +1; i < count; ++i) {
|
||||
if (i % 3 == 0) expect += sign * (a + b);
|
||||
if (i % 3 == 1) expect += sign * (a - b);
|
||||
if (i % 3 == 2) expect += sign * (a * b);
|
||||
if (i % 4 == 0) sign = -sign;
|
||||
}
|
||||
const int a = 47, b = 12;
|
||||
int expect = 0;
|
||||
for (int i = 0, sign = +1; i < count; ++i) {
|
||||
if (i % 3 == 0) expect += sign * (a + b);
|
||||
if (i % 3 == 1) expect += sign * (a - b);
|
||||
if (i % 3 == 2) expect += sign * (a * b);
|
||||
if (i % 4 == 0) sign = -sign;
|
||||
}
|
||||
|
||||
std::unique_ptr<wasm::NativeModule> module = AllocateNativeModule(
|
||||
handles.main_isolate(), code->raw_instruction_size());
|
||||
byte* code_start = module->AddCodeCopy(code, wasm::WasmCode::kFunction, 0)
|
||||
->instructions()
|
||||
.start();
|
||||
std::unique_ptr<wasm::NativeModule> module = AllocateNativeModule(
|
||||
handles.main_isolate(), code->raw_instruction_size());
|
||||
byte* code_start = module->AddCodeCopy(code, wasm::WasmCode::kFunction, 0)
|
||||
->instructions()
|
||||
.start();
|
||||
|
||||
RawMachineAssemblerTester<int32_t> mt;
|
||||
Node* call_inputs[] = {mt.PointerConstant(code_start),
|
||||
// WasmContext dummy
|
||||
mt.PointerConstant(nullptr),
|
||||
// Inputs
|
||||
MakeConstant(mt, type, a),
|
||||
MakeConstant(mt, type, b)};
|
||||
RawMachineAssemblerTester<int32_t> mt;
|
||||
const int input_count = 2 + param_count;
|
||||
Node* call_inputs[2 + kMaxParamCount];
|
||||
call_inputs[0] = mt.PointerConstant(code_start);
|
||||
// WasmContext dummy
|
||||
call_inputs[1] = mt.PointerConstant(nullptr);
|
||||
// Special inputs for the test.
|
||||
call_inputs[2] = MakeConstant(mt, type, a);
|
||||
call_inputs[3] = MakeConstant(mt, type, b);
|
||||
for (int i = 2; i < param_count; i++) {
|
||||
call_inputs[2 + i] = MakeConstant(mt, type, i);
|
||||
}
|
||||
|
||||
Node* ret_multi = mt.AddNode(mt.common()->Call(desc),
|
||||
arraysize(call_inputs), call_inputs);
|
||||
Node* ret = MakeConstant(mt, type, 0);
|
||||
bool sign = false;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
Node* x = (count == 1)
|
||||
? ret_multi
|
||||
: mt.AddNode(mt.common()->Projection(i), ret_multi);
|
||||
ret = sign ? Sub(mt, type, ret, x) : Add(mt, type, ret, x);
|
||||
if (i % 4 == 0) sign = !sign;
|
||||
}
|
||||
mt.Return(ToInt32(mt, type, ret));
|
||||
Node* ret_multi = mt.AddNode(mt.common()->Call(desc),
|
||||
input_count, call_inputs);
|
||||
Node* ret = MakeConstant(mt, type, 0);
|
||||
bool sign = false;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
Node* x = (count == 1)
|
||||
? ret_multi
|
||||
: mt.AddNode(mt.common()->Projection(i), ret_multi);
|
||||
ret = sign ? Sub(mt, type, ret, x) : Add(mt, type, ret, x);
|
||||
if (i % 4 == 0) sign = !sign;
|
||||
}
|
||||
mt.Return(ToInt32(mt, type, ret));
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
Handle<Code> code2 = mt.GetCode();
|
||||
if (FLAG_print_code) {
|
||||
StdoutStream os;
|
||||
code2->Disassemble("multi_value_call", os);
|
||||
}
|
||||
Handle<Code> code2 = mt.GetCode();
|
||||
if (FLAG_print_code) {
|
||||
StdoutStream os;
|
||||
code2->Disassemble("multi_value_call", os);
|
||||
}
|
||||
#endif
|
||||
CHECK_EQ(expect, mt.Call());
|
||||
CHECK_EQ(expect, mt.Call());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,6 +306,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
&wrapper_info, i_isolate, wrapper_desc, caller.graph(),
|
||||
AssemblerOptions::Default(i_isolate), caller.Export())
|
||||
.ToHandleChecked();
|
||||
|
||||
auto fn = GeneratedCode<int32_t>::FromCode(*wrapper_code);
|
||||
int result = fn.Call();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user