mirror of
https://github.com/open-goal/jak-project
synced 2026-08-13 12:19:35 -04:00
decomp: main-collide and support a bunch of new inline-asm operations (#673)
* decomp/goal-lib: Implement all fixed point macros * decompiler/goalc: Support half-word and byte parallel extend ops * decompiler/goalc: Support all parallel compare instructions * decompiler/goalc: Wire up PPACH and parallel bitwise operations * goalc: Add emitter tests * decomp: finalize `main-collide` * codacy lint
This commit is contained in:
@@ -12,11 +12,28 @@ const std::map<InstructionKind, OpenGOALAsm::Function> MIPS_ASM_TO_OPEN_GOAL_FUN
|
||||
{InstructionKind::PSRAW, {".pw.sra", {}}},
|
||||
{InstructionKind::PSUBW, {".psubw", {}}},
|
||||
|
||||
// Boolean Arithmetic - or / not or / and
|
||||
{InstructionKind::POR, {".por", {}}},
|
||||
{InstructionKind::PNOR, {".pnor", {}}},
|
||||
{InstructionKind::PAND, {".pand", {}}},
|
||||
|
||||
// Parallel Pack
|
||||
{InstructionKind::PPACH, {".ppach", {}}},
|
||||
|
||||
// Parallel Compares
|
||||
{InstructionKind::PCEQB, {".pceqb", {}}},
|
||||
// {InstructionKind::PCEQH, {".pceqh", {}}},
|
||||
{InstructionKind::PCEQW, {".pceqw", {}}},
|
||||
// {InstructionKind::PCGTB, {".pcgtb", {}}},
|
||||
// {InstructionKind::PCGTH, {".pcgth", {}}},
|
||||
{InstructionKind::PCGTW, {".pcgtw", {}}},
|
||||
|
||||
// Parallel Extends
|
||||
{InstructionKind::PEXTUB, {".pextub", {}}},
|
||||
{InstructionKind::PEXTUH, {".pextuh", {}}},
|
||||
{InstructionKind::PEXTUW, {".pextuw", {}}},
|
||||
{InstructionKind::PEXTLB, {".pextlb", {}}},
|
||||
{InstructionKind::PEXTLH, {".pextlh", {}}},
|
||||
{InstructionKind::PEXTLW, {".pextlw", {}}},
|
||||
{InstructionKind::PCPYLD, {".pcpyld", {}}},
|
||||
{InstructionKind::PCPYUD, {".pcpyud", {}}},
|
||||
@@ -113,13 +130,11 @@ const std::map<InstructionKind, OpenGOALAsm::Function> MIPS_ASM_TO_OPEN_GOAL_FUN
|
||||
//// Fixed point conversions
|
||||
{InstructionKind::VFTOI0, {".ftoi.vf", {MOD::DEST_MASK}}},
|
||||
{InstructionKind::VITOF0, {".itof.vf", {MOD::DEST_MASK}}},
|
||||
|
||||
{InstructionKind::VFTOI4, {"TODO.VFTOI4", {}}},
|
||||
|
||||
{InstructionKind::VITOF12, {"TODO.VITOF12", {}}},
|
||||
{InstructionKind::VFTOI12, {"TODO.VFTOI12", {}}},
|
||||
|
||||
{InstructionKind::VITOF15, {"TODO.VITOF15", {}}},
|
||||
// NOTE - Only the .xyzw mask is supported via macros!
|
||||
{InstructionKind::VFTOI4, {"vftoi4.xyzw", {MOD::DEST_MASK}}},
|
||||
{InstructionKind::VITOF12, {"vitof12.xyzw", {MOD::DEST_MASK}}},
|
||||
{InstructionKind::VFTOI12, {"vftoi12.xyzw", {MOD::DEST_MASK}}},
|
||||
{InstructionKind::VITOF15, {"vitof15.xyzw", {MOD::DEST_MASK}}},
|
||||
|
||||
//// Status Checks
|
||||
{InstructionKind::VCLIP, {"TODO.VCLIP", {}}},
|
||||
|
||||
@@ -961,4 +961,4 @@ const DecompilerLabel& LinkedObjectFile::get_label_by_name(const std::string& na
|
||||
}
|
||||
throw std::runtime_error("Cannot find label " + name);
|
||||
}
|
||||
} // namespace decompiler
|
||||
} // namespace decompiler
|
||||
|
||||
@@ -15793,7 +15793,7 @@
|
||||
|
||||
(define-extern collide-cache-using-line-sphere-test function)
|
||||
(define-extern collide-cache-using-y-probe-test function)
|
||||
(define-extern collide-cache-using-box-test function)
|
||||
(define-extern collide-cache-using-box-test (function vector symbol))
|
||||
(define-extern draw-node-cull function)
|
||||
|
||||
|
||||
@@ -19481,9 +19481,9 @@
|
||||
|
||||
;; - Functions
|
||||
|
||||
(define-extern drawable-sphere-box-intersect? function)
|
||||
(define-extern instance-sphere-box-intersect? function)
|
||||
(define-extern instance-tfragment-add-debug-sphere function)
|
||||
(define-extern drawable-sphere-box-intersect? (function drawable bounding-box4w symbol)) ;; TODO - pcgtw | por | ppach
|
||||
(define-extern instance-sphere-box-intersect? (function drawable instance-tie bounding-box4w symbol)) ;; pextlh | VITOF12 | pcgtw | por | ppach ;; TODO - the first arg is based from the second arg in `drawable:11`
|
||||
(define-extern instance-tfragment-add-debug-sphere (function drawable instance-tie symbol)) ;; unused
|
||||
|
||||
|
||||
;; ----------------------
|
||||
|
||||
@@ -1286,6 +1286,10 @@
|
||||
["L652", "float", true]
|
||||
],
|
||||
|
||||
"main-collide": [
|
||||
["L5", "rgba", true]
|
||||
],
|
||||
|
||||
// please do not add things after this entry! git is dumb.
|
||||
"object-file-that-doesnt-actually-exist-and-i-just-put-this-here-to-prevent-merge-conflicts-with-this-file": []
|
||||
}
|
||||
|
||||
@@ -577,6 +577,12 @@
|
||||
"anim-tester-add-newobj": [[16, "event-message-block"]],
|
||||
"anim-tester-start": [[16, "event-message-block"]],
|
||||
"anim-tester-add-sequence": [[16, "event-message-block"]],
|
||||
|
||||
"(anon-function 28 task-control)": [[16, "event-message-block"]],
|
||||
|
||||
"instance-tfragment-add-debug-sphere": [
|
||||
[16, "vector"]
|
||||
],
|
||||
|
||||
"placeholder-do-not-add-below!": []
|
||||
}
|
||||
|
||||
@@ -5,3 +5,227 @@
|
||||
;; name in dgo: main-collide
|
||||
;; dgos: GAME, ENGINE
|
||||
|
||||
;; definition for function drawable-sphere-box-intersect?
|
||||
;; WARN: Function may read a register that is not set: f31
|
||||
;; Used lq/sq
|
||||
(defun drawable-sphere-box-intersect? ((arg0 drawable) (arg1 bounding-box4w))
|
||||
(local-vars
|
||||
(r0-0 int)
|
||||
(r0-1 int)
|
||||
(r0-2 uint128)
|
||||
(r0-3 int)
|
||||
(v1-1 uint128)
|
||||
(v1-2 uint128)
|
||||
(v1-3 uint128)
|
||||
(a0-1 uint128)
|
||||
(a1-2 uint128)
|
||||
(a2-0 uint128)
|
||||
(f31-0 none)
|
||||
)
|
||||
(rlet ((vf1 :class vf)
|
||||
(vf2 :class vf)
|
||||
(vf3 :class vf)
|
||||
(vf4 :class vf)
|
||||
)
|
||||
(nop!)
|
||||
(nop!)
|
||||
(.lvf vf1 (&-> arg0 bsphere quad))
|
||||
(.add.w.vf vf2 vf1 vf1 :mask #b111)
|
||||
(let ((v1-0 (-> arg1 min quad)))
|
||||
(.sub.w.vf vf1 vf1 vf1 :mask #b111)
|
||||
(let ((a1-1 (-> arg1 max quad)))
|
||||
(.ftoi.vf vf4 vf2)
|
||||
(nop!)
|
||||
(.ftoi.vf vf3 vf1)
|
||||
(nop!)
|
||||
(.mov a0-1 vf4)
|
||||
(nop!)
|
||||
(.mov a2-0 vf3)
|
||||
(nop!)
|
||||
(.pcgtw a1-2 a2-0 a1-1)
|
||||
)
|
||||
(.mov r0-0 f31-0)
|
||||
(.pcgtw v1-1 v1-0 a0-1)
|
||||
)
|
||||
(.mov r0-1 f31-0)
|
||||
(.por v1-2 a1-2 v1-1)
|
||||
(.mov r0-2 f31-0)
|
||||
(.ppach v1-3 r0-2 v1-2)
|
||||
(.mov r0-3 f31-0)
|
||||
(let ((v1-4 (shl (the-as int v1-3) 16)))
|
||||
(nop!)
|
||||
(zero? v1-4)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function instance-sphere-box-intersect?
|
||||
;; WARN: Function may read a register that is not set: f31
|
||||
;; Used lq/sq
|
||||
(defun
|
||||
instance-sphere-box-intersect?
|
||||
((arg0 drawable) (arg1 instance-tie) (arg2 bounding-box4w))
|
||||
(local-vars
|
||||
(r0-0 uint128)
|
||||
(r0-1 int)
|
||||
(r0-2 uint128)
|
||||
(r0-3 int)
|
||||
(r0-4 int)
|
||||
(r0-5 uint128)
|
||||
(r0-6 int)
|
||||
(v1-3 uint128)
|
||||
(v1-4 uint128)
|
||||
(v1-5 uint128)
|
||||
(a0-2 uint128)
|
||||
(a1-2 uint128)
|
||||
(a2-1 uint128)
|
||||
(a3-1 uint128)
|
||||
(a3-3 uint128)
|
||||
(a3-4 uint128)
|
||||
(t0-1 uint128)
|
||||
(t0-2 uint128)
|
||||
(t1-0 uint128)
|
||||
(t2-1 uint128)
|
||||
(t2-2 uint128)
|
||||
(f31-0 none)
|
||||
)
|
||||
(rlet ((acc :class vf)
|
||||
(vf0 :class vf)
|
||||
(vf1 :class vf)
|
||||
(vf10 :class vf)
|
||||
(vf2 :class vf)
|
||||
(vf3 :class vf)
|
||||
(vf4 :class vf)
|
||||
(vf5 :class vf)
|
||||
(vf6 :class vf)
|
||||
(vf7 :class vf)
|
||||
(vf8 :class vf)
|
||||
(vf9 :class vf)
|
||||
)
|
||||
(init-vf0-vector)
|
||||
(nop!)
|
||||
(let ((v1-0 (-> arg1 max-scale)))
|
||||
(nop!)
|
||||
(let ((a3-0 (the-as uint128 (-> arg1 origin vector4h 3 long))))
|
||||
(nop!)
|
||||
(let ((t2-0 (the-as uint128 (-> arg1 origin vector4h 0 long))))
|
||||
(.pextlh a3-1 a3-0 r0-0)
|
||||
(let ((t0-0 (the-as uint128 (-> arg1 origin vector4h 1 long))))
|
||||
(.pw.sra t1-0 a3-1 10)
|
||||
(let ((a3-2 (the-as uint128 (-> arg1 origin vector4h 2 long))))
|
||||
(.pextlh t2-1 t2-0 r0-0)
|
||||
(.mov r0-1 f31-0)
|
||||
(.pw.sra t2-2 t2-1 16)
|
||||
(.mov r0-2 f31-0)
|
||||
(.pextlh t0-1 t0-0 r0-2)
|
||||
(.mov vf8 t1-0)
|
||||
(.pw.sra t0-2 t0-1 16)
|
||||
(.mov vf5 t2-2)
|
||||
(.pextlh a3-3 a3-2 r0-2)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(.mov vf6 t0-2)
|
||||
(.pw.sra a3-4 a3-3 16)
|
||||
(.lvf vf9 (&-> arg1 bsphere quad))
|
||||
(nop!)
|
||||
(.mov vf7 a3-4)
|
||||
(nop!)
|
||||
(.mov vf10 v1-0)
|
||||
)
|
||||
(.itof.vf vf8 vf8)
|
||||
(nop!)
|
||||
(vitof12.xyzw vf5 vf5)
|
||||
(nop!)
|
||||
(vitof12.xyzw vf6 vf6)
|
||||
(nop!)
|
||||
(vitof12.xyzw vf7 vf7)
|
||||
(nop!)
|
||||
(.add.vf vf8 vf8 vf9 :mask #b111)
|
||||
(nop!)
|
||||
(nop!)
|
||||
(.lvf vf9 (&-> arg0 bsphere quad))
|
||||
(vitof12.xyzw vf10 vf10)
|
||||
(nop!)
|
||||
(.mul.w.vf vf10 vf10 vf9 :mask #b1)
|
||||
(nop!)
|
||||
(.mul.x.vf acc vf5 vf9)
|
||||
(nop!)
|
||||
(.add.mul.y.vf acc vf6 vf9 acc)
|
||||
(let ((v1-2 (-> arg2 min quad)))
|
||||
(.add.mul.z.vf acc vf7 vf9 acc)
|
||||
(let ((a1-1 (-> arg2 max quad)))
|
||||
(.add.mul.w.vf vf1 vf8 vf0 acc)
|
||||
(nop!)
|
||||
(.add.x.vf vf2 vf1 vf10 :mask #b111)
|
||||
(nop!)
|
||||
(.sub.x.vf vf1 vf1 vf10 :mask #b111)
|
||||
(nop!)
|
||||
(.ftoi.vf vf4 vf2)
|
||||
(nop!)
|
||||
(.ftoi.vf vf3 vf1)
|
||||
(nop!)
|
||||
(.mov a0-2 vf4)
|
||||
(nop!)
|
||||
(.mov a2-1 vf3)
|
||||
(nop!)
|
||||
(.pcgtw a1-2 a2-1 a1-1)
|
||||
)
|
||||
(.mov r0-3 f31-0)
|
||||
(.pcgtw v1-3 v1-2 a0-2)
|
||||
)
|
||||
(.mov r0-4 f31-0)
|
||||
(.por v1-4 a1-2 v1-3)
|
||||
(.mov r0-5 f31-0)
|
||||
(.ppach v1-5 r0-5 v1-4)
|
||||
(.mov r0-6 f31-0)
|
||||
(let ((v1-6 (shl (the-as int v1-5) 16)))
|
||||
(nop!)
|
||||
(zero? v1-6)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function instance-tfragment-add-debug-sphere
|
||||
;; Used lq/sq
|
||||
(defun instance-tfragment-add-debug-sphere ((arg0 drawable) (arg1 instance-tie))
|
||||
(local-vars (r0-0 uint128) (v1-1 uint128) (v1-2 uint128) (a3-0 float))
|
||||
(rlet ((vf0 :class vf)
|
||||
(vf10 :class vf)
|
||||
(vf11 :class vf)
|
||||
(vf12 :class vf)
|
||||
(vf9 :class vf)
|
||||
)
|
||||
(init-vf0-vector)
|
||||
(nop!)
|
||||
(let ((v1-0 (the-as uint128 (-> arg1 origin vector4h 3 long))))
|
||||
(.pextlh v1-1 v1-0 r0-0)
|
||||
)
|
||||
(.lvf vf9 (&-> arg0 bsphere quad))
|
||||
(.pw.sra v1-2 v1-1 10)
|
||||
(.lvf vf10 (&-> arg1 bsphere quad))
|
||||
(nop!)
|
||||
(.mov vf12 v1-2)
|
||||
(.itof.vf vf12 vf12)
|
||||
(nop!)
|
||||
(.add.vf vf10 vf10 vf12 :mask #b111)
|
||||
(nop!)
|
||||
(.add.vf vf9 vf9 vf10 :mask #b111)
|
||||
(nop!)
|
||||
(.add.w.vf vf11 vf0 vf9 :mask #b1)
|
||||
(nop!)
|
||||
(.mov a3-0 vf11)
|
||||
(nop!)
|
||||
(let ((a2-0 (new-stack-vector0)))
|
||||
(.svf (&-> a2-0 quad) vf9)
|
||||
(add-debug-sphere
|
||||
#t
|
||||
(bucket-id debug-draw0)
|
||||
a2-0
|
||||
a3-0
|
||||
(new 'static 'rgba :r #x80 :g #x80 :b #x80 :a #x80)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -65,6 +65,85 @@
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro vftoi12.xyzw (dst src)
|
||||
"convert to 20.12 integer. This does the multiply while the number is still
|
||||
a float. This will have issues for very large floats, but it seems like this
|
||||
is how PCSX2 does it as well, so maybe it's right?
|
||||
NOTE: this is the only version of the instruction used in Jak 1, so we
|
||||
don't need to worry about masks."
|
||||
|
||||
`(begin
|
||||
(rlet ((temp :class vf))
|
||||
(set! temp 4096.0)
|
||||
(.mul.x.vf temp ,src temp)
|
||||
(.ftoi.vf ,dst temp)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro vftoi15.xyzw (dst src)
|
||||
"convert to 17.15 integer. This does the multiply while the number is still
|
||||
a float. This will have issues for very large floats, but it seems like this
|
||||
is how PCSX2 does it as well, so maybe it's right?
|
||||
NOTE: this is the only version of the instruction used in Jak 1, so we
|
||||
don't need to worry about masks."
|
||||
|
||||
`(begin
|
||||
(rlet ((temp :class vf))
|
||||
(set! temp 32768.0)
|
||||
(.mul.x.vf temp ,src temp)
|
||||
(.ftoi.vf ,dst temp)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro vitof4.xyzw (dst src)
|
||||
"convert from a 28.4 integer. This does the multiply while the number is still
|
||||
a float. This will have issues for very large floats, but it seems like this
|
||||
is how PCSX2 does it as well, so maybe it's right?
|
||||
NOTE: this is the only version of the instruction used in Jak 1, so we
|
||||
don't need to worry about masks."
|
||||
|
||||
`(begin
|
||||
(rlet ((temp :class vf))
|
||||
(set! temp 0.0625)
|
||||
(.mul.x.vf temp ,src temp)
|
||||
(.ftoi.vf ,dst temp)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro vitof12.xyzw (dst src)
|
||||
"convert from a 20.12 integer. This does the multiply while the number is still
|
||||
a float. This will have issues for very large floats, but it seems like this
|
||||
is how PCSX2 does it as well, so maybe it's right?
|
||||
NOTE: this is the only version of the instruction used in Jak 1, so we
|
||||
don't need to worry about masks."
|
||||
|
||||
`(begin
|
||||
(rlet ((temp :class vf))
|
||||
(set! temp 0.000244140625)
|
||||
(.mul.x.vf temp ,src temp)
|
||||
(.ftoi.vf ,dst temp)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro vitof15.xyzw (dst src)
|
||||
"convert from a 17.15 integer. This does the multiply while the number is still
|
||||
a float. This will have issues for very large floats, but it seems like this
|
||||
is how PCSX2 does it as well, so maybe it's right?
|
||||
NOTE: this is the only version of the instruction used in Jak 1, so we
|
||||
don't need to worry about masks."
|
||||
|
||||
`(begin
|
||||
(rlet ((temp :class vf))
|
||||
(set! temp 0.000030517578125)
|
||||
(.mul.x.vf temp ,src temp)
|
||||
(.ftoi.vf ,dst temp)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; In the original game, init-for-transform stashed a bunch of stuff in registers, to be used by other functions.
|
||||
;; In OpenGOAL, this seems risky so we're going to back up this manually.
|
||||
|
||||
@@ -457,18 +457,33 @@ class Compiler {
|
||||
Val* compile_asm_pw_sll(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pw_srl(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pw_sra(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pextlw(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pextuw(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pcpyud(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pcpyld(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pceqw(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_ppach(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_psubw(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_xorp(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
|
||||
Val* compile_asm_por(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pnor(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pand(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
|
||||
Val* compile_asm_pceqb(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pceqh(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pceqw(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
|
||||
Val* compile_asm_pcgtb(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pcgth(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pcgtw(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
|
||||
Val* compile_asm_pextub(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pextuh(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pextuw(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
|
||||
Val* compile_asm_pextlb(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pextlh(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pextlw(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
|
||||
Val* compile_asm_pcpyud(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_pcpyld(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_ppach(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_psubw(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_asm_xorp(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
|
||||
// Atoms
|
||||
|
||||
// Block
|
||||
|
||||
+63
-5
@@ -1518,9 +1518,21 @@ IR_Int128Math3Asm::IR_Int128Math3Asm(bool use_color,
|
||||
std::string IR_Int128Math3Asm::print() {
|
||||
std::string function = "";
|
||||
switch (m_kind) {
|
||||
case Kind::PEXTLB:
|
||||
function = ".pextlb";
|
||||
break;
|
||||
case Kind::PEXTLH:
|
||||
function = ".pextlh";
|
||||
break;
|
||||
case Kind::PEXTLW:
|
||||
function = ".pextlw";
|
||||
break;
|
||||
case Kind::PEXTUB:
|
||||
function = ".pextub";
|
||||
break;
|
||||
case Kind::PEXTUH:
|
||||
function = ".pextuh";
|
||||
break;
|
||||
case Kind::PEXTUW:
|
||||
function = ".pextuw";
|
||||
break;
|
||||
@@ -1530,11 +1542,26 @@ std::string IR_Int128Math3Asm::print() {
|
||||
case Kind::PCPYUD:
|
||||
function = ".pcpyud";
|
||||
break;
|
||||
case Kind::PSUBW:
|
||||
function = ".psubw";
|
||||
break;
|
||||
case Kind::PCEQB:
|
||||
function = ".pceqb";
|
||||
break;
|
||||
case Kind::PCEQH:
|
||||
function = ".pceqh";
|
||||
break;
|
||||
case Kind::PCEQW:
|
||||
function = ".pceqw";
|
||||
break;
|
||||
case Kind::PSUBW:
|
||||
function = ".psubw";
|
||||
case Kind::PCGTB:
|
||||
function = ".pcgtb";
|
||||
break;
|
||||
case Kind::PCGTH:
|
||||
function = ".pcgth";
|
||||
break;
|
||||
case Kind::PCGTW:
|
||||
function = ".pcgtw";
|
||||
break;
|
||||
case Kind::POR:
|
||||
function = ".por";
|
||||
@@ -1570,14 +1597,30 @@ void IR_Int128Math3Asm::do_codegen(emitter::ObjectGenerator* gen,
|
||||
auto src2 = get_reg_asm(m_src2, allocs, irec, m_use_coloring);
|
||||
|
||||
switch (m_kind) {
|
||||
case Kind::PEXTLW:
|
||||
case Kind::PEXTUB:
|
||||
// NOTE: this is intentionally swapped because x86 and PS2 do this opposite ways.
|
||||
gen->add_instr(IGen::pextlw_swapped(dst, src2, src1), irec);
|
||||
gen->add_instr(IGen::pextub_swapped(dst, src2, src1), irec);
|
||||
break;
|
||||
case Kind::PEXTUH:
|
||||
// NOTE: this is intentionally swapped because x86 and PS2 do this opposite ways.
|
||||
gen->add_instr(IGen::pextuh_swapped(dst, src2, src1), irec);
|
||||
break;
|
||||
case Kind::PEXTUW:
|
||||
// NOTE: this is intentionally swapped because x86 and PS2 do this opposite ways.
|
||||
gen->add_instr(IGen::pextuw_swapped(dst, src2, src1), irec);
|
||||
break;
|
||||
case Kind::PEXTLB:
|
||||
// NOTE: this is intentionally swapped because x86 and PS2 do this opposite ways.
|
||||
gen->add_instr(IGen::pextlb_swapped(dst, src2, src1), irec);
|
||||
break;
|
||||
case Kind::PEXTLH:
|
||||
// NOTE: this is intentionally swapped because x86 and PS2 do this opposite ways.
|
||||
gen->add_instr(IGen::pextlh_swapped(dst, src2, src1), irec);
|
||||
break;
|
||||
case Kind::PEXTLW:
|
||||
// NOTE: this is intentionally swapped because x86 and PS2 do this opposite ways.
|
||||
gen->add_instr(IGen::pextlw_swapped(dst, src2, src1), irec);
|
||||
break;
|
||||
case Kind::PCPYLD:
|
||||
// NOTE: this is intentionally swapped because x86 and PS2 do this opposite ways.
|
||||
gen->add_instr(IGen::pcpyld_swapped(dst, src2, src1), irec);
|
||||
@@ -1585,8 +1628,23 @@ void IR_Int128Math3Asm::do_codegen(emitter::ObjectGenerator* gen,
|
||||
case Kind::PCPYUD:
|
||||
gen->add_instr(IGen::pcpyud(dst, src1, src2), irec);
|
||||
break;
|
||||
case Kind::PCEQB:
|
||||
gen->add_instr(IGen::parallel_compare_e_b(dst, src2, src1), irec);
|
||||
break;
|
||||
case Kind::PCEQH:
|
||||
gen->add_instr(IGen::parallel_compare_e_h(dst, src2, src1), irec);
|
||||
break;
|
||||
case Kind::PCEQW:
|
||||
gen->add_instr(IGen::pceqw(dst, src1, src2), irec);
|
||||
gen->add_instr(IGen::parallel_compare_e_w(dst, src2, src1), irec);
|
||||
break;
|
||||
case Kind::PCGTB:
|
||||
gen->add_instr(IGen::parallel_compare_gt_b(dst, src2, src1), irec);
|
||||
break;
|
||||
case Kind::PCGTH:
|
||||
gen->add_instr(IGen::parallel_compare_gt_h(dst, src2, src1), irec);
|
||||
break;
|
||||
case Kind::PCGTW:
|
||||
gen->add_instr(IGen::parallel_compare_gt_w(dst, src2, src1), irec);
|
||||
break;
|
||||
case Kind::PSUBW:
|
||||
// psubW on mips is psubD on x86...
|
||||
|
||||
+20
-1
@@ -562,7 +562,26 @@ class IR_VFMath3Asm : public IR_Asm {
|
||||
class IR_Int128Math3Asm : public IR_Asm {
|
||||
public:
|
||||
// these are MIPS names, not x86 names.
|
||||
enum class Kind { PEXTLW, PEXTUW, PCPYUD, PCPYLD, PCEQW, PSUBW, POR, PXOR, PAND };
|
||||
enum class Kind {
|
||||
PEXTUB,
|
||||
PEXTUH,
|
||||
PEXTUW,
|
||||
PEXTLB,
|
||||
PEXTLH,
|
||||
PEXTLW,
|
||||
PCPYUD,
|
||||
PCPYLD,
|
||||
PSUBW,
|
||||
PCEQB,
|
||||
PCEQH,
|
||||
PCEQW,
|
||||
PCGTB,
|
||||
PCGTH,
|
||||
PCGTW,
|
||||
POR,
|
||||
PXOR,
|
||||
PAND
|
||||
};
|
||||
IR_Int128Math3Asm(bool use_color,
|
||||
const RegVal* dst,
|
||||
const RegVal* src1,
|
||||
|
||||
@@ -686,14 +686,54 @@ Val* Compiler::compile_asm_pand(const goos::Object& form, const goos::Object& re
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PAND, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pextlw(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PEXTLW, env);
|
||||
Val* Compiler::compile_asm_pceqb(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PCEQB, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pceqh(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PCEQH, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pceqw(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PCEQW, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pcgtb(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PCGTB, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pcgth(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PCGTH, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pcgtw(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PCGTW, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pextub(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PEXTUB, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pextuh(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PEXTUH, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pextuw(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PEXTUW, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pextlb(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PEXTLB, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pextlh(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PEXTLH, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pextlw(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PEXTLW, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pcpyud(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PCPYUD, env);
|
||||
}
|
||||
@@ -702,10 +742,6 @@ Val* Compiler::compile_asm_pcpyld(const goos::Object& form, const goos::Object&
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PCPYLD, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_pceqw(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PCEQW, env);
|
||||
}
|
||||
|
||||
Val* Compiler::compile_asm_psubw(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_asm_int128_math3(form, rest, IR_Int128Math3Asm::Kind::PSUBW, env);
|
||||
}
|
||||
|
||||
@@ -96,8 +96,27 @@ const std::unordered_map<
|
||||
{".pw.sll", &Compiler::compile_asm_pw_sll},
|
||||
{".pw.srl", &Compiler::compile_asm_pw_srl},
|
||||
{".pw.sra", &Compiler::compile_asm_pw_sra},
|
||||
|
||||
{".por", &Compiler::compile_asm_por},
|
||||
{".pnor", &Compiler::compile_asm_pnor},
|
||||
{".pand", &Compiler::compile_asm_pand},
|
||||
|
||||
{".pceqb", &Compiler::compile_asm_pceqb},
|
||||
{".pceqh", &Compiler::compile_asm_pceqh},
|
||||
{".pceqw", &Compiler::compile_asm_pceqw},
|
||||
|
||||
{".pcgtb", &Compiler::compile_asm_pcgtb},
|
||||
{".pcgth", &Compiler::compile_asm_pcgth},
|
||||
{".pcgtw", &Compiler::compile_asm_pcgtw},
|
||||
|
||||
{".pextlb", &Compiler::compile_asm_pextlb},
|
||||
{".pextlh", &Compiler::compile_asm_pextlh},
|
||||
{".pextlw", &Compiler::compile_asm_pextlw},
|
||||
|
||||
{".pextub", &Compiler::compile_asm_pextub},
|
||||
{".pextuh", &Compiler::compile_asm_pextuh},
|
||||
{".pextuw", &Compiler::compile_asm_pextuw},
|
||||
|
||||
{".pcpyld", &Compiler::compile_asm_pcpyld},
|
||||
{".pcpyud", &Compiler::compile_asm_pcpyud},
|
||||
{".pceqw", &Compiler::compile_asm_pceqw},
|
||||
|
||||
+175
-51
@@ -2433,13 +2433,70 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction pextlw_swapped(Register dst, Register src0, Register src1) {
|
||||
static Instruction parallel_bitwise_or(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG 62/r VPUNPCKLDQ xmm1, xmm2, xmm3/m128
|
||||
// VEX.128.66.0F.WIG EB /r VPOR xmm1, xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0x62);
|
||||
Instruction instr(0xEB);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction parallel_bitwise_xor(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG EF /r VPXOR xmm1, xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0xEF);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction parallel_bitwise_and(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG DB /r VPAND xmm1, xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0xDB);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
// Reminder - a word in MIPS = 32bits = a DWORD in x86
|
||||
// MIPS || x86
|
||||
// -----------------------
|
||||
// byte || byte
|
||||
// halfword || word
|
||||
// word || dword
|
||||
// doubleword || quadword
|
||||
|
||||
// -- Unpack High Data Instructions
|
||||
static Instruction pextub_swapped(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG 68/r VPUNPCKHBW xmm1,xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0x68);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction pextuh_swapped(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG 69/r VPUNPCKHWD xmm1,xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0x69);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
@@ -2457,6 +2514,121 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
// -- Unpack Low Data Instructions
|
||||
static Instruction pextlb_swapped(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG 60/r VPUNPCKLBW xmm1,xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0x60);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction pextlh_swapped(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG 61/r VPUNPCKLWD xmm1,xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0x61);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction pextlw_swapped(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG 62/r VPUNPCKLDQ xmm1, xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0x62);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
// Equal to than comparison as 16 bytes (8 bits)
|
||||
static Instruction parallel_compare_e_b(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG 74 /r VPCMPEQB xmm1, xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0x74);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
// Equal to than comparison as 8 halfwords (16 bits)
|
||||
static Instruction parallel_compare_e_h(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG 75 /r VPCMPEQW xmm1, xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0x75);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
// Equal to than comparison as 4 words (32 bits)
|
||||
static Instruction parallel_compare_e_w(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG 76 /r VPCMPEQD xmm1, xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0x76);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
// Greater than comparison as 16 bytes (8 bits)
|
||||
static Instruction parallel_compare_gt_b(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG 64 /r VPCMPGTB xmm1, xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0x64);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
// Greater than comparison as 8 halfwords (16 bits)
|
||||
static Instruction parallel_compare_gt_h(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG 65 /r VPCMPGTW xmm1, xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0x65);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
// Greater than comparison as 4 words (32 bits)
|
||||
static Instruction parallel_compare_gt_w(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG 66 /r VPCMPGTD xmm1, xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0x66);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction vpunpcklqdq(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
@@ -2485,18 +2657,6 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction pceqw(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG 76 /r VPCMPEQD xmm1, xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0x76);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction vpsubd(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
@@ -2552,41 +2712,5 @@ class IGen {
|
||||
instr.set(Imm(1, imm));
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction parallel_bitwise_or(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG EB /r VPOR xmm1, xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0xEB);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction parallel_bitwise_xor(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG EF /r VPXOR xmm1, xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0xEF);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction parallel_bitwise_and(Register dst, Register src0, Register src1) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src0.is_xmm());
|
||||
assert(src1.is_xmm());
|
||||
// VEX.128.66.0F.WIG DB /r VPAND xmm1, xmm2, xmm3/m128
|
||||
// reg, vex, r/m
|
||||
Instruction instr(0xDB);
|
||||
instr.set_vex_modrm_and_rex(dst.hw_id(), src1.hw_id(), VEX3::LeadingBytes::P_0F, src0.hw_id(),
|
||||
false, VexPrefix::P_66);
|
||||
return instr;
|
||||
}
|
||||
};
|
||||
} // namespace emitter
|
||||
|
||||
@@ -233,4 +233,100 @@
|
||||
)
|
||||
`(new 'static 'sound-name :lo ,lo-val :hi ,hi-val)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro vftoi4.xyzw (dst src)
|
||||
"convert to 28.4 integer. This does the multiply while the number is still
|
||||
a float. This will have issues for very large floats, but it seems like this
|
||||
is how PCSX2 does it as well, so maybe it's right?
|
||||
NOTE: this is the only version of the instruction used in Jak 1, so we
|
||||
don't need to worry about masks."
|
||||
|
||||
`(begin
|
||||
(rlet ((temp :class vf))
|
||||
(set! temp 16.0)
|
||||
(.mul.x.vf temp ,src temp)
|
||||
(.ftoi.vf ,dst temp)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro vftoi12.xyzw (dst src)
|
||||
"convert to 20.12 integer. This does the multiply while the number is still
|
||||
a float. This will have issues for very large floats, but it seems like this
|
||||
is how PCSX2 does it as well, so maybe it's right?
|
||||
NOTE: this is the only version of the instruction used in Jak 1, so we
|
||||
don't need to worry about masks."
|
||||
|
||||
`(begin
|
||||
(rlet ((temp :class vf))
|
||||
(set! temp 4096.0)
|
||||
(.mul.x.vf temp ,src temp)
|
||||
(.ftoi.vf ,dst temp)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro vftoi15.xyzw (dst src)
|
||||
"convert to 17.15 integer. This does the multiply while the number is still
|
||||
a float. This will have issues for very large floats, but it seems like this
|
||||
is how PCSX2 does it as well, so maybe it's right?
|
||||
NOTE: this is the only version of the instruction used in Jak 1, so we
|
||||
don't need to worry about masks."
|
||||
|
||||
`(begin
|
||||
(rlet ((temp :class vf))
|
||||
(set! temp 32768.0)
|
||||
(.mul.x.vf temp ,src temp)
|
||||
(.ftoi.vf ,dst temp)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro vitof4.xyzw (dst src)
|
||||
"convert from a 28.4 integer. This does the multiply while the number is still
|
||||
a float. This will have issues for very large floats, but it seems like this
|
||||
is how PCSX2 does it as well, so maybe it's right?
|
||||
NOTE: this is the only version of the instruction used in Jak 1, so we
|
||||
don't need to worry about masks."
|
||||
|
||||
`(begin
|
||||
(rlet ((temp :class vf))
|
||||
(set! temp 0.0625)
|
||||
(.mul.x.vf temp ,src temp)
|
||||
(.ftoi.vf ,dst temp)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro vitof12.xyzw (dst src)
|
||||
"convert from a 20.12 integer. This does the multiply while the number is still
|
||||
a float. This will have issues for very large floats, but it seems like this
|
||||
is how PCSX2 does it as well, so maybe it's right?
|
||||
NOTE: this is the only version of the instruction used in Jak 1, so we
|
||||
don't need to worry about masks."
|
||||
|
||||
`(begin
|
||||
(rlet ((temp :class vf))
|
||||
(set! temp 0.000244140625)
|
||||
(.mul.x.vf temp ,src temp)
|
||||
(.ftoi.vf ,dst temp)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro vitof15.xyzw (dst src)
|
||||
"convert from a 17.15 integer. This does the multiply while the number is still
|
||||
a float. This will have issues for very large floats, but it seems like this
|
||||
is how PCSX2 does it as well, so maybe it's right?
|
||||
NOTE: this is the only version of the instruction used in Jak 1, so we
|
||||
don't need to worry about masks."
|
||||
|
||||
`(begin
|
||||
(rlet ((temp :class vf))
|
||||
(set! temp 0.000030517578125)
|
||||
(.mul.x.vf temp ,src temp)
|
||||
(.ftoi.vf ,dst temp)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -475,7 +475,6 @@
|
||||
;; definition for function transform-point-qword!
|
||||
;; WARN: Inline assembly instruction marked with TODO - [TODO.VCLIP]
|
||||
;; WARN: Unsupported inline assembly instruction kind - [cfc2.i v1, Clipping]
|
||||
;; WARN: Inline assembly instruction marked with TODO - [TODO.VFTOI4]
|
||||
(defun transform-point-qword! ((arg0 vector4w) (arg1 vector))
|
||||
(local-vars (v1-7 int))
|
||||
(rlet ((acc :class vf)
|
||||
@@ -514,7 +513,7 @@
|
||||
(.mul.vf vf23 vf23 Q)
|
||||
(.add.vf vf28 vf28 vf30)
|
||||
(.max.x.vf vf28 vf28 vf0 :mask #b1000)
|
||||
(TODO.VFTOI4 vf28 vf28)
|
||||
(vftoi4.xyzw vf28 vf28)
|
||||
(.svf (&-> arg0 quad) vf28)
|
||||
(zero? (logand v1-7 63))
|
||||
)
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
;;-*-Lisp-*-
|
||||
(in-package goal)
|
||||
|
||||
;; definition for function drawable-sphere-box-intersect?
|
||||
;; WARN: Function may read a register that is not set: f31
|
||||
;; Used lq/sq
|
||||
(defun drawable-sphere-box-intersect? ((arg0 drawable) (arg1 bounding-box4w))
|
||||
(local-vars
|
||||
(r0-0 int)
|
||||
(r0-1 int)
|
||||
(r0-2 uint128)
|
||||
(r0-3 int)
|
||||
(v1-1 uint128)
|
||||
(v1-2 uint128)
|
||||
(v1-3 uint128)
|
||||
(a0-1 uint128)
|
||||
(a1-2 uint128)
|
||||
(a2-0 uint128)
|
||||
(f31-0 none)
|
||||
)
|
||||
(rlet ((vf1 :class vf)
|
||||
(vf2 :class vf)
|
||||
(vf3 :class vf)
|
||||
(vf4 :class vf)
|
||||
)
|
||||
(nop!)
|
||||
(nop!)
|
||||
(.lvf vf1 (&-> arg0 bsphere quad))
|
||||
(.add.w.vf vf2 vf1 vf1 :mask #b111)
|
||||
(let ((v1-0 (-> arg1 min quad)))
|
||||
(.sub.w.vf vf1 vf1 vf1 :mask #b111)
|
||||
(let ((a1-1 (-> arg1 max quad)))
|
||||
(.ftoi.vf vf4 vf2)
|
||||
(nop!)
|
||||
(.ftoi.vf vf3 vf1)
|
||||
(nop!)
|
||||
(.mov a0-1 vf4)
|
||||
(nop!)
|
||||
(.mov a2-0 vf3)
|
||||
(nop!)
|
||||
(.pcgtw a1-2 a2-0 a1-1)
|
||||
)
|
||||
(.mov r0-0 f31-0)
|
||||
(.pcgtw v1-1 v1-0 a0-1)
|
||||
)
|
||||
(.mov r0-1 f31-0)
|
||||
(.por v1-2 a1-2 v1-1)
|
||||
(.mov r0-2 f31-0)
|
||||
(.ppach v1-3 r0-2 v1-2)
|
||||
(.mov r0-3 f31-0)
|
||||
(let ((v1-4 (shl (the-as int v1-3) 16)))
|
||||
(nop!)
|
||||
(zero? v1-4)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function instance-sphere-box-intersect?
|
||||
;; WARN: Function may read a register that is not set: f31
|
||||
;; Used lq/sq
|
||||
(defun
|
||||
instance-sphere-box-intersect?
|
||||
((arg0 drawable) (arg1 instance-tie) (arg2 bounding-box4w))
|
||||
(local-vars
|
||||
(r0-0 uint128)
|
||||
(r0-1 int)
|
||||
(r0-2 uint128)
|
||||
(r0-3 int)
|
||||
(r0-4 int)
|
||||
(r0-5 uint128)
|
||||
(r0-6 int)
|
||||
(v1-3 uint128)
|
||||
(v1-4 uint128)
|
||||
(v1-5 uint128)
|
||||
(a0-2 uint128)
|
||||
(a1-2 uint128)
|
||||
(a2-1 uint128)
|
||||
(a3-1 uint128)
|
||||
(a3-3 uint128)
|
||||
(a3-4 uint128)
|
||||
(t0-1 uint128)
|
||||
(t0-2 uint128)
|
||||
(t1-0 uint128)
|
||||
(t2-1 uint128)
|
||||
(t2-2 uint128)
|
||||
(f31-0 none)
|
||||
)
|
||||
(rlet ((acc :class vf)
|
||||
(vf0 :class vf)
|
||||
(vf1 :class vf)
|
||||
(vf10 :class vf)
|
||||
(vf2 :class vf)
|
||||
(vf3 :class vf)
|
||||
(vf4 :class vf)
|
||||
(vf5 :class vf)
|
||||
(vf6 :class vf)
|
||||
(vf7 :class vf)
|
||||
(vf8 :class vf)
|
||||
(vf9 :class vf)
|
||||
)
|
||||
(init-vf0-vector)
|
||||
(nop!)
|
||||
(let ((v1-0 (-> arg1 max-scale)))
|
||||
(nop!)
|
||||
(let ((a3-0 (the-as uint128 (-> arg1 origin vector4h 3 long))))
|
||||
(nop!)
|
||||
(let ((t2-0 (the-as uint128 (-> arg1 origin vector4h 0 long))))
|
||||
(.pextlh a3-1 a3-0 r0-0)
|
||||
(let ((t0-0 (the-as uint128 (-> arg1 origin vector4h 1 long))))
|
||||
(.pw.sra t1-0 a3-1 10)
|
||||
(let ((a3-2 (the-as uint128 (-> arg1 origin vector4h 2 long))))
|
||||
(.pextlh t2-1 t2-0 r0-0)
|
||||
(.mov r0-1 f31-0)
|
||||
(.pw.sra t2-2 t2-1 16)
|
||||
(.mov r0-2 f31-0)
|
||||
(.pextlh t0-1 t0-0 r0-2)
|
||||
(.mov vf8 t1-0)
|
||||
(.pw.sra t0-2 t0-1 16)
|
||||
(.mov vf5 t2-2)
|
||||
(.pextlh a3-3 a3-2 r0-2)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(.mov vf6 t0-2)
|
||||
(.pw.sra a3-4 a3-3 16)
|
||||
(.lvf vf9 (&-> arg1 bsphere quad))
|
||||
(nop!)
|
||||
(.mov vf7 a3-4)
|
||||
(nop!)
|
||||
(.mov vf10 v1-0)
|
||||
)
|
||||
(.itof.vf vf8 vf8)
|
||||
(nop!)
|
||||
(vitof12.xyzw vf5 vf5)
|
||||
(nop!)
|
||||
(vitof12.xyzw vf6 vf6)
|
||||
(nop!)
|
||||
(vitof12.xyzw vf7 vf7)
|
||||
(nop!)
|
||||
(.add.vf vf8 vf8 vf9 :mask #b111)
|
||||
(nop!)
|
||||
(nop!)
|
||||
(.lvf vf9 (&-> arg0 bsphere quad))
|
||||
(vitof12.xyzw vf10 vf10)
|
||||
(nop!)
|
||||
(.mul.w.vf vf10 vf10 vf9 :mask #b1)
|
||||
(nop!)
|
||||
(.mul.x.vf acc vf5 vf9)
|
||||
(nop!)
|
||||
(.add.mul.y.vf acc vf6 vf9 acc)
|
||||
(let ((v1-2 (-> arg2 min quad)))
|
||||
(.add.mul.z.vf acc vf7 vf9 acc)
|
||||
(let ((a1-1 (-> arg2 max quad)))
|
||||
(.add.mul.w.vf vf1 vf8 vf0 acc)
|
||||
(nop!)
|
||||
(.add.x.vf vf2 vf1 vf10 :mask #b111)
|
||||
(nop!)
|
||||
(.sub.x.vf vf1 vf1 vf10 :mask #b111)
|
||||
(nop!)
|
||||
(.ftoi.vf vf4 vf2)
|
||||
(nop!)
|
||||
(.ftoi.vf vf3 vf1)
|
||||
(nop!)
|
||||
(.mov a0-2 vf4)
|
||||
(nop!)
|
||||
(.mov a2-1 vf3)
|
||||
(nop!)
|
||||
(.pcgtw a1-2 a2-1 a1-1)
|
||||
)
|
||||
(.mov r0-3 f31-0)
|
||||
(.pcgtw v1-3 v1-2 a0-2)
|
||||
)
|
||||
(.mov r0-4 f31-0)
|
||||
(.por v1-4 a1-2 v1-3)
|
||||
(.mov r0-5 f31-0)
|
||||
(.ppach v1-5 r0-5 v1-4)
|
||||
(.mov r0-6 f31-0)
|
||||
(let ((v1-6 (shl (the-as int v1-5) 16)))
|
||||
(nop!)
|
||||
(zero? v1-6)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function instance-tfragment-add-debug-sphere
|
||||
;; Used lq/sq
|
||||
(defun instance-tfragment-add-debug-sphere ((arg0 drawable) (arg1 instance-tie))
|
||||
(local-vars (r0-0 uint128) (v1-1 uint128) (v1-2 uint128) (a3-0 float))
|
||||
(rlet ((vf0 :class vf)
|
||||
(vf10 :class vf)
|
||||
(vf11 :class vf)
|
||||
(vf12 :class vf)
|
||||
(vf9 :class vf)
|
||||
)
|
||||
(init-vf0-vector)
|
||||
(nop!)
|
||||
(let ((v1-0 (the-as uint128 (-> arg1 origin vector4h 3 long))))
|
||||
(.pextlh v1-1 v1-0 r0-0)
|
||||
)
|
||||
(.lvf vf9 (&-> arg0 bsphere quad))
|
||||
(.pw.sra v1-2 v1-1 10)
|
||||
(.lvf vf10 (&-> arg1 bsphere quad))
|
||||
(nop!)
|
||||
(.mov vf12 v1-2)
|
||||
(.itof.vf vf12 vf12)
|
||||
(nop!)
|
||||
(.add.vf vf10 vf10 vf12 :mask #b111)
|
||||
(nop!)
|
||||
(.add.vf vf9 vf9 vf10 :mask #b111)
|
||||
(nop!)
|
||||
(.add.w.vf vf11 vf0 vf9 :mask #b1)
|
||||
(nop!)
|
||||
(.mov a3-0 vf11)
|
||||
(nop!)
|
||||
(let ((a2-0 (new-stack-vector0)))
|
||||
(.svf (&-> a2-0 quad) vf9)
|
||||
(add-debug-sphere
|
||||
#t
|
||||
(bucket-id debug-draw0)
|
||||
a2-0
|
||||
a3-0
|
||||
(new 'static 'rgba :r #x80 :g #x80 :b #x80 :a #x80)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -667,6 +667,8 @@ TEST_F(WithGameTests, I128Simple) {
|
||||
"12344321\n"});
|
||||
}
|
||||
|
||||
// TODO - add tests
|
||||
|
||||
TEST_F(WithGameTests, Pextlw) {
|
||||
runner.run_static_test(env, testCategory, "test-pextlw.gc",
|
||||
{"#x07060504171615140302010013121110\n"
|
||||
|
||||
+151
-16
@@ -373,6 +373,126 @@ TEST(EmitterAVX, VPSLLD) {
|
||||
EXPECT_EQ(tester.dump_to_hex_string(true), "C5E172F403C4C16172F604C59172F405C4C11172F606");
|
||||
}
|
||||
|
||||
TEST(EmitterAVX, VPCMPEQB) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(1024);
|
||||
tester.emit(IGen::parallel_compare_e_b(XMM0 + 3, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_e_b(XMM0 + 3, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_e_b(XMM0 + 3, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_e_b(XMM0 + 3, XMM0 + 13, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_e_b(XMM0 + 13, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_e_b(XMM0 + 13, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_e_b(XMM0 + 13, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_e_b(XMM0 + 13, XMM0 + 13, XMM0 + 13));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(true),
|
||||
"C5E174DBC4C16174DDC59174DBC4C11174DDC56174EBC4416174EDC51174EBC4411174ED");
|
||||
}
|
||||
|
||||
TEST(EmitterAVX, VPCMPEQW) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(1024);
|
||||
tester.emit(IGen::parallel_compare_e_h(XMM0 + 3, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_e_h(XMM0 + 3, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_e_h(XMM0 + 3, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_e_h(XMM0 + 3, XMM0 + 13, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_e_h(XMM0 + 13, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_e_h(XMM0 + 13, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_e_h(XMM0 + 13, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_e_h(XMM0 + 13, XMM0 + 13, XMM0 + 13));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(true),
|
||||
"C5E175DBC4C16175DDC59175DBC4C11175DDC56175EBC4416175EDC51175EBC4411175ED");
|
||||
}
|
||||
|
||||
TEST(EmitterAVX, VPCMPEQD) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(1024);
|
||||
tester.emit(IGen::parallel_compare_e_w(XMM0 + 3, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_e_w(XMM0 + 3, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_e_w(XMM0 + 3, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_e_w(XMM0 + 3, XMM0 + 13, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_e_w(XMM0 + 13, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_e_w(XMM0 + 13, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_e_w(XMM0 + 13, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_e_w(XMM0 + 13, XMM0 + 13, XMM0 + 13));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(true),
|
||||
"C5E176DBC4C16176DDC59176DBC4C11176DDC56176EBC4416176EDC51176EBC4411176ED");
|
||||
}
|
||||
|
||||
TEST(EmitterAVX, VPCMPGTB) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(1024);
|
||||
tester.emit(IGen::parallel_compare_gt_b(XMM0 + 3, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_gt_b(XMM0 + 3, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_gt_b(XMM0 + 3, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_gt_b(XMM0 + 3, XMM0 + 13, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_gt_b(XMM0 + 13, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_gt_b(XMM0 + 13, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_gt_b(XMM0 + 13, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_gt_b(XMM0 + 13, XMM0 + 13, XMM0 + 13));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(true),
|
||||
"C5E164DBC4C16164DDC59164DBC4C11164DDC56164EBC4416164EDC51164EBC4411164ED");
|
||||
}
|
||||
|
||||
TEST(EmitterAVX, VPCMPGTW) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(1024);
|
||||
tester.emit(IGen::parallel_compare_gt_h(XMM0 + 3, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_gt_h(XMM0 + 3, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_gt_h(XMM0 + 3, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_gt_h(XMM0 + 3, XMM0 + 13, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_gt_h(XMM0 + 13, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_gt_h(XMM0 + 13, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_gt_h(XMM0 + 13, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_gt_h(XMM0 + 13, XMM0 + 13, XMM0 + 13));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(true),
|
||||
"C5E165DBC4C16165DDC59165DBC4C11165DDC56165EBC4416165EDC51165EBC4411165ED");
|
||||
}
|
||||
|
||||
TEST(EmitterAVX, VPCMPGTD) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(1024);
|
||||
tester.emit(IGen::parallel_compare_gt_w(XMM0 + 3, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_gt_w(XMM0 + 3, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_gt_w(XMM0 + 3, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_gt_w(XMM0 + 3, XMM0 + 13, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_gt_w(XMM0 + 13, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_gt_w(XMM0 + 13, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::parallel_compare_gt_w(XMM0 + 13, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::parallel_compare_gt_w(XMM0 + 13, XMM0 + 13, XMM0 + 13));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(true),
|
||||
"C5E166DBC4C16166DDC59166DBC4C11166DDC56166EBC4416166EDC51166EBC4411166ED");
|
||||
}
|
||||
|
||||
TEST(EmitterAVX, VPUNPCKLBW) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(1024);
|
||||
tester.emit(IGen::pextlb_swapped(XMM0 + 3, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::pextlb_swapped(XMM0 + 3, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::pextlb_swapped(XMM0 + 3, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::pextlb_swapped(XMM0 + 3, XMM0 + 13, XMM0 + 13));
|
||||
tester.emit(IGen::pextlb_swapped(XMM0 + 13, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::pextlb_swapped(XMM0 + 13, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::pextlb_swapped(XMM0 + 13, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::pextlb_swapped(XMM0 + 13, XMM0 + 13, XMM0 + 13));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(true),
|
||||
"C5E160DBC4C16160DDC59160DBC4C11160DDC56160EBC4416160EDC51160EBC4411160ED");
|
||||
}
|
||||
|
||||
TEST(EmitterAVX, VPUNPCKLWD) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(1024);
|
||||
tester.emit(IGen::pextlh_swapped(XMM0 + 3, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::pextlh_swapped(XMM0 + 3, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::pextlh_swapped(XMM0 + 3, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::pextlh_swapped(XMM0 + 3, XMM0 + 13, XMM0 + 13));
|
||||
tester.emit(IGen::pextlh_swapped(XMM0 + 13, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::pextlh_swapped(XMM0 + 13, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::pextlh_swapped(XMM0 + 13, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::pextlh_swapped(XMM0 + 13, XMM0 + 13, XMM0 + 13));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(true),
|
||||
"C5E161DBC4C16161DDC59161DBC4C11161DDC56161EBC4416161EDC51161EBC4411161ED");
|
||||
}
|
||||
|
||||
TEST(EmitterAVX, VPUNPCKLDQ) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(1024);
|
||||
@@ -388,6 +508,36 @@ TEST(EmitterAVX, VPUNPCKLDQ) {
|
||||
"C5E162DBC4C16162DDC59162DBC4C11162DDC56162EBC4416162EDC51162EBC4411162ED");
|
||||
}
|
||||
|
||||
TEST(EmitterAVX, VPUNPCKHBW) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(1024);
|
||||
tester.emit(IGen::pextub_swapped(XMM0 + 3, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::pextub_swapped(XMM0 + 3, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::pextub_swapped(XMM0 + 3, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::pextub_swapped(XMM0 + 3, XMM0 + 13, XMM0 + 13));
|
||||
tester.emit(IGen::pextub_swapped(XMM0 + 13, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::pextub_swapped(XMM0 + 13, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::pextub_swapped(XMM0 + 13, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::pextub_swapped(XMM0 + 13, XMM0 + 13, XMM0 + 13));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(true),
|
||||
"C5E168DBC4C16168DDC59168DBC4C11168DDC56168EBC4416168EDC51168EBC4411168ED");
|
||||
}
|
||||
|
||||
TEST(EmitterAVX, VPUNPCKHWD) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(1024);
|
||||
tester.emit(IGen::pextuh_swapped(XMM0 + 3, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::pextuh_swapped(XMM0 + 3, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::pextuh_swapped(XMM0 + 3, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::pextuh_swapped(XMM0 + 3, XMM0 + 13, XMM0 + 13));
|
||||
tester.emit(IGen::pextuh_swapped(XMM0 + 13, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::pextuh_swapped(XMM0 + 13, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::pextuh_swapped(XMM0 + 13, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::pextuh_swapped(XMM0 + 13, XMM0 + 13, XMM0 + 13));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(true),
|
||||
"C5E169DBC4C16169DDC59169DBC4C11169DDC56169EBC4416169EDC51169EBC4411169ED");
|
||||
}
|
||||
|
||||
TEST(EmitterAVX, VPUNPCKHDQ) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(1024);
|
||||
@@ -433,21 +583,6 @@ TEST(EmitterAVX, VPUNPCKHQDQ) {
|
||||
"C5E16DDBC4C1616DDDC5916DDBC4C1116DDDC5616DEBC441616DEDC5116DEBC441116DED");
|
||||
}
|
||||
|
||||
TEST(EmitterAVX, VPCMPEQD) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(1024);
|
||||
tester.emit(IGen::pceqw(XMM0 + 3, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::pceqw(XMM0 + 3, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::pceqw(XMM0 + 3, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::pceqw(XMM0 + 3, XMM0 + 13, XMM0 + 13));
|
||||
tester.emit(IGen::pceqw(XMM0 + 13, XMM0 + 3, XMM0 + 3));
|
||||
tester.emit(IGen::pceqw(XMM0 + 13, XMM0 + 3, XMM0 + 13));
|
||||
tester.emit(IGen::pceqw(XMM0 + 13, XMM0 + 13, XMM0 + 3));
|
||||
tester.emit(IGen::pceqw(XMM0 + 13, XMM0 + 13, XMM0 + 13));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(true),
|
||||
"C5E176DBC4C16176DDC59176DBC4C11176DDC56176EBC4416176EDC51176EBC4411176ED");
|
||||
}
|
||||
|
||||
TEST(EmitterAVX, VPSRLDQ) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(1024);
|
||||
@@ -566,4 +701,4 @@ TEST(EmitterAVX, VPAND) {
|
||||
tester.emit(IGen::parallel_bitwise_and(XMM0 + 13, XMM0 + 13, XMM0 + 13));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(true),
|
||||
"C5E1DBDBC4C161DBDDC591DBDBC4C111DBDDC561DBEBC44161DBEDC511DBEBC44111DBED");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user