From: ager@chromium.org Date: Wed, 21 Jul 2010 07:42:51 +0000 (+0000) Subject: Landing for Rodolph Perfetta. X-Git-Tag: upstream/4.7.83~21463 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=74f9789f613108e5547d2d70305854311609a93d;p=platform%2Fupstream%2Fv8.git Landing for Rodolph Perfetta. Add support for saturation instruction (ARMv6 or above). The byte array clamping code has been updated accordingly. Review URL: http://codereview.chromium.org/3036008/show git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5106 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc index 0dc6b7710..a16f2002f 100644 --- a/src/arm/assembler-arm.cc +++ b/src/arm/assembler-arm.cc @@ -1192,6 +1192,30 @@ void Assembler::clz(Register dst, Register src, Condition cond) { } +// Saturating instructions. + +// Unsigned saturate. +void Assembler::usat(Register dst, + int satpos, + const Operand& src, + Condition cond) { + // v6 and above. + ASSERT(CpuFeatures::IsSupported(ARMv7)); + ASSERT(!dst.is(pc) && !src.rm_.is(pc)); + ASSERT((satpos >= 0) && (satpos <= 31)); + ASSERT((src.shift_op_ == ASR) || (src.shift_op_ == LSL)); + ASSERT(src.rs_.is(no_reg)); + + int sh = 0; + if (src.shift_op_ == ASR) { + sh = 1; + } + + emit(cond | 0x6*B24 | 0xe*B20 | satpos*B16 | dst.code()*B12 | + src.shift_imm_*B7 | sh*B6 | 0x1*B4 | src.rm_.code()); +} + + // Bitfield manipulation instructions. // Unsigned bit field extract. diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h index 226fb8740..39a5b4e9d 100644 --- a/src/arm/assembler-arm.h +++ b/src/arm/assembler-arm.h @@ -445,6 +445,8 @@ class Operand BASE_EMBEDDED { } Register rm() const { return rm_; } + Register rs() const { return rs_; } + ShiftOp shift_op() const { return shift_op_; } private: Register rm_; @@ -834,6 +836,25 @@ class Assembler : public Malloced { void clz(Register dst, Register src, Condition cond = al); // v5 and above + // Saturating instructions. v6 and above. + + // Unsigned saturate. + // + // Saturate an optionally shifted signed value to an unsigned range. + // + // usat dst, #satpos, src + // usat dst, #satpos, src, lsl #sh + // usat dst, #satpos, src, asr #sh + // + // Register dst will contain: + // + // 0, if s < 0 + // (1 << satpos) - 1, if s > ((1 << satpos) - 1) + // s, otherwise + // + // where s is the contents of src after shifting (if used.) + void usat(Register dst, int satpos, const Operand& src, Condition cond = al); + // Bitfield manipulation instructions. v7 and above. void ubfx(Register dst, Register src, int lsb, int width, diff --git a/src/arm/disasm-arm.cc b/src/arm/disasm-arm.cc index 37401ed28..fd142bd96 100644 --- a/src/arm/disasm-arm.cc +++ b/src/arm/disasm-arm.cc @@ -106,6 +106,7 @@ class Decoder { void PrintCondition(Instr* instr); void PrintShiftRm(Instr* instr); void PrintShiftImm(Instr* instr); + void PrintShiftSat(Instr* instr); void PrintPU(Instr* instr); void PrintSoftwareInterrupt(SoftwareInterruptCodes swi); @@ -248,6 +249,18 @@ void Decoder::PrintShiftImm(Instr* instr) { } +// Print the optional shift and immediate used by saturating instructions. +void Decoder::PrintShiftSat(Instr* instr) { + int shift = instr->Bits(11, 7); + if (shift > 0) { + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, + ", %s #%d", + shift_names[instr->Bit(6) * 2], + instr->Bits(11, 7)); + } +} + + // Print PU formatting to reduce complexity of FormatOption. void Decoder::PrintPU(Instr* instr) { switch (instr->PUField()) { @@ -440,6 +453,20 @@ int Decoder::FormatOption(Instr* instr, const char* format) { } return 1; } + case 'i': { // 'i: immediate value from adjacent bits. + // Expects tokens in the form imm%02d@%02d, ie. imm05@07, imm10@16 + int width = (format[3] - '0') * 10 + (format[4] - '0'); + int lsb = (format[6] - '0') * 10 + (format[7] - '0'); + + ASSERT((width >= 1) && (width <= 32)); + ASSERT((lsb >= 0) && (lsb <= 31)); + ASSERT((width + lsb) <= 32); + + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "#%d", + instr->Bits(width + lsb - 1, lsb)); + return 8; + } case 'l': { // 'l: branch and link if (instr->HasLink()) { Print("l"); @@ -507,7 +534,7 @@ int Decoder::FormatOption(Instr* instr, const char* format) { return FormatRegister(instr, format); } case 's': { - if (format[1] == 'h') { // 'shift_op or 'shift_rm + if (format[1] == 'h') { // 'shift_op or 'shift_rm or 'shift_sat. if (format[6] == 'o') { // 'shift_op ASSERT(STRING_STARTS_WITH(format, "shift_op")); if (instr->TypeField() == 0) { @@ -517,6 +544,10 @@ int Decoder::FormatOption(Instr* instr, const char* format) { PrintShiftImm(instr); } return 8; + } else if (format[6] == 's') { // 'shift_sat. + ASSERT(STRING_STARTS_WITH(format, "shift_sat")); + PrintShiftSat(instr); + return 9; } else { // 'shift_rm ASSERT(STRING_STARTS_WITH(format, "shift_rm")); PrintShiftRm(instr); @@ -897,8 +928,16 @@ void Decoder::DecodeType3(Instr* instr) { break; } case 1: { - ASSERT(!instr->HasW()); - Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm"); + if (instr->HasW()) { + ASSERT(instr->Bits(5, 4) == 0x1); + if (instr->Bit(22) == 0x1) { + Format(instr, "usat 'rd, 'imm05@16, 'rm'shift_sat"); + } else { + UNREACHABLE(); // SSAT. + } + } else { + Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm"); + } break; } case 2: { diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc index 57d9376ec..144f8e3b9 100644 --- a/src/arm/ic-arm.cc +++ b/src/arm/ic-arm.cc @@ -1674,14 +1674,8 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { __ cmp(r4, Operand(ip)); __ b(hs, &slow); __ mov(r5, Operand(value, ASR, kSmiTagSize)); // Untag the value. - { // Clamp the value to [0..255]. - Label done; - __ tst(r5, Operand(0xFFFFFF00)); - __ b(eq, &done); - __ mov(r5, Operand(0), LeaveCC, mi); // 0 if negative. - __ mov(r5, Operand(255), LeaveCC, pl); // 255 if positive. - __ bind(&done); - } + __ Usat(r5, 8, Operand(r5)); // Clamp the value to [0..255]. + // Get the pointer to the external array. This clobbers elements. __ ldr(elements, FieldMemOperand(elements, PixelArray::kExternalPointerOffset)); diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index f251b31f0..ad22cd940 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -281,6 +281,37 @@ void MacroAssembler::Bfc(Register dst, int lsb, int width, Condition cond) { } +void MacroAssembler::Usat(Register dst, int satpos, const Operand& src, + Condition cond) { + if (!CpuFeatures::IsSupported(ARMv7)) { + ASSERT(!dst.is(pc) && !src.rm().is(pc)); + ASSERT((satpos >= 0) && (satpos <= 31)); + + // These asserts are required to ensure compatibility with the ARMv7 + // implementation. + ASSERT((src.shift_op() == ASR) || (src.shift_op() == LSL)); + ASSERT(src.rs().is(no_reg)); + + Label done; + int satval = (1 << satpos) - 1; + + if (cond != al) { + b(NegateCondition(cond), &done); // Skip saturate if !condition. + } + if (!(src.is_reg() && dst.is(src.rm()))) { + mov(dst, src); + } + tst(dst, Operand(~satval)); + b(eq, &done); + mov(dst, Operand(0), LeaveCC, mi); // 0 if negative. + mov(dst, Operand(satval), LeaveCC, pl); // satval if positive. + bind(&done); + } else { + usat(dst, satpos, src, cond); + } +} + + void MacroAssembler::SmiJumpTable(Register index, Vector targets) { // Empty the const pool. CheckConstPool(true, true); diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 156e13269..9949fac15 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -112,6 +112,8 @@ class MacroAssembler: public Assembler { void Sbfx(Register dst, Register src, int lsb, int width, Condition cond = al); void Bfc(Register dst, int lsb, int width, Condition cond = al); + void Usat(Register dst, int satpos, const Operand& src, + Condition cond = al); void Call(Label* target); void Move(Register dst, Handle value); diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc index 3345e4559..04635e3f9 100644 --- a/src/arm/simulator-arm.cc +++ b/src/arm/simulator-arm.cc @@ -2047,11 +2047,41 @@ void Simulator::DecodeType3(Instr* instr) { case 0: { ASSERT(!instr->HasW()); Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm"); + UNIMPLEMENTED(); break; } case 1: { - ASSERT(!instr->HasW()); - Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm"); + if (instr->HasW()) { + ASSERT(instr->Bits(5, 4) == 0x1); + + if (instr->Bit(22) == 0x1) { // USAT. + int32_t sat_pos = instr->Bits(20, 16); + int32_t sat_val = (1 << sat_pos) - 1; + int32_t shift = instr->Bits(11, 7); + int32_t shift_type = instr->Bit(6); + int32_t rm_val = get_register(instr->RmField()); + if (shift_type == 0) { // LSL + rm_val <<= shift; + } else { // ASR + rm_val >>= shift; + } + // If saturation occurs, the Q flag should be set in the CPSR. + // There is no Q flag yet, and no instruction (MRS) to read the + // CPSR directly. + if (rm_val > sat_val) { + rm_val = sat_val; + } else if (rm_val < 0) { + rm_val = 0; + } + set_register(rd, rm_val); + } else { // SSAT. + UNIMPLEMENTED(); + } + return; + } else { + Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm"); + UNIMPLEMENTED(); + } break; } case 2: { diff --git a/src/arm/simulator-arm.h b/src/arm/simulator-arm.h index 61af3aa6e..fee296e40 100644 --- a/src/arm/simulator-arm.h +++ b/src/arm/simulator-arm.h @@ -294,6 +294,9 @@ class Simulator { void TrashCallerSaveRegisters(); // Architecture state. + // Saturating instructions require a Q flag to indicate saturation. + // There is currently no way to read the CPSR directly, and thus read the Q + // flag, so this is left unimplemented. int32_t registers_[16]; bool n_flag_; bool z_flag_; diff --git a/test/cctest/test-assembler-arm.cc b/test/cctest/test-assembler-arm.cc index 5e49c0cda..9033f4b87 100644 --- a/test/cctest/test-assembler-arm.cc +++ b/test/cctest/test-assembler-arm.cc @@ -310,4 +310,38 @@ TEST(5) { } } + +TEST(6) { + // Test saturating instructions. + InitializeVM(); + v8::HandleScope scope; + + Assembler assm(NULL, 0); + + if (CpuFeatures::IsSupported(ARMv7)) { + CpuFeatures::Scope scope(ARMv7); + __ usat(r1, 8, Operand(r0)); // Sat 0xFFFF to 0-255 = 0xFF. + __ usat(r2, 12, Operand(r0, ASR, 9)); // Sat (0xFFFF>>9) to 0-4095 = 0x7F. + __ usat(r3, 1, Operand(r0, LSL, 16)); // Sat (0xFFFF<<16) to 0-1 = 0x0. + __ add(r0, r1, Operand(r2)); + __ add(r0, r0, Operand(r3)); + __ mov(pc, Operand(lr)); + + CodeDesc desc; + assm.GetCode(&desc); + Object* code = Heap::CreateCode(desc, + Code::ComputeFlags(Code::STUB), + Handle(Heap::undefined_value())); + CHECK(code->IsCode()); +#ifdef DEBUG + Code::cast(code)->Print(); +#endif + F1 f = FUNCTION_CAST(Code::cast(code)->entry()); + int res = reinterpret_cast( + CALL_GENERATED_CODE(f, 0xFFFF, 0, 0, 0, 0)); + ::printf("f() = %d\n", res); + CHECK_EQ(382, res); + } +} + #undef __ diff --git a/test/cctest/test-disasm-arm.cc b/test/cctest/test-disasm-arm.cc index 2bb32e7f5..0ba4f9ae4 100644 --- a/test/cctest/test-disasm-arm.cc +++ b/test/cctest/test-disasm-arm.cc @@ -396,6 +396,15 @@ TEST(Type3) { "e7df0f91 bfi r0, r1, #31, #1"); COMPARE(bfi(r1, r0, 31, 1), "e7df1f90 bfi r1, r0, #31, #1"); + + COMPARE(usat(r0, 1, Operand(r1)), + "e6e10011 usat r0, #1, r1"); + COMPARE(usat(r2, 7, Operand(lr)), + "e6e7201e usat r2, #7, lr"); + COMPARE(usat(r3, 31, Operand(r4, LSL, 31)), + "e6ff3f94 usat r3, #31, r4, lsl #31"); + COMPARE(usat(r8, 0, Operand(r5, ASR, 17)), + "e6e088d5 usat r8, #0, r5, asr #17"); } VERIFY_RUN();