[GEN_OPCODE_AVG] = { .name = "avg", .nsrc = 2, .ndst = 1 },
[GEN_OPCODE_ADD] = { .name = "add", .nsrc = 2, .ndst = 1 },
[GEN_OPCODE_ADDC] = { .name = "addc", .nsrc = 2, .ndst = 1 },
+ [GEN_OPCODE_SUBB] = { .name = "subb", .nsrc = 2, .ndst = 1 },
[GEN_OPCODE_SEL] = { .name = "sel", .nsrc = 2, .ndst = 1 },
[GEN_OPCODE_AND] = { .name = "and", .nsrc = 2, .ndst = 1 },
[GEN_OPCODE_OR] = { .name = "or", .nsrc = 2, .ndst = 1 },
}
}
+ void GenContext::loadTopHalf(GenRegister dest, GenRegister src) {
+ int execWidth = p->curr.execWidth;
+ src = src.top_half();
+ p->push();
+ p->curr.predicate = GEN_PREDICATE_NONE;
+ p->curr.execWidth = 8;
+ p->MOV(dest, src);
+ p->MOV(GenRegister::suboffset(dest, 4), GenRegister::suboffset(src, 8));
+ if (execWidth == 16) {
+ p->MOV(GenRegister::suboffset(dest, 8), GenRegister::suboffset(src, 16));
+ p->MOV(GenRegister::suboffset(dest, 12), GenRegister::suboffset(src, 24));
+ }
+ p->pop();
+ }
+
+ void GenContext::storeTopHalf(GenRegister dest, GenRegister src) {
+ int execWidth = p->curr.execWidth;
+ dest = dest.top_half();
+ p->push();
+ p->curr.execWidth = 8;
+ p->MOV(dest, src);
+ p->curr.nibControl = 1;
+ p->MOV(GenRegister::suboffset(dest, 8), GenRegister::suboffset(src, 4));
+ if (execWidth == 16) {
+ p->curr.quarterControl = 1;
+ p->curr.nibControl = 0;
+ p->MOV(GenRegister::suboffset(dest, 16), GenRegister::suboffset(src, 8));
+ p->curr.nibControl = 1;
+ p->MOV(GenRegister::suboffset(dest, 24), GenRegister::suboffset(src, 12));
+ }
+ p->pop();
+ }
+
+ void GenContext::loadBottomHalf(GenRegister dest, GenRegister src) {
+ int execWidth = p->curr.execWidth;
+ src = src.bottom_half();
+ p->push();
+ p->curr.predicate = GEN_PREDICATE_NONE;
+ p->curr.execWidth = 8;
+ p->MOV(dest, src);
+ p->MOV(GenRegister::suboffset(dest, 4), GenRegister::suboffset(src, 8));
+ if (execWidth == 16) {
+ p->MOV(GenRegister::suboffset(dest, 8), GenRegister::suboffset(src, 16));
+ p->MOV(GenRegister::suboffset(dest, 12), GenRegister::suboffset(src, 24));
+ }
+ p->pop();
+ }
+
+ void GenContext::storeBottomHalf(GenRegister dest, GenRegister src) {
+ int execWidth = p->curr.execWidth;
+ dest = dest.bottom_half();
+ p->push();
+ p->curr.execWidth = 8;
+ p->MOV(dest, src);
+ p->curr.nibControl = 1;
+ p->MOV(GenRegister::suboffset(dest, 8), GenRegister::suboffset(src, 4));
+ if (execWidth == 16) {
+ p->curr.quarterControl = 1;
+ p->curr.nibControl = 0;
+ p->MOV(GenRegister::suboffset(dest, 16), GenRegister::suboffset(src, 8));
+ p->curr.nibControl = 1;
+ p->MOV(GenRegister::suboffset(dest, 24), GenRegister::suboffset(src, 12));
+ }
+ p->pop();
+ }
+
+ void GenContext::addWithCarry(GenRegister dest, GenRegister src0, GenRegister src1) {
+ int execWidth = p->curr.execWidth;
+ GenRegister acc0 = GenRegister::retype(GenRegister::acc(), GEN_TYPE_D);
+ p->push();
+ p->curr.predicate = GEN_PREDICATE_NONE;
+ p->curr.execWidth = 8;
+ p->ADDC(dest, src0, src1);
+ p->MOV(src1, acc0);
+ if (execWidth == 16) {
+ p->ADDC(GenRegister::suboffset(dest, 8),
+ GenRegister::suboffset(src0, 8),
+ GenRegister::suboffset(src1, 8));
+ p->MOV(GenRegister::suboffset(src1, 8), acc0);
+ }
+ p->pop();
+ }
+
+ void GenContext::subWithBorrow(GenRegister dest, GenRegister src0, GenRegister src1) {
+ int execWidth = p->curr.execWidth;
+ GenRegister acc0 = GenRegister::retype(GenRegister::acc(), GEN_TYPE_D);
+ p->push();
+ p->curr.predicate = GEN_PREDICATE_NONE;
+ p->curr.execWidth = 8;
+ p->SUBB(dest, src0, src1);
+ p->MOV(src1, acc0);
+ if (execWidth == 16) {
+ p->SUBB(GenRegister::suboffset(dest, 8),
+ GenRegister::suboffset(src0, 8),
+ GenRegister::suboffset(src1, 8));
+ p->MOV(GenRegister::suboffset(src1, 8), acc0);
+ }
+ p->pop();
+ }
+
void GenContext::emitTernaryInstruction(const SelectionInstruction &insn) {
const GenRegister dst = ra->genReg(insn.dst(0));
const GenRegister src0 = ra->genReg(insn.src(0));
const GenRegister src1 = ra->genReg(insn.src(1));
const GenRegister src2 = ra->genReg(insn.src(2));
switch (insn.opcode) {
+ case SEL_OP_I64ADD:
+ {
+ GenRegister x = GenRegister::retype(src2, GEN_TYPE_UD),
+ y = GenRegister::suboffset(x, p->curr.execWidth);
+ loadBottomHalf(x, src0);
+ loadBottomHalf(y, src1);
+ addWithCarry(x, x, y);
+ storeBottomHalf(dst, x);
+ loadTopHalf(x, src0);
+ p->ADD(x, x, y);
+ loadTopHalf(y, src1);
+ p->ADD(x, x, y);
+ storeTopHalf(dst, x);
+ }
+ break;
+ case SEL_OP_I64SUB:
+ {
+ GenRegister x = GenRegister::retype(src2, GEN_TYPE_UD),
+ y = GenRegister::suboffset(x, p->curr.execWidth);
+ loadBottomHalf(x, src0);
+ loadBottomHalf(y, src1);
+ subWithBorrow(x, x, y);
+ storeBottomHalf(dst, x);
+ loadTopHalf(x, src0);
+ subWithBorrow(x, x, y);
+ loadTopHalf(y, src1);
+ subWithBorrow(x, x, y);
+ storeTopHalf(dst, x);
+ }
+ break;
case SEL_OP_MUL_HI:
{
int w = p->curr.execWidth;
#include "backend/context.hpp"
#include "backend/program.h"
+#include "backend/gen_register.hpp"
#include "ir/function.hpp"
#include "ir/liveness.hpp"
#include "sys/map.hpp"
INLINE const ir::Liveness::LiveOut &getLiveOut(const ir::BasicBlock *bb) const {
return this->liveness->getLiveOut(bb);
}
+
+ void loadTopHalf(GenRegister dest, GenRegister src);
+ void storeTopHalf(GenRegister dest, GenRegister src);
+
+ void loadBottomHalf(GenRegister dest, GenRegister src);
+ void storeBottomHalf(GenRegister dest, GenRegister src);
+
+ void addWithCarry(GenRegister dest, GenRegister src0, GenRegister src1);
+ void subWithBorrow(GenRegister dest, GenRegister src0, GenRegister src1);
+
/*! Final Gen ISA emission helper functions */
void emitLabelInstruction(const SelectionInstruction &insn);
void emitUnaryInstruction(const SelectionInstruction &insn);
GEN_OPCODE_FBH = 75,
GEN_OPCODE_FBL = 76,
GEN_OPCODE_ADDC = 78,
+ GEN_OPCODE_SUBB = 79,
GEN_OPCODE_SAD2 = 80,
GEN_OPCODE_SADA2 = 81,
GEN_OPCODE_DP4 = 84,
#define GEN_TYPE_V 6 /* packed int vector, immediates only, uword dest only */
#define GEN_TYPE_DF 6
#define GEN_TYPE_F 7
+#define GEN_TYPE_UL 8
+#define GEN_TYPE_L 9
#define GEN_ARF_NULL 0x00
#define GEN_ARF_ADDRESS 0x10
ALU2(MACH)
ALU3(MAD)
+ void GenEncoder::SUBB(GenRegister dest, GenRegister src0, GenRegister src1) {
+ push();
+ curr.accWrEnable = 1;
+ alu2(this, GEN_OPCODE_SUBB, dest, src0, src1);
+ pop();
+ }
+
void GenEncoder::ADDC(GenRegister dest, GenRegister src0, GenRegister src1) {
push();
curr.accWrEnable = 1;
ALU1(MOV)
ALU1(FBH)
ALU1(FBL)
+ ALU2(SUBB)
ALU2(UPSAMPLE_SHORT)
ALU2(UPSAMPLE_INT)
ALU1(RNDZ)
case TYPE_U16: return GEN_TYPE_UW;
case TYPE_S32: return GEN_TYPE_D;
case TYPE_U32: return GEN_TYPE_UD;
+ case TYPE_S64: return GEN_TYPE_L;
+ case TYPE_U64: return GEN_TYPE_UL;
case TYPE_FLOAT: return GEN_TYPE_F;
case TYPE_DOUBLE: return GEN_TYPE_DF;
default: NOT_SUPPORTED; return GEN_TYPE_F;
ALU2(RSL)
ALU2(ASR)
ALU2(ADD)
+ ALU3(I64ADD)
+ ALU3(I64SUB)
ALU2(MUL)
ALU1(FRC)
ALU1(RNDD)
using namespace ir;
const auto &childInsn = cast<LoadImmInstruction>(insn);
const auto &imm = childInsn.getImmediate();
- if(imm.type != TYPE_DOUBLE)
+ if(imm.type != TYPE_DOUBLE && imm.type != TYPE_S64 && imm.type != TYPE_U64)
return true;
return false;
}
// Output the binary instruction
switch (opcode) {
- case OP_ADD: sel.ADD(dst, src0, src1); break;
+ case OP_ADD:
+ if (type == Type::TYPE_U64 || type == Type::TYPE_S64) {
+ GenRegister t = sel.selReg(sel.reg(RegisterFamily::FAMILY_QWORD), Type::TYPE_S64);
+ sel.I64ADD(dst, src0, src1, t);
+ } else
+ sel.ADD(dst, src0, src1);
+ break;
case OP_ADDSAT:
sel.push();
sel.curr.saturate = GEN_MATH_SATURATE_SATURATE;
case OP_XOR: sel.XOR(dst, src0, src1); break;
case OP_OR: sel.OR(dst, src0, src1); break;
case OP_AND: sel.AND(dst, src0, src1); break;
- case OP_SUB: sel.ADD(dst, src0, GenRegister::negate(src1)); break;
+ case OP_SUB:
+ if (type == Type::TYPE_U64 || type == Type::TYPE_S64) {
+ GenRegister t = sel.selReg(sel.reg(RegisterFamily::FAMILY_QWORD), Type::TYPE_S64);
+ sel.I64SUB(dst, src0, src1, t);
+ } else
+ sel.ADD(dst, src0, GenRegister::negate(src1));
+ break;
case OP_SUBSAT:
sel.push();
sel.curr.saturate = GEN_MATH_SATURATE_SATURATE;
DECL_SELECTION_IR(RSL, BinaryInstruction)
DECL_SELECTION_IR(ASR, BinaryInstruction)
DECL_SELECTION_IR(ADD, BinaryInstruction)
+DECL_SELECTION_IR(I64ADD, TernaryInstruction)
+DECL_SELECTION_IR(I64SUB, TernaryInstruction)
DECL_SELECTION_IR(MUL, BinaryInstruction)
DECL_SELECTION_IR(ATOMIC, AtomicInstruction)
DECL_SELECTION_IR(MACH, BinaryInstruction)
INLINE int typeSize(uint32_t type) {
switch(type) {
case GEN_TYPE_DF:
+ case GEN_TYPE_UL:
+ case GEN_TYPE_L:
return 8;
case GEN_TYPE_UD:
case GEN_TYPE_D:
return r;
}
+ INLINE bool isint64(void) const {
+ if ((type == GEN_TYPE_UL || type == GEN_TYPE_L) && file == GEN_GENERAL_REGISTER_FILE)
+ return true;
+ return false;
+ }
+
INLINE bool isimmdf(void) const {
if (type == GEN_TYPE_DF && file == GEN_IMMEDIATE_VALUE)
return true;
return false;
}
+ INLINE GenRegister top_half(void) const {
+ GenRegister r = bottom_half();
+ r.subnr += 4;
+ return r;
+ }
+
+ INLINE GenRegister bottom_half(void) const {
+ GBE_ASSERT(isint64());
+ GenRegister r = *this;
+ r.type = type == GEN_TYPE_UL ? GEN_TYPE_UD : GEN_TYPE_D;
+ r.hstride = GEN_HORIZONTAL_STRIDE_2;
+ return r;
+ }
+
INLINE bool isdf(void) const {
if (type == GEN_TYPE_DF && file == GEN_GENERAL_REGISTER_FILE)
return true;
--- /dev/null
+kernel void compiler_long(global long *src1, global long *src2, global long *dst) {
+ int i = get_global_id(0);
+ if(i < 5)
+ dst[i] = src1[i] + src2[i];
+ if(i > 5)
+ dst[i] = src1[i] - src2[i];
+}
compiler_double_2.cpp
compiler_double_3.cpp
compiler_double_4.cpp
+ compiler_long.cpp
utest_assert.cpp
utest.cpp
utest_file_map.cpp
--- /dev/null
+#include <cstdint>
+#include <cstring>
+#include <iostream>
+#include "utest_helper.hpp"
+
+void compiler_long(void)
+{
+ const size_t n = 16;
+ int64_t src1[n], src2[n];
+
+ // Setup kernel and buffers
+ OCL_CREATE_KERNEL("compiler_long");
+ OCL_CREATE_BUFFER(buf[0], 0, n * sizeof(int64_t), NULL);
+ OCL_CREATE_BUFFER(buf[1], 0, n * sizeof(int64_t), NULL);
+ OCL_CREATE_BUFFER(buf[2], 0, n * sizeof(int64_t), NULL);
+ OCL_SET_ARG(0, sizeof(cl_mem), &buf[0]);
+ OCL_SET_ARG(1, sizeof(cl_mem), &buf[1]);
+ OCL_SET_ARG(2, sizeof(cl_mem), &buf[2]);
+ globals[0] = n;
+ locals[0] = 16;
+
+ // Run random tests
+ src1[0] = -1L, src2[0] = -1L;
+ src1[1] = 0x8000000000000000UL, src2[1] = 0x8000000000000000UL;
+ src1[2] = 0x7FFFFFFFFFFFFFFFL, src2[2] = 1L;
+ src1[3] = 0xFFFFFFFEL, src2[3] = 1L;
+ src1[4] = 0x7FFFFFFFL, src2[4] = 0x80000000L;
+ src1[5] = 0, src2[5] = 0;
+ src1[6] = 0, src2[6] = 1;
+ src1[7] = -2L, src2[7] = -1L;
+ src1[8] = 0, src2[8] = 0x8000000000000000UL;
+ for (int32_t i = 9; i < (int32_t) n; ++i) {
+ src1[i] = ((long)rand() << 32) + rand();
+ src2[i] = ((long)rand() << 32) + rand();
+ }
+ OCL_MAP_BUFFER(0);
+ OCL_MAP_BUFFER(1);
+ memcpy(buf_data[0], src1, sizeof(src1));
+ memcpy(buf_data[1], src2, sizeof(src2));
+ OCL_UNMAP_BUFFER(0);
+ OCL_UNMAP_BUFFER(1);
+
+ // Run the kernel on GPU
+ OCL_NDRANGE(1);
+
+ // Compare
+ OCL_MAP_BUFFER(2);
+ for (int32_t i = 0; i < (int32_t) n; ++i) {
+ //printf("%lx\n", ((int64_t *)buf_data[2])[i]);
+ if (i < 5)
+ OCL_ASSERT(src1[i] + src2[i] == ((int64_t *)buf_data[2])[i]);
+ if (i > 5)
+ OCL_ASSERT(src1[i] - src2[i] == ((int64_t *)buf_data[2])[i]);
+ }
+ OCL_UNMAP_BUFFER(2);
+}
+
+MAKE_UTEST_FROM_FUNCTION(compiler_long);