1 // Copyright 2014 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <cmath> 6 #include <functional> 7 #include <limits> 8 9 #include "src/assembler.h" 10 #include "src/base/bits.h" 11 #include "src/base/utils/random-number-generator.h" 12 #include "src/codegen.h" 13 #include "src/compiler.h" 14 #include "src/compiler/linkage.h" 15 #include "src/macro-assembler.h" 16 #include "test/cctest/cctest.h" 17 #include "test/cctest/compiler/codegen-tester.h" 18 #include "test/cctest/compiler/value-helper.h" 19 20 namespace v8 { 21 namespace internal { 22 namespace compiler { 23 24 namespace { 25 26 CallDescriptor* GetCallDescriptor(Zone* zone, int return_count, 27 int param_count) { 28 MachineSignature::Builder msig(zone, return_count, param_count); 29 LocationSignature::Builder locations(zone, return_count, param_count); 30 const RegisterConfiguration* config = 31 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN); 32 33 // Add return location(s). 34 CHECK(return_count <= config->num_allocatable_general_registers()); 35 for (int i = 0; i < return_count; i++) { 36 msig.AddReturn(MachineType::Int32()); 37 locations.AddReturn( 38 LinkageLocation::ForRegister(config->allocatable_general_codes()[i])); 39 } 40 41 // Add register and/or stack parameter(s). 42 CHECK(param_count <= config->num_allocatable_general_registers()); 43 for (int i = 0; i < param_count; i++) { 44 msig.AddParam(MachineType::Int32()); 45 locations.AddParam( 46 LinkageLocation::ForRegister(config->allocatable_general_codes()[i])); 47 } 48 49 const RegList kCalleeSaveRegisters = 0; 50 const RegList kCalleeSaveFPRegisters = 0; 51 52 // The target for WASM calls is always a code object. 53 MachineType target_type = MachineType::AnyTagged(); 54 LinkageLocation target_loc = LinkageLocation::ForAnyRegister(); 55 return new (zone) CallDescriptor( // -- 56 CallDescriptor::kCallCodeObject, // kind 57 target_type, // target MachineType 58 target_loc, // target location 59 msig.Build(), // machine_sig 60 locations.Build(), // location_sig 61 0, // js_parameter_count 62 compiler::Operator::kNoProperties, // properties 63 kCalleeSaveRegisters, // callee-saved registers 64 kCalleeSaveFPRegisters, // callee-saved fp regs 65 CallDescriptor::kNoFlags, // flags 66 "c-call"); 67 } 68 } // namespace 69 70 71 TEST(ReturnThreeValues) { 72 Zone zone; 73 CallDescriptor* desc = GetCallDescriptor(&zone, 3, 2); 74 HandleAndZoneScope handles; 75 RawMachineAssembler m(handles.main_isolate(), 76 new (handles.main_zone()) Graph(handles.main_zone()), 77 desc, MachineType::PointerRepresentation(), 78 InstructionSelector::SupportedMachineOperatorFlags()); 79 80 Node* p0 = m.Parameter(0); 81 Node* p1 = m.Parameter(1); 82 Node* add = m.Int32Add(p0, p1); 83 Node* sub = m.Int32Sub(p0, p1); 84 Node* mul = m.Int32Mul(p0, p1); 85 m.Return(add, sub, mul); 86 87 CompilationInfo info("testing", handles.main_isolate(), handles.main_zone()); 88 Handle<Code> code = 89 Pipeline::GenerateCodeForTesting(&info, desc, m.graph(), m.Export()); 90 #ifdef ENABLE_DISASSEMBLER 91 if (FLAG_print_code) { 92 OFStream os(stdout); 93 code->Disassemble("three_value", os); 94 } 95 #endif 96 97 RawMachineAssemblerTester<int32_t> mt; 98 Node* a = mt.Int32Constant(123); 99 Node* b = mt.Int32Constant(456); 100 Node* ret3 = mt.AddNode(mt.common()->Call(desc), mt.HeapConstant(code), a, b); 101 Node* x = mt.AddNode(mt.common()->Projection(0), ret3); 102 Node* y = mt.AddNode(mt.common()->Projection(1), ret3); 103 Node* z = mt.AddNode(mt.common()->Projection(2), ret3); 104 Node* ret = mt.Int32Add(mt.Int32Add(x, y), z); 105 mt.Return(ret); 106 #ifdef ENABLE_DISASSEMBLER 107 Handle<Code> code2 = mt.GetCode(); 108 if (FLAG_print_code) { 109 OFStream os(stdout); 110 code2->Disassemble("three_value_call", os); 111 } 112 #endif 113 CHECK_EQ((123 + 456) + (123 - 456) + (123 * 456), mt.Call()); 114 } 115 116 } // namespace compiler 117 } // namespace internal 118 } // namespace v8 119