diff --git a/tools/simdstring/generate.go b/tools/simdstring/generate.go index a0b7872fc..6453c0948 100644 --- a/tools/simdstring/generate.go +++ b/tools/simdstring/generate.go @@ -386,7 +386,7 @@ func shrn8b_immediate4(a, b Register) uint32 { } func encode_cmgt16b(a, b, dest Register) (ans uint32) { - return 0x271<<21 | a.ARMId()<<16 | 0xd<<10 | b.ARMId()<<5 | dest.ARMId() + return 0x271<<21 | b.ARMId()<<16 | 0xd<<10 | a.ARMId()<<5 | dest.ARMId() } func (f *Function) CountBytesToFirstMatchDestructive(vec, ans Register) { @@ -738,19 +738,36 @@ func (f *Function) cmp(a, b, ans Register, op, c_rep string) { f.instr("WORD", fmt.Sprintf("$0x%x", encode_cmgt16b(a, b, ans))) } } else { - op := `PCMP` + op + "B" + fop := `PCMP` + op + "B" if f.ISA.Bits == 128 { - switch ans.Name { - case a.Name: - f.instr(op, b, ans) - case b.Name: - f.instr(op, a, ans) - default: - f.CopyRegister(a, ans) - f.instr(op, b, ans) + if op == "EQ" { + switch ans.Name { + case a.Name: + f.instr(fop, b, ans) + case b.Name: + f.instr(fop, a, ans) + default: + f.CopyRegister(a, ans) + f.instr(fop, b, ans) + } + } else { + // order matters, we want destination aka 2nd arg to be both a and ans + switch ans.Name { + case a.Name: + f.instr(fop, b, a) + case b.Name: + vec := f.Vec(a.Size) + f.CopyRegister(a, vec) + f.instr(fop, b, vec) + f.CopyRegister(vec, b) + f.ReleaseReg(vec) + default: + f.CopyRegister(a, ans) + f.instr(fop, b, ans) + } } } else { - f.instr("V"+op, a, b, ans) + f.instr("V"+fop, b, a, ans) } } f.AddTrailingComment(ans, "= 0xff on every byte where", a.Name+"[n]", c_rep, b.Name+"[n] and zero elsewhere") @@ -1201,14 +1218,31 @@ func (s *State) test_cmpeq_epi8() { } func (s *State) test_cmplt_epi8() { - f := s.NewFunction("test_cmplt_epi8_asm", "Test byte comparison of two vectors", []FunctionParam{{"a", ByteSlice}, {"b", ByteSlice}, {"ans", ByteSlice}}, nil) + f := s.NewFunction( + "test_cmplt_epi8_asm", "Test byte comparison of two vectors", []FunctionParam{{"a", ByteSlice}, {"b", ByteSlice}, {"which", types.Int}, {"ans", ByteSlice}}, nil) if !s.ISA.HasSIMD { return } + which := f.LoadParam("which") a := f.load_vec_from_param("a") b := f.load_vec_from_param("b") + r := f.Reg() + f.SetRegisterTo(r, 1) + f.JumpIfEqual(which, r, "one") + f.SetRegisterTo(r, 2) + f.JumpIfEqual(which, r, "two") + ans := f.Vec() + f.CmpLtEpi8(a, b, ans) + f.store_vec_in_param(ans, "ans") + f.Return() + f.Label("one") f.CmpLtEpi8(a, b, a) f.store_vec_in_param(a, "ans") + f.Return() + f.Label("two") + f.CmpLtEpi8(a, b, b) + f.store_vec_in_param(b, "ans") + f.Return() } func (s *State) test_or() { diff --git a/tools/simdstring/intrinsics_test.go b/tools/simdstring/intrinsics_test.go index 79e4859f4..5e0eab314 100644 --- a/tools/simdstring/intrinsics_test.go +++ b/tools/simdstring/intrinsics_test.go @@ -44,12 +44,21 @@ func test_cmpeq_epi8(a, b []byte) []byte { return ans } -func test_cmplt_epi8(a, b []byte) []byte { +func test_cmplt_epi8(t *testing.T, a, b []byte) []byte { ans := make([]byte, len(a)) - if len(ans) == 16 { - test_cmplt_epi8_asm_128(a, b, ans) - } else { - test_cmplt_epi8_asm_256(a, b, ans) + var prev []byte + for which := 0; which < 3; which++ { + if len(ans) == 16 { + test_cmplt_epi8_asm_128(a, b, which, ans) + } else { + test_cmplt_epi8_asm_256(a, b, which, ans) + } + if prev != nil { + if s := cmp.Diff(prev, ans); s != "" { + t.Fatalf("cmplt returned different result for which=%d\n%s", which, s) + } + } + prev = bytes.Clone(ans) } return ans } @@ -251,14 +260,25 @@ func TestIntrinsics(t *testing.T) { b := ordered_bytes(sz) ans := test_cmpeq_epi8(a, b) ae(sz, `cmpeq_epi8_test`, broadcast_byte(0xff, sz), ans) - threshold := -1 - a[1] = byte(threshold) - a[2] = byte(threshold - 1) - ans = test_cmplt_epi8(a, broadcast_byte(byte(threshold), sz)) - expected := broadcast_byte(0xff, sz) - expected[1] = 0 - expected[2] = 0 - ae(sz, `cmplt_epi8_test`, expected, ans) + + lt := func(a, b []byte) []byte { + ans := make([]byte, len(a)) + for i := range ans { + if int8(a[i]) < int8(b[i]) { + ans[i] = 0xff + } + } + return ans + } + + ae(sz, "cmplt_epi8_test with equal vecs of non-negative numbers", lt(a, b), test_cmplt_epi8(t, a, b)) + a = broadcast_byte(1, sz) + b = broadcast_byte(2, sz) + ae(sz, "cmplt_epi8_test with 1 and 2", lt(a, b), test_cmplt_epi8(t, a, b)) + ae(sz, "cmplt_epi8_test with 2 and 1", lt(b, a), test_cmplt_epi8(t, b, a)) + a = broadcast_byte(0xff, sz) + b = broadcast_byte(0, sz) + ae(sz, "cmplt_epi8_test with -1 and 0", lt(a, b), test_cmplt_epi8(t, a, b)) }) tests = append(tests, func(sz int) { a := make([]byte, sz)