llvm-project/clang/utils/TableGen/NeonEmitter.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

2488 lines
75 KiB
C++
Raw Normal View History

//===- NeonEmitter.cpp - Generate arm_neon.h for use with clang -*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This tablegen backend is responsible for emitting arm_neon.h, which includes
// a declaration and definition of each function specified by the ARM NEON
// compiler interface. See ARM document DUI0348B.
//
// Each NEON instruction is implemented in terms of 1 or more functions which
// are suffixed with the element type of the input vectors. Functions may be
// implemented in terms of generic vector operations such as +, *, -, etc. or
// by calling a __builtin_-prefixed function which will be handled by clang's
// CodeGen library.
//
// Additional validation code can be generated by this file when runHeader() is
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// called, rather than the normal run() entry point.
//
// See also the documentation in include/clang/Basic/arm_neon.td.
//
//===----------------------------------------------------------------------===//
#include "TableGenBackends.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
#include "llvm/TableGen/SetTheory.h"
#include <algorithm>
#include <cassert>
#include <cctype>
#include <cstddef>
#include <cstdint>
#include <deque>
#include <map>
#include <set>
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
#include <sstream>
#include <string>
#include <utility>
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
#include <vector>
using namespace llvm;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
namespace {
// While globals are generally bad, this one allows us to perform assertions
// liberally and somehow still trace them back to the def they indirectly
// came from.
static Record *CurrentRecord = nullptr;
static void assert_with_loc(bool Assertion, const std::string &Str) {
if (!Assertion) {
if (CurrentRecord)
PrintFatalError(CurrentRecord->getLoc(), Str);
else
PrintFatalError(Str);
}
}
enum ClassKind {
ClassNone,
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
ClassI, // generic integer instruction, e.g., "i8" suffix
ClassS, // signed/unsigned/poly, e.g., "s8", "u8" or "p8" suffix
ClassW, // width-specific instruction, e.g., "8" suffix
ClassB, // bitcast arguments with enum argument to specify type
ClassL, // Logical instructions which are op instructions
// but we need to not emit any suffix for in our
// tests.
ClassNoTest // Instructions which we do not test since they are
// not TRUE instructions.
};
/// NeonTypeFlags - Flags to identify the types for overloaded Neon
/// builtins. These must be kept in sync with the flags in
/// include/clang/Basic/TargetBuiltins.h.
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
namespace NeonTypeFlags {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
enum { EltTypeMask = 0xf, UnsignedFlag = 0x10, QuadFlag = 0x20 };
enum EltType {
Int8,
Int16,
Int32,
Int64,
Poly8,
Poly16,
Poly64,
Poly128,
Float16,
Float32,
Float64
};
} // end namespace NeonTypeFlags
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
class NeonEmitter;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
//===----------------------------------------------------------------------===//
// TypeSpec
//===----------------------------------------------------------------------===//
/// A TypeSpec is just a simple wrapper around a string, but gets its own type
/// for strong typing purposes.
///
/// A TypeSpec can be used to create a type.
class TypeSpec : public std::string {
public:
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
static std::vector<TypeSpec> fromTypeSpecs(StringRef Str) {
std::vector<TypeSpec> Ret;
TypeSpec Acc;
for (char I : Str.str()) {
if (islower(I)) {
Acc.push_back(I);
Ret.push_back(TypeSpec(Acc));
Acc.clear();
} else {
Acc.push_back(I);
}
}
return Ret;
}
};
//===----------------------------------------------------------------------===//
// Type
//===----------------------------------------------------------------------===//
/// A Type. Not much more to say here.
class Type {
private:
TypeSpec TS;
enum TypeKind {
Void,
Float,
SInt,
UInt,
Poly,
};
TypeKind Kind;
bool Immediate, Constant, Pointer;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// ScalarForMangling and NoManglingQ are really not suited to live here as
// they are not related to the type. But they live in the TypeSpec (not the
// prototype), so this is really the only place to store them.
bool ScalarForMangling, NoManglingQ;
unsigned Bitwidth, ElementBitwidth, NumVectors;
public:
Type()
: Kind(Void), Immediate(false), Constant(false),
Pointer(false), ScalarForMangling(false), NoManglingQ(false),
Bitwidth(0), ElementBitwidth(0), NumVectors(0) {}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Type(TypeSpec TS, StringRef CharMods)
: TS(std::move(TS)), Kind(Void), Immediate(false),
Constant(false), Pointer(false), ScalarForMangling(false),
NoManglingQ(false), Bitwidth(0), ElementBitwidth(0), NumVectors(0) {
applyModifiers(CharMods);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
}
/// Returns a type representing "void".
static Type getVoid() { return Type(); }
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
bool operator==(const Type &Other) const { return str() == Other.str(); }
bool operator!=(const Type &Other) const { return !operator==(Other); }
//
// Query functions
//
bool isScalarForMangling() const { return ScalarForMangling; }
bool noManglingQ() const { return NoManglingQ; }
bool isPointer() const { return Pointer; }
bool isValue() const { return !isVoid() && !isPointer(); }
bool isScalar() const { return isValue() && NumVectors == 0; }
bool isVector() const { return isValue() && NumVectors > 0; }
bool isConstPointer() const { return Constant; }
bool isFloating() const { return Kind == Float; }
bool isInteger() const { return Kind == SInt || Kind == UInt; }
bool isPoly() const { return Kind == Poly; }
bool isSigned() const { return Kind == SInt; }
bool isImmediate() const { return Immediate; }
bool isFloat() const { return isFloating() && ElementBitwidth == 32; }
bool isDouble() const { return isFloating() && ElementBitwidth == 64; }
bool isHalf() const { return isFloating() && ElementBitwidth == 16; }
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
bool isChar() const { return ElementBitwidth == 8; }
bool isShort() const { return isInteger() && ElementBitwidth == 16; }
bool isInt() const { return isInteger() && ElementBitwidth == 32; }
bool isLong() const { return isInteger() && ElementBitwidth == 64; }
bool isVoid() const { return Kind == Void; }
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
unsigned getNumElements() const { return Bitwidth / ElementBitwidth; }
unsigned getSizeInBits() const { return Bitwidth; }
unsigned getElementSizeInBits() const { return ElementBitwidth; }
unsigned getNumVectors() const { return NumVectors; }
//
// Mutator functions
//
void makeUnsigned() {
assert(!isVoid() && "not a potentially signed type");
Kind = UInt;
}
void makeSigned() {
assert(!isVoid() && "not a potentially signed type");
Kind = SInt;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void makeInteger(unsigned ElemWidth, bool Sign) {
assert(!isVoid() && "converting void to int probably not useful");
Kind = Sign ? SInt : UInt;
Immediate = false;
ElementBitwidth = ElemWidth;
}
void makeImmediate(unsigned ElemWidth) {
Kind = SInt;
Immediate = true;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
ElementBitwidth = ElemWidth;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void makeScalar() {
Bitwidth = ElementBitwidth;
NumVectors = 0;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void makeOneVector() {
assert(isVector());
NumVectors = 1;
}
void make32BitElement() {
assert_with_loc(Bitwidth > 32, "Not enough bits to make it 32!");
ElementBitwidth = 32;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void doubleLanes() {
assert_with_loc(Bitwidth != 128, "Can't get bigger than 128!");
Bitwidth = 128;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void halveLanes() {
assert_with_loc(Bitwidth != 64, "Can't get smaller than 64!");
Bitwidth = 64;
}
/// Return the C string representation of a type, which is the typename
/// defined in stdint.h or arm_neon.h.
std::string str() const;
/// Return the string representation of a type, which is an encoded
/// string for passing to the BUILTIN() macro in Builtins.def.
std::string builtin_str() const;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
/// Return the value in NeonTypeFlags for this type.
unsigned getNeonEnum() const;
/// Parse a type from a stdint.h or arm_neon.h typedef name,
/// for example uint32x2_t or int64_t.
static Type fromTypedefName(StringRef Name);
private:
/// Creates the type based on the typespec string in TS.
/// Sets "Quad" to true if the "Q" or "H" modifiers were
/// seen. This is needed by applyModifier as some modifiers
/// only take effect if the type size was changed by "Q" or "H".
void applyTypespec(bool &Quad);
/// Applies prototype modifiers to the type.
void applyModifiers(StringRef Mods);
};
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
//===----------------------------------------------------------------------===//
// Variable
//===----------------------------------------------------------------------===//
/// A variable is a simple class that just has a type and a name.
class Variable {
Type T;
std::string N;
public:
Variable() : T(Type::getVoid()), N("") {}
Variable(Type T, std::string N) : T(std::move(T)), N(std::move(N)) {}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Type getType() const { return T; }
std::string getName() const { return "__" + N; }
};
//===----------------------------------------------------------------------===//
// Intrinsic
//===----------------------------------------------------------------------===//
/// The main grunt class. This represents an instantiation of an intrinsic with
/// a particular typespec and prototype.
class Intrinsic {
/// The Record this intrinsic was created from.
Record *R;
/// The unmangled name.
std::string Name;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
/// The input and output typespecs. InTS == OutTS except when
/// CartesianProductOfTypes is 1 - this is the case for vreinterpret.
TypeSpec OutTS, InTS;
/// The base class kind. Most intrinsics use ClassS, which has full type
/// info for integers (s32/u32). Some use ClassI, which doesn't care about
/// signedness (i32), while some (ClassB) have no type at all, only a width
/// (32).
ClassKind CK;
/// The list of DAGs for the body. May be empty, in which case we should
/// emit a builtin call.
ListInit *Body;
/// The architectural #ifdef guard.
std::string Guard;
/// Set if the Unavailable bit is 1. This means we don't generate a body,
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
/// just an "unavailable" attribute on a declaration.
bool IsUnavailable;
/// Is this intrinsic safe for big-endian? or does it need its arguments
/// reversing?
bool BigEndianSafe;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
/// The types of return value [0] and parameters [1..].
std::vector<Type> Types;
/// The index of the key type passed to CGBuiltin.cpp for polymorphic calls.
int PolymorphicKeyType;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
/// The local variables defined.
std::map<std::string, Variable> Variables;
/// NeededEarly - set if any other intrinsic depends on this intrinsic.
bool NeededEarly;
/// UseMacro - set if we should implement using a macro or unset for a
/// function.
bool UseMacro;
/// The set of intrinsics that this intrinsic uses/requires.
std::set<Intrinsic *> Dependencies;
/// The "base type", which is Type('d', OutTS). InBaseType is only
/// different if CartesianProductOfTypes = 1 (for vreinterpret).
Type BaseType, InBaseType;
/// The return variable.
Variable RetVar;
/// A postfix to apply to every variable. Defaults to "".
std::string VariablePostfix;
NeonEmitter &Emitter;
std::stringstream OS;
bool isBigEndianSafe() const {
if (BigEndianSafe)
return true;
for (const auto &T : Types){
if (T.isVector() && T.getNumElements() > 1)
return false;
}
return true;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
public:
Intrinsic(Record *R, StringRef Name, StringRef Proto, TypeSpec OutTS,
TypeSpec InTS, ClassKind CK, ListInit *Body, NeonEmitter &Emitter,
StringRef Guard, bool IsUnavailable, bool BigEndianSafe)
: R(R), Name(Name.str()), OutTS(OutTS), InTS(InTS), CK(CK), Body(Body),
Guard(Guard.str()), IsUnavailable(IsUnavailable),
BigEndianSafe(BigEndianSafe), PolymorphicKeyType(0), NeededEarly(false),
UseMacro(false), BaseType(OutTS, "."), InBaseType(InTS, "."),
Emitter(Emitter) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Modify the TypeSpec per-argument to get a concrete Type, and create
// known variables for each.
// Types[0] is the return value.
unsigned Pos = 0;
Types.emplace_back(OutTS, getNextModifiers(Proto, Pos));
StringRef Mods = getNextModifiers(Proto, Pos);
while (!Mods.empty()) {
Types.emplace_back(InTS, Mods);
if (Mods.find("!") != StringRef::npos)
PolymorphicKeyType = Types.size() - 1;
Mods = getNextModifiers(Proto, Pos);
}
for (auto Type : Types) {
// If this builtin takes an immediate argument, we need to #define it rather
// than use a standard declaration, so that SemaChecking can range check
// the immediate passed by the user.
// Pointer arguments need to use macros to avoid hiding aligned attributes
// from the pointer type.
// It is not permitted to pass or return an __fp16 by value, so intrinsics
// taking a scalar float16_t must be implemented as macros.
if (Type.isImmediate() || Type.isPointer() ||
(Type.isScalar() && Type.isHalf()))
UseMacro = true;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
}
/// Get the Record that this intrinsic is based off.
Record *getRecord() const { return R; }
/// Get the set of Intrinsics that this intrinsic calls.
/// this is the set of immediate dependencies, NOT the
/// transitive closure.
const std::set<Intrinsic *> &getDependencies() const { return Dependencies; }
/// Get the architectural guard string (#ifdef).
std::string getGuard() const { return Guard; }
/// Get the non-mangled name.
std::string getName() const { return Name; }
/// Return true if the intrinsic takes an immediate operand.
bool hasImmediate() const {
return std::any_of(Types.begin(), Types.end(),
[](const Type &T) { return T.isImmediate(); });
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
/// Return the parameter index of the immediate operand.
unsigned getImmediateIdx() const {
for (unsigned Idx = 0; Idx < Types.size(); ++Idx)
if (Types[Idx].isImmediate())
return Idx - 1;
llvm_unreachable("Intrinsic has no immediate");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
}
unsigned getNumParams() const { return Types.size() - 1; }
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Type getReturnType() const { return Types[0]; }
Type getParamType(unsigned I) const { return Types[I + 1]; }
Type getBaseType() const { return BaseType; }
Type getPolymorphicKeyType() const { return Types[PolymorphicKeyType]; }
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
/// Return true if the prototype has a scalar argument.
bool protoHasScalar() const;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
/// Return the index that parameter PIndex will sit at
/// in a generated function call. This is often just PIndex,
/// but may not be as things such as multiple-vector operands
/// and sret parameters need to be taken into accont.
unsigned getGeneratedParamIdx(unsigned PIndex) {
unsigned Idx = 0;
if (getReturnType().getNumVectors() > 1)
// Multiple vectors are passed as sret.
++Idx;
for (unsigned I = 0; I < PIndex; ++I)
Idx += std::max(1U, getParamType(I).getNumVectors());
return Idx;
}
bool hasBody() const { return Body && !Body->getValues().empty(); }
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void setNeededEarly() { NeededEarly = true; }
bool operator<(const Intrinsic &Other) const {
// Sort lexicographically on a two-tuple (Guard, Name)
if (Guard != Other.Guard)
return Guard < Other.Guard;
return Name < Other.Name;
}
ClassKind getClassKind(bool UseClassBIfScalar = false) {
if (UseClassBIfScalar && !protoHasScalar())
return ClassB;
return CK;
}
/// Return the name, mangled with type information.
/// If ForceClassS is true, use ClassS (u32/s32) instead
/// of the intrinsic's own type class.
std::string getMangledName(bool ForceClassS = false) const;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
/// Return the type code for a builtin function call.
std::string getInstTypeCode(Type T, ClassKind CK) const;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
/// Return the type string for a BUILTIN() macro in Builtins.def.
std::string getBuiltinTypeStr();
/// Generate the intrinsic, returning code.
std::string generate();
/// Perform type checking and populate the dependency graph, but
/// don't generate code yet.
void indexBody();
private:
StringRef getNextModifiers(StringRef Proto, unsigned &Pos) const;
std::string mangleName(std::string Name, ClassKind CK) const;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void initVariables();
std::string replaceParamsIn(std::string S);
void emitBodyAsBuiltinCall();
void generateImpl(bool ReverseArguments,
StringRef NamePrefix, StringRef CallPrefix);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void emitReturn();
void emitBody(StringRef CallPrefix);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void emitShadowedArgs();
void emitArgumentReversal();
void emitReturnReversal();
void emitReverseVariable(Variable &Dest, Variable &Src);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void emitNewLine();
void emitClosingBrace();
void emitOpeningBrace();
void emitPrototype(StringRef NamePrefix);
class DagEmitter {
Intrinsic &Intr;
StringRef CallPrefix;
public:
DagEmitter(Intrinsic &Intr, StringRef CallPrefix) :
Intr(Intr), CallPrefix(CallPrefix) {
}
std::pair<Type, std::string> emitDagArg(Init *Arg, std::string ArgName);
std::pair<Type, std::string> emitDagSaveTemp(DagInit *DI);
std::pair<Type, std::string> emitDagSplat(DagInit *DI);
std::pair<Type, std::string> emitDagDup(DagInit *DI);
std::pair<Type, std::string> emitDagDupTyped(DagInit *DI);
std::pair<Type, std::string> emitDagShuffle(DagInit *DI);
std::pair<Type, std::string> emitDagCast(DagInit *DI, bool IsBitCast);
std::pair<Type, std::string> emitDagCall(DagInit *DI,
bool MatchMangledName);
std::pair<Type, std::string> emitDagNameReplace(DagInit *DI);
std::pair<Type, std::string> emitDagLiteral(DagInit *DI);
std::pair<Type, std::string> emitDagOp(DagInit *DI);
std::pair<Type, std::string> emitDag(DagInit *DI);
};
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
};
//===----------------------------------------------------------------------===//
// NeonEmitter
//===----------------------------------------------------------------------===//
class NeonEmitter {
RecordKeeper &Records;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
DenseMap<Record *, ClassKind> ClassMap;
std::map<std::string, std::deque<Intrinsic>> IntrinsicMap;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
unsigned UniqueNumber;
void createIntrinsic(Record *R, SmallVectorImpl<Intrinsic *> &Out);
void genBuiltinsDef(raw_ostream &OS, SmallVectorImpl<Intrinsic *> &Defs);
void genOverloadTypeCheckCode(raw_ostream &OS,
SmallVectorImpl<Intrinsic *> &Defs);
void genIntrinsicRangeCheckCode(raw_ostream &OS,
SmallVectorImpl<Intrinsic *> &Defs);
public:
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
/// Called by Intrinsic - this attempts to get an intrinsic that takes
/// the given types as arguments.
Intrinsic &getIntrinsic(StringRef Name, ArrayRef<Type> Types,
Optional<std::string> MangledName);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
/// Called by Intrinsic - returns a globally-unique number.
unsigned getUniqueNumber() { return UniqueNumber++; }
NeonEmitter(RecordKeeper &R) : Records(R), UniqueNumber(0) {
Record *SI = R.getClass("SInst");
Record *II = R.getClass("IInst");
Record *WI = R.getClass("WInst");
Record *SOpI = R.getClass("SOpInst");
Record *IOpI = R.getClass("IOpInst");
Record *WOpI = R.getClass("WOpInst");
Record *LOpI = R.getClass("LOpInst");
Record *NoTestOpI = R.getClass("NoTestOpInst");
ClassMap[SI] = ClassS;
ClassMap[II] = ClassI;
ClassMap[WI] = ClassW;
ClassMap[SOpI] = ClassS;
ClassMap[IOpI] = ClassI;
ClassMap[WOpI] = ClassW;
ClassMap[LOpI] = ClassL;
ClassMap[NoTestOpI] = ClassNoTest;
}
// run - Emit arm_neon.h.inc
void run(raw_ostream &o);
// runFP16 - Emit arm_fp16.h.inc
void runFP16(raw_ostream &o);
// runHeader - Emit all the __builtin prototypes used in arm_neon.h
// and arm_fp16.h
void runHeader(raw_ostream &o);
// runTests - Emit tests for all the Neon intrinsics.
void runTests(raw_ostream &o);
};
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
} // end anonymous namespace
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
//===----------------------------------------------------------------------===//
// Type implementation
//===----------------------------------------------------------------------===//
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string Type::str() const {
if (isVoid())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
return "void";
std::string S;
if (isInteger() && !isSigned())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
S += "u";
if (isPoly())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
S += "poly";
else if (isFloating())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
S += "float";
else
S += "int";
S += utostr(ElementBitwidth);
if (isVector())
S += "x" + utostr(getNumElements());
if (NumVectors > 1)
S += "x" + utostr(NumVectors);
S += "_t";
if (Constant)
S += " const";
if (Pointer)
S += " *";
return S;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string Type::builtin_str() const {
std::string S;
if (isVoid())
return "v";
if (isPointer()) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// All pointers are void pointers.
S = "v";
if (isConstPointer())
S += "C";
S += "*";
return S;
} else if (isInteger())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
switch (ElementBitwidth) {
case 8: S += "c"; break;
case 16: S += "s"; break;
case 32: S += "i"; break;
case 64: S += "Wi"; break;
case 128: S += "LLLi"; break;
default: llvm_unreachable("Unhandled case!");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
}
else
switch (ElementBitwidth) {
case 16: S += "h"; break;
case 32: S += "f"; break;
case 64: S += "d"; break;
default: llvm_unreachable("Unhandled case!");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
}
// FIXME: NECESSARY???????????????????????????????????????????????????????????????????????
if (isChar() && !isPointer() && isSigned())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Make chars explicitly signed.
S = "S" + S;
else if (isInteger() && !isSigned())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
S = "U" + S;
// Constant indices are "int", but have the "constant expression" modifier.
if (isImmediate()) {
assert(isInteger() && isSigned());
S = "I" + S;
}
if (isScalar())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
return S;
std::string Ret;
for (unsigned I = 0; I < NumVectors; ++I)
Ret += "V" + utostr(getNumElements()) + S;
return Ret;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
unsigned Type::getNeonEnum() const {
unsigned Addend;
switch (ElementBitwidth) {
case 8: Addend = 0; break;
case 16: Addend = 1; break;
case 32: Addend = 2; break;
case 64: Addend = 3; break;
case 128: Addend = 4; break;
default: llvm_unreachable("Unhandled element bitwidth!");
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
unsigned Base = (unsigned)NeonTypeFlags::Int8 + Addend;
if (isPoly()) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Adjustment needed because Poly32 doesn't exist.
if (Addend >= 2)
--Addend;
Base = (unsigned)NeonTypeFlags::Poly8 + Addend;
}
if (isFloating()) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert(Addend != 0 && "Float8 doesn't exist!");
Base = (unsigned)NeonTypeFlags::Float16 + (Addend - 1);
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (Bitwidth == 128)
Base |= (unsigned)NeonTypeFlags::QuadFlag;
if (isInteger() && !isSigned())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Base |= (unsigned)NeonTypeFlags::UnsignedFlag;
return Base;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Type Type::fromTypedefName(StringRef Name) {
Type T;
T.Kind = SInt;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (Name.front() == 'u') {
T.Kind = UInt;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Name = Name.drop_front();
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (Name.startswith("float")) {
T.Kind = Float;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Name = Name.drop_front(5);
} else if (Name.startswith("poly")) {
T.Kind = Poly;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Name = Name.drop_front(4);
} else {
assert(Name.startswith("int"));
Name = Name.drop_front(3);
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
unsigned I = 0;
for (I = 0; I < Name.size(); ++I) {
if (!isdigit(Name[I]))
break;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Name.substr(0, I).getAsInteger(10, T.ElementBitwidth);
Name = Name.drop_front(I);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
T.Bitwidth = T.ElementBitwidth;
T.NumVectors = 1;
if (Name.front() == 'x') {
Name = Name.drop_front();
unsigned I = 0;
for (I = 0; I < Name.size(); ++I) {
if (!isdigit(Name[I]))
break;
}
unsigned NumLanes;
Name.substr(0, I).getAsInteger(10, NumLanes);
Name = Name.drop_front(I);
T.Bitwidth = T.ElementBitwidth * NumLanes;
} else {
// Was scalar.
T.NumVectors = 0;
}
if (Name.front() == 'x') {
Name = Name.drop_front();
unsigned I = 0;
for (I = 0; I < Name.size(); ++I) {
if (!isdigit(Name[I]))
break;
}
Name.substr(0, I).getAsInteger(10, T.NumVectors);
Name = Name.drop_front(I);
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert(Name.startswith("_t") && "Malformed typedef!");
return T;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void Type::applyTypespec(bool &Quad) {
std::string S = TS;
ScalarForMangling = false;
Kind = SInt;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
ElementBitwidth = ~0U;
NumVectors = 1;
for (char I : S) {
switch (I) {
case 'S':
ScalarForMangling = true;
break;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
case 'H':
NoManglingQ = true;
Quad = true;
break;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
case 'Q':
Quad = true;
break;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
case 'P':
Kind = Poly;
break;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
case 'U':
Kind = UInt;
break;
case 'c':
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
ElementBitwidth = 8;
break;
case 'h':
Kind = Float;
LLVM_FALLTHROUGH;
case 's':
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
ElementBitwidth = 16;
break;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
case 'f':
Kind = Float;
LLVM_FALLTHROUGH;
case 'i':
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
ElementBitwidth = 32;
break;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
case 'd':
Kind = Float;
LLVM_FALLTHROUGH;
case 'l':
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
ElementBitwidth = 64;
break;
case 'k':
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
ElementBitwidth = 128;
// Poly doesn't have a 128x1 type.
if (isPoly())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
NumVectors = 0;
break;
default:
llvm_unreachable("Unhandled type code!");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
}
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Bitwidth = Quad ? 128 : 64;
}
void Type::applyModifiers(StringRef Mods) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
bool AppliedQuad = false;
applyTypespec(AppliedQuad);
for (char Mod : Mods) {
switch (Mod) {
case '.':
break;
case 'v':
Kind = Void;
break;
case 'S':
Kind = SInt;
break;
case 'U':
Kind = UInt;
break;
case 'F':
Kind = Float;
break;
case 'P':
Kind = Poly;
break;
case '>':
assert(ElementBitwidth < 128);
ElementBitwidth *= 2;
break;
case '<':
assert(ElementBitwidth > 8);
ElementBitwidth /= 2;
break;
case '1':
NumVectors = 0;
break;
case '2':
NumVectors = 2;
break;
case '3':
NumVectors = 3;
break;
case '4':
NumVectors = 4;
break;
case '*':
Pointer = true;
break;
case 'c':
Constant = true;
break;
case 'Q':
Bitwidth = 128;
break;
case 'q':
Bitwidth = 64;
break;
case 'I':
Kind = SInt;
ElementBitwidth = Bitwidth = 32;
NumVectors = 0;
Immediate = true;
break;
case 'p':
if (isPoly())
Kind = UInt;
break;
case '!':
// Key type, handled elsewhere.
break;
default:
llvm_unreachable("Unhandled character!");
}
}
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
//===----------------------------------------------------------------------===//
// Intrinsic implementation
//===----------------------------------------------------------------------===//
StringRef Intrinsic::getNextModifiers(StringRef Proto, unsigned &Pos) const {
if (Proto.size() == Pos)
return StringRef();
else if (Proto[Pos] != '(')
return Proto.substr(Pos++, 1);
size_t Start = Pos + 1;
size_t End = Proto.find(')', Start);
assert_with_loc(End != StringRef::npos, "unmatched modifier group paren");
Pos = End + 1;
return Proto.slice(Start, End);
}
std::string Intrinsic::getInstTypeCode(Type T, ClassKind CK) const {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
char typeCode = '\0';
bool printNumber = true;
if (CK == ClassB)
return "";
if (T.isPoly())
typeCode = 'p';
else if (T.isInteger())
typeCode = T.isSigned() ? 's' : 'u';
else
typeCode = 'f';
if (CK == ClassI) {
switch (typeCode) {
default:
break;
case 's':
case 'u':
case 'p':
typeCode = 'i';
break;
}
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (CK == ClassB) {
typeCode = '\0';
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string S;
if (typeCode != '\0')
S.push_back(typeCode);
if (printNumber)
S += utostr(T.getElementSizeInBits());
return S;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string Intrinsic::getBuiltinTypeStr() {
ClassKind LocalCK = getClassKind(true);
std::string S;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Type RetT = getReturnType();
if ((LocalCK == ClassI || LocalCK == ClassW) && RetT.isScalar() &&
!RetT.isFloating())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
RetT.makeInteger(RetT.getElementSizeInBits(), false);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Since the return value must be one type, return a vector type of the
// appropriate width which we will bitcast. An exception is made for
// returning structs of 2, 3, or 4 vectors which are returned in a sret-like
// fashion, storing them to a pointer arg.
if (RetT.getNumVectors() > 1) {
S += "vv*"; // void result with void* first argument
} else {
if (RetT.isPoly())
RetT.makeInteger(RetT.getElementSizeInBits(), false);
if (!RetT.isScalar() && RetT.isInteger() && !RetT.isSigned())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
RetT.makeSigned();
if (LocalCK == ClassB && RetT.isValue() && !RetT.isScalar())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Cast to vector of 8-bit elements.
RetT.makeInteger(8, true);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
S += RetT.builtin_str();
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (unsigned I = 0; I < getNumParams(); ++I) {
Type T = getParamType(I);
if (T.isPoly())
T.makeInteger(T.getElementSizeInBits(), false);
if (LocalCK == ClassB && !T.isScalar())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
T.makeInteger(8, true);
// Halves always get converted to 8-bit elements.
if (T.isHalf() && T.isVector() && !T.isScalarForMangling())
T.makeInteger(8, true);
if (LocalCK == ClassI && T.isInteger())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
T.makeSigned();
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (hasImmediate() && getImmediateIdx() == I)
T.makeImmediate(32);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
S += T.builtin_str();
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Extra constant integer to hold type class enum for this function, e.g. s8
if (LocalCK == ClassB)
S += "i";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
return S;
}
std::string Intrinsic::getMangledName(bool ForceClassS) const {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Check if the prototype has a scalar operand with the type of the vector
// elements. If not, bitcasting the args will take care of arg checking.
// The actual signedness etc. will be taken care of with special enums.
ClassKind LocalCK = CK;
if (!protoHasScalar())
LocalCK = ClassB;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
return mangleName(Name, ForceClassS ? ClassS : LocalCK);
}
std::string Intrinsic::mangleName(std::string Name, ClassKind LocalCK) const {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string typeCode = getInstTypeCode(BaseType, LocalCK);
std::string S = Name;
if (Name == "vcvt_f16_f32" || Name == "vcvt_f32_f16" ||
Name == "vcvt_f32_f64" || Name == "vcvt_f64_f32")
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
return Name;
if (!typeCode.empty()) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// If the name ends with _xN (N = 2,3,4), insert the typeCode before _xN.
if (Name.size() >= 3 && isdigit(Name.back()) &&
Name[Name.length() - 2] == 'x' && Name[Name.length() - 3] == '_')
S.insert(S.length() - 3, "_" + typeCode);
else
S += "_" + typeCode;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (BaseType != InBaseType) {
// A reinterpret - out the input base type at the end.
S += "_" + getInstTypeCode(InBaseType, LocalCK);
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (LocalCK == ClassB)
S += "_v";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Insert a 'q' before the first '_' character so that it ends up before
// _lane or _n on vector-scalar operations.
if (BaseType.getSizeInBits() == 128 && !BaseType.noManglingQ()) {
size_t Pos = S.find('_');
S.insert(Pos, "q");
}
char Suffix = '\0';
if (BaseType.isScalarForMangling()) {
switch (BaseType.getElementSizeInBits()) {
case 8: Suffix = 'b'; break;
case 16: Suffix = 'h'; break;
case 32: Suffix = 's'; break;
case 64: Suffix = 'd'; break;
default: llvm_unreachable("Bad suffix!");
}
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (Suffix != '\0') {
size_t Pos = S.find('_');
S.insert(Pos, &Suffix, 1);
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
return S;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string Intrinsic::replaceParamsIn(std::string S) {
while (S.find('$') != std::string::npos) {
size_t Pos = S.find('$');
size_t End = Pos + 1;
while (isalpha(S[End]))
++End;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string VarName = S.substr(Pos + 1, End - Pos - 1);
assert_with_loc(Variables.find(VarName) != Variables.end(),
"Variable not defined!");
S.replace(Pos, End - Pos, Variables.find(VarName)->second.getName());
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
return S;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void Intrinsic::initVariables() {
Variables.clear();
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Modify the TypeSpec per-argument to get a concrete Type, and create
// known variables for each.
for (unsigned I = 1; I < Types.size(); ++I) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
char NameC = '0' + (I - 1);
std::string Name = "p";
Name.push_back(NameC);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Variables[Name] = Variable(Types[I], Name + VariablePostfix);
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
RetVar = Variable(Types[0], "ret" + VariablePostfix);
}
void Intrinsic::emitPrototype(StringRef NamePrefix) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (UseMacro)
OS << "#define ";
else
OS << "__ai " << Types[0].str() << " ";
OS << NamePrefix.str() << mangleName(Name, ClassS) << "(";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (unsigned I = 0; I < getNumParams(); ++I) {
if (I != 0)
OS << ", ";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
char NameC = '0' + I;
std::string Name = "p";
Name.push_back(NameC);
assert(Variables.find(Name) != Variables.end());
Variable &V = Variables[Name];
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (!UseMacro)
OS << V.getType().str() << " ";
OS << V.getName();
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
OS << ")";
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void Intrinsic::emitOpeningBrace() {
if (UseMacro)
OS << " __extension__ ({";
else
OS << " {";
emitNewLine();
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void Intrinsic::emitClosingBrace() {
if (UseMacro)
OS << "})";
else
OS << "}";
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void Intrinsic::emitNewLine() {
if (UseMacro)
OS << " \\\n";
else
OS << "\n";
}
void Intrinsic::emitReverseVariable(Variable &Dest, Variable &Src) {
if (Dest.getType().getNumVectors() > 1) {
emitNewLine();
for (unsigned K = 0; K < Dest.getType().getNumVectors(); ++K) {
OS << " " << Dest.getName() << ".val[" << K << "] = "
<< "__builtin_shufflevector("
<< Src.getName() << ".val[" << K << "], "
<< Src.getName() << ".val[" << K << "]";
for (int J = Dest.getType().getNumElements() - 1; J >= 0; --J)
OS << ", " << J;
OS << ");";
emitNewLine();
}
} else {
OS << " " << Dest.getName()
<< " = __builtin_shufflevector(" << Src.getName() << ", " << Src.getName();
for (int J = Dest.getType().getNumElements() - 1; J >= 0; --J)
OS << ", " << J;
OS << ");";
emitNewLine();
}
}
void Intrinsic::emitArgumentReversal() {
if (isBigEndianSafe())
return;
// Reverse all vector arguments.
for (unsigned I = 0; I < getNumParams(); ++I) {
std::string Name = "p" + utostr(I);
std::string NewName = "rev" + utostr(I);
Variable &V = Variables[Name];
Variable NewV(V.getType(), NewName + VariablePostfix);
if (!NewV.getType().isVector() || NewV.getType().getNumElements() == 1)
continue;
OS << " " << NewV.getType().str() << " " << NewV.getName() << ";";
emitReverseVariable(NewV, V);
V = NewV;
}
}
void Intrinsic::emitReturnReversal() {
if (isBigEndianSafe())
return;
if (!getReturnType().isVector() || getReturnType().isVoid() ||
getReturnType().getNumElements() == 1)
return;
emitReverseVariable(RetVar, RetVar);
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void Intrinsic::emitShadowedArgs() {
// Macro arguments are not type-checked like inline function arguments,
// so assign them to local temporaries to get the right type checking.
if (!UseMacro)
return;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (unsigned I = 0; I < getNumParams(); ++I) {
// Do not create a temporary for an immediate argument.
// That would defeat the whole point of using a macro!
if (getParamType(I).isImmediate())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
continue;
// Do not create a temporary for pointer arguments. The input
// pointer may have an alignment hint.
if (getParamType(I).isPointer())
continue;
std::string Name = "p" + utostr(I);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert(Variables.find(Name) != Variables.end());
Variable &V = Variables[Name];
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string NewName = "s" + utostr(I);
Variable V2(V.getType(), NewName + VariablePostfix);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
OS << " " << V2.getType().str() << " " << V2.getName() << " = "
<< V.getName() << ";";
emitNewLine();
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
V = V2;
}
}
bool Intrinsic::protoHasScalar() const {
return std::any_of(Types.begin(), Types.end(), [](const Type &T) {
return T.isScalar() && !T.isImmediate();
});
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void Intrinsic::emitBodyAsBuiltinCall() {
std::string S;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit
// sret-like argument.
bool SRet = getReturnType().getNumVectors() >= 2;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
StringRef N = Name;
ClassKind LocalCK = CK;
if (!protoHasScalar())
LocalCK = ClassB;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (!getReturnType().isVoid() && !SRet)
S += "(" + RetVar.getType().str() + ") ";
S += "__builtin_neon_" + mangleName(std::string(N), LocalCK) + "(";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (SRet)
S += "&" + RetVar.getName() + ", ";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (unsigned I = 0; I < getNumParams(); ++I) {
Variable &V = Variables["p" + utostr(I)];
Type T = V.getType();
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Handle multiple-vector values specially, emitting each subvector as an
// argument to the builtin.
if (T.getNumVectors() > 1) {
// Check if an explicit cast is needed.
std::string Cast;
if (LocalCK == ClassB) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Type T2 = T;
T2.makeOneVector();
T2.makeInteger(8, /*Signed=*/true);
Cast = "(" + T2.str() + ")";
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (unsigned J = 0; J < T.getNumVectors(); ++J)
S += Cast + V.getName() + ".val[" + utostr(J) + "], ";
continue;
}
std::string Arg = V.getName();
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Type CastToType = T;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Check if an explicit cast is needed.
if (CastToType.isVector() &&
(LocalCK == ClassB || (T.isHalf() && !T.isScalarForMangling()))) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
CastToType.makeInteger(8, true);
Arg = "(" + CastToType.str() + ")" + Arg;
} else if (CastToType.isVector() && LocalCK == ClassI) {
if (CastToType.isInteger())
CastToType.makeSigned();
Arg = "(" + CastToType.str() + ")" + Arg;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
}
S += Arg + ", ";
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Extra constant integer to hold type class enum for this function, e.g. s8
if (getClassKind(true) == ClassB) {
S += utostr(getPolymorphicKeyType().getNeonEnum());
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
} else {
// Remove extraneous ", ".
S.pop_back();
S.pop_back();
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
S += ");";
std::string RetExpr;
if (!SRet && !RetVar.getType().isVoid())
RetExpr = RetVar.getName() + " = ";
OS << " " << RetExpr << S;
emitNewLine();
}
void Intrinsic::emitBody(StringRef CallPrefix) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::vector<std::string> Lines;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert(RetVar.getType() == Types[0]);
// Create a return variable, if we're not void.
if (!RetVar.getType().isVoid()) {
OS << " " << RetVar.getType().str() << " " << RetVar.getName() << ";";
emitNewLine();
}
if (!Body || Body->getValues().empty()) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Nothing specific to output - must output a builtin.
emitBodyAsBuiltinCall();
return;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// We have a list of "things to output". The last should be returned.
for (auto *I : Body->getValues()) {
if (StringInit *SI = dyn_cast<StringInit>(I)) {
Lines.push_back(replaceParamsIn(SI->getAsString()));
} else if (DagInit *DI = dyn_cast<DagInit>(I)) {
DagEmitter DE(*this, CallPrefix);
Lines.push_back(DE.emitDag(DI).second + ";");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
}
}
assert(!Lines.empty() && "Empty def?");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (!RetVar.getType().isVoid())
Lines.back().insert(0, RetVar.getName() + " = ");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (auto &L : Lines) {
OS << " " << L;
emitNewLine();
}
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void Intrinsic::emitReturn() {
if (RetVar.getType().isVoid())
return;
if (UseMacro)
OS << " " << RetVar.getName() << ";";
else
OS << " return " << RetVar.getName() << ";";
emitNewLine();
}
std::pair<Type, std::string> Intrinsic::DagEmitter::emitDag(DagInit *DI) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// At this point we should only be seeing a def.
DefInit *DefI = cast<DefInit>(DI->getOperator());
std::string Op = DefI->getAsString();
if (Op == "cast" || Op == "bitcast")
return emitDagCast(DI, Op == "bitcast");
if (Op == "shuffle")
return emitDagShuffle(DI);
if (Op == "dup")
return emitDagDup(DI);
if (Op == "dup_typed")
return emitDagDupTyped(DI);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (Op == "splat")
return emitDagSplat(DI);
if (Op == "save_temp")
return emitDagSaveTemp(DI);
if (Op == "op")
return emitDagOp(DI);
if (Op == "call" || Op == "call_mangled")
return emitDagCall(DI, Op == "call_mangled");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (Op == "name_replace")
return emitDagNameReplace(DI);
if (Op == "literal")
return emitDagLiteral(DI);
assert_with_loc(false, "Unknown operation!");
return std::make_pair(Type::getVoid(), "");
}
std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagOp(DagInit *DI) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string Op = cast<StringInit>(DI->getArg(0))->getAsUnquotedString();
if (DI->getNumArgs() == 2) {
// Unary op.
std::pair<Type, std::string> R =
emitDagArg(DI->getArg(1), std::string(DI->getArgNameStr(1)));
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
return std::make_pair(R.first, Op + R.second);
} else {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert(DI->getNumArgs() == 3 && "Can only handle unary and binary ops!");
std::pair<Type, std::string> R1 =
emitDagArg(DI->getArg(1), std::string(DI->getArgNameStr(1)));
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::pair<Type, std::string> R2 =
emitDagArg(DI->getArg(2), std::string(DI->getArgNameStr(2)));
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert_with_loc(R1.first == R2.first, "Argument type mismatch!");
return std::make_pair(R1.first, R1.second + " " + Op + " " + R2.second);
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
}
std::pair<Type, std::string>
Intrinsic::DagEmitter::emitDagCall(DagInit *DI, bool MatchMangledName) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::vector<Type> Types;
std::vector<std::string> Values;
for (unsigned I = 0; I < DI->getNumArgs() - 1; ++I) {
std::pair<Type, std::string> R =
emitDagArg(DI->getArg(I + 1), std::string(DI->getArgNameStr(I + 1)));
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Types.push_back(R.first);
Values.push_back(R.second);
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Look up the called intrinsic.
std::string N;
if (StringInit *SI = dyn_cast<StringInit>(DI->getArg(0)))
N = SI->getAsUnquotedString();
else
N = emitDagArg(DI->getArg(0), "").second;
Optional<std::string> MangledName;
if (MatchMangledName) {
if (Intr.getRecord()->getValueAsBit("isLaneQ"))
N += "q";
MangledName = Intr.mangleName(N, ClassS);
}
Intrinsic &Callee = Intr.Emitter.getIntrinsic(N, Types, MangledName);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Make sure the callee is known as an early def.
Callee.setNeededEarly();
Intr.Dependencies.insert(&Callee);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Now create the call itself.
std::string S = "";
if (!Callee.isBigEndianSafe())
S += CallPrefix.str();
S += Callee.getMangledName(true) + "(";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (unsigned I = 0; I < DI->getNumArgs() - 1; ++I) {
if (I != 0)
S += ", ";
S += Values[I];
}
S += ")";
return std::make_pair(Callee.getReturnType(), S);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
}
std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagCast(DagInit *DI,
bool IsBitCast){
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// (cast MOD* VAL) -> cast VAL to type given by MOD.
std::pair<Type, std::string> R =
emitDagArg(DI->getArg(DI->getNumArgs() - 1),
std::string(DI->getArgNameStr(DI->getNumArgs() - 1)));
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Type castToType = R.first;
for (unsigned ArgIdx = 0; ArgIdx < DI->getNumArgs() - 1; ++ArgIdx) {
// MOD can take several forms:
// 1. $X - take the type of parameter / variable X.
// 2. The value "R" - take the type of the return type.
// 3. a type string
// 4. The value "U" or "S" to switch the signedness.
// 5. The value "H" or "D" to half or double the bitwidth.
// 6. The value "8" to convert to 8-bit (signed) integer lanes.
if (!DI->getArgNameStr(ArgIdx).empty()) {
assert_with_loc(Intr.Variables.find(std::string(
DI->getArgNameStr(ArgIdx))) != Intr.Variables.end(),
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
"Variable not found");
castToType =
Intr.Variables[std::string(DI->getArgNameStr(ArgIdx))].getType();
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
} else {
StringInit *SI = dyn_cast<StringInit>(DI->getArg(ArgIdx));
assert_with_loc(SI, "Expected string type or $Name for cast type");
if (SI->getAsUnquotedString() == "R") {
castToType = Intr.getReturnType();
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
} else if (SI->getAsUnquotedString() == "U") {
castToType.makeUnsigned();
} else if (SI->getAsUnquotedString() == "S") {
castToType.makeSigned();
} else if (SI->getAsUnquotedString() == "H") {
castToType.halveLanes();
} else if (SI->getAsUnquotedString() == "D") {
castToType.doubleLanes();
} else if (SI->getAsUnquotedString() == "8") {
castToType.makeInteger(8, true);
} else if (SI->getAsUnquotedString() == "32") {
castToType.make32BitElement();
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
} else {
castToType = Type::fromTypedefName(SI->getAsUnquotedString());
assert_with_loc(!castToType.isVoid(), "Unknown typedef");
}
}
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string S;
if (IsBitCast) {
// Emit a reinterpret cast. The second operand must be an lvalue, so create
// a temporary.
std::string N = "reint";
unsigned I = 0;
while (Intr.Variables.find(N) != Intr.Variables.end())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
N = "reint" + utostr(++I);
Intr.Variables[N] = Variable(R.first, N + Intr.VariablePostfix);
Intr.OS << R.first.str() << " " << Intr.Variables[N].getName() << " = "
<< R.second << ";";
Intr.emitNewLine();
S = "*(" + castToType.str() + " *) &" + Intr.Variables[N].getName() + "";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
} else {
// Emit a normal (static) cast.
S = "(" + castToType.str() + ")(" + R.second + ")";
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
return std::make_pair(castToType, S);
}
std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagShuffle(DagInit *DI){
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// See the documentation in arm_neon.td for a description of these operators.
class LowHalf : public SetTheory::Operator {
public:
void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts,
ArrayRef<SMLoc> Loc) override {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
SetTheory::RecSet Elts2;
ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts2, Loc);
Elts.insert(Elts2.begin(), Elts2.begin() + (Elts2.size() / 2));
}
};
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
class HighHalf : public SetTheory::Operator {
public:
void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts,
ArrayRef<SMLoc> Loc) override {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
SetTheory::RecSet Elts2;
ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts2, Loc);
Elts.insert(Elts2.begin() + (Elts2.size() / 2), Elts2.end());
}
};
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
class Rev : public SetTheory::Operator {
unsigned ElementSize;
public:
Rev(unsigned ElementSize) : ElementSize(ElementSize) {}
void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts,
ArrayRef<SMLoc> Loc) override {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
SetTheory::RecSet Elts2;
ST.evaluate(Expr->arg_begin() + 1, Expr->arg_end(), Elts2, Loc);
int64_t VectorSize = cast<IntInit>(Expr->getArg(0))->getValue();
VectorSize /= ElementSize;
std::vector<Record *> Revved;
for (unsigned VI = 0; VI < Elts2.size(); VI += VectorSize) {
for (int LI = VectorSize - 1; LI >= 0; --LI) {
Revved.push_back(Elts2[VI + LI]);
}
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Elts.insert(Revved.begin(), Revved.end());
}
};
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
class MaskExpander : public SetTheory::Expander {
unsigned N;
public:
MaskExpander(unsigned N) : N(N) {}
void expand(SetTheory &ST, Record *R, SetTheory::RecSet &Elts) override {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
unsigned Addend = 0;
if (R->getName() == "mask0")
Addend = 0;
else if (R->getName() == "mask1")
Addend = N;
else
return;
for (unsigned I = 0; I < N; ++I)
Elts.insert(R->getRecords().getDef("sv" + utostr(I + Addend)));
}
};
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// (shuffle arg1, arg2, sequence)
std::pair<Type, std::string> Arg1 =
emitDagArg(DI->getArg(0), std::string(DI->getArgNameStr(0)));
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::pair<Type, std::string> Arg2 =
emitDagArg(DI->getArg(1), std::string(DI->getArgNameStr(1)));
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert_with_loc(Arg1.first == Arg2.first,
"Different types in arguments to shuffle!");
SetTheory ST;
SetTheory::RecSet Elts;
ST.addOperator("lowhalf", std::make_unique<LowHalf>());
ST.addOperator("highhalf", std::make_unique<HighHalf>());
ST.addOperator("rev",
std::make_unique<Rev>(Arg1.first.getElementSizeInBits()));
ST.addExpander("MaskExpand",
std::make_unique<MaskExpander>(Arg1.first.getNumElements()));
ST.evaluate(DI->getArg(2), Elts, None);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string S = "__builtin_shufflevector(" + Arg1.second + ", " + Arg2.second;
for (auto &E : Elts) {
StringRef Name = E->getName();
assert_with_loc(Name.startswith("sv"),
"Incorrect element kind in shuffle mask!");
S += ", " + Name.drop_front(2).str();
}
S += ")";
// Recalculate the return type - the shuffle may have halved or doubled it.
Type T(Arg1.first);
if (Elts.size() > T.getNumElements()) {
assert_with_loc(
Elts.size() == T.getNumElements() * 2,
"Can only double or half the number of elements in a shuffle!");
T.doubleLanes();
} else if (Elts.size() < T.getNumElements()) {
assert_with_loc(
Elts.size() == T.getNumElements() / 2,
"Can only double or half the number of elements in a shuffle!");
T.halveLanes();
}
return std::make_pair(T, S);
}
std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagDup(DagInit *DI) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert_with_loc(DI->getNumArgs() == 1, "dup() expects one argument");
std::pair<Type, std::string> A =
emitDagArg(DI->getArg(0), std::string(DI->getArgNameStr(0)));
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert_with_loc(A.first.isScalar(), "dup() expects a scalar argument");
Type T = Intr.getBaseType();
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert_with_loc(T.isVector(), "dup() used but default type is scalar!");
std::string S = "(" + T.str() + ") {";
for (unsigned I = 0; I < T.getNumElements(); ++I) {
if (I != 0)
S += ", ";
S += A.second;
}
S += "}";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
return std::make_pair(T, S);
}
std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagDupTyped(DagInit *DI) {
assert_with_loc(DI->getNumArgs() == 2, "dup_typed() expects two arguments");
std::pair<Type, std::string> A =
emitDagArg(DI->getArg(0), std::string(DI->getArgNameStr(0)));
std::pair<Type, std::string> B =
emitDagArg(DI->getArg(1), std::string(DI->getArgNameStr(1)));
assert_with_loc(B.first.isScalar(),
"dup_typed() requires a scalar as the second argument");
Type T = A.first;
assert_with_loc(T.isVector(), "dup_typed() used but target type is scalar!");
std::string S = "(" + T.str() + ") {";
for (unsigned I = 0; I < T.getNumElements(); ++I) {
if (I != 0)
S += ", ";
S += B.second;
}
S += "}";
return std::make_pair(T, S);
}
std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagSplat(DagInit *DI) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert_with_loc(DI->getNumArgs() == 2, "splat() expects two arguments");
std::pair<Type, std::string> A =
emitDagArg(DI->getArg(0), std::string(DI->getArgNameStr(0)));
std::pair<Type, std::string> B =
emitDagArg(DI->getArg(1), std::string(DI->getArgNameStr(1)));
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert_with_loc(B.first.isScalar(),
"splat() requires a scalar int as the second argument");
std::string S = "__builtin_shufflevector(" + A.second + ", " + A.second;
for (unsigned I = 0; I < Intr.getBaseType().getNumElements(); ++I) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
S += ", " + B.second;
}
S += ")";
return std::make_pair(Intr.getBaseType(), S);
}
std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagSaveTemp(DagInit *DI) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert_with_loc(DI->getNumArgs() == 2, "save_temp() expects two arguments");
std::pair<Type, std::string> A =
emitDagArg(DI->getArg(1), std::string(DI->getArgNameStr(1)));
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert_with_loc(!A.first.isVoid(),
"Argument to save_temp() must have non-void type!");
std::string N = std::string(DI->getArgNameStr(0));
assert_with_loc(!N.empty(),
"save_temp() expects a name as the first argument");
assert_with_loc(Intr.Variables.find(N) == Intr.Variables.end(),
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
"Variable already defined!");
Intr.Variables[N] = Variable(A.first, N + Intr.VariablePostfix);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string S =
A.first.str() + " " + Intr.Variables[N].getName() + " = " + A.second;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
return std::make_pair(Type::getVoid(), S);
}
std::pair<Type, std::string>
Intrinsic::DagEmitter::emitDagNameReplace(DagInit *DI) {
std::string S = Intr.Name;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert_with_loc(DI->getNumArgs() == 2, "name_replace requires 2 arguments!");
std::string ToReplace = cast<StringInit>(DI->getArg(0))->getAsUnquotedString();
std::string ReplaceWith = cast<StringInit>(DI->getArg(1))->getAsUnquotedString();
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
size_t Idx = S.find(ToReplace);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert_with_loc(Idx != std::string::npos, "name should contain '" + ToReplace + "'!");
S.replace(Idx, ToReplace.size(), ReplaceWith);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
return std::make_pair(Type::getVoid(), S);
}
std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagLiteral(DagInit *DI){
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string Ty = cast<StringInit>(DI->getArg(0))->getAsUnquotedString();
std::string Value = cast<StringInit>(DI->getArg(1))->getAsUnquotedString();
return std::make_pair(Type::fromTypedefName(Ty), Value);
}
std::pair<Type, std::string>
Intrinsic::DagEmitter::emitDagArg(Init *Arg, std::string ArgName) {
if (!ArgName.empty()) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert_with_loc(!Arg->isComplete(),
"Arguments must either be DAGs or names, not both!");
assert_with_loc(Intr.Variables.find(ArgName) != Intr.Variables.end(),
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
"Variable not defined!");
Variable &V = Intr.Variables[ArgName];
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
return std::make_pair(V.getType(), V.getName());
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert(Arg && "Neither ArgName nor Arg?!");
DagInit *DI = dyn_cast<DagInit>(Arg);
assert_with_loc(DI, "Arguments must either be DAGs or names!");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
return emitDag(DI);
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string Intrinsic::generate() {
// Avoid duplicated code for big and little endian
if (isBigEndianSafe()) {
generateImpl(false, "", "");
return OS.str();
}
// Little endian intrinsics are simple and don't require any argument
// swapping.
OS << "#ifdef __LITTLE_ENDIAN__\n";
generateImpl(false, "", "");
OS << "#else\n";
// Big endian intrinsics are more complex. The user intended these
// intrinsics to operate on a vector "as-if" loaded by (V)LDR,
// but we load as-if (V)LD1. So we should swap all arguments and
// swap the return value too.
//
// If we call sub-intrinsics, we should call a version that does
// not re-swap the arguments!
generateImpl(true, "", "__noswap_");
// If we're needed early, create a non-swapping variant for
// big-endian.
if (NeededEarly) {
generateImpl(false, "__noswap_", "__noswap_");
}
OS << "#endif\n\n";
return OS.str();
}
void Intrinsic::generateImpl(bool ReverseArguments,
StringRef NamePrefix, StringRef CallPrefix) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
CurrentRecord = R;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// If we call a macro, our local variables may be corrupted due to
// lack of proper lexical scoping. So, add a globally unique postfix
// to every variable.
//
// indexBody() should have set up the Dependencies set by now.
for (auto *I : Dependencies)
if (I->UseMacro) {
VariablePostfix = "_" + utostr(Emitter.getUniqueNumber());
break;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
initVariables();
emitPrototype(NamePrefix);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (IsUnavailable) {
OS << " __attribute__((unavailable));";
} else {
emitOpeningBrace();
emitShadowedArgs();
if (ReverseArguments)
emitArgumentReversal();
emitBody(CallPrefix);
if (ReverseArguments)
emitReturnReversal();
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
emitReturn();
emitClosingBrace();
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
OS << "\n";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
CurrentRecord = nullptr;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void Intrinsic::indexBody() {
CurrentRecord = R;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
initVariables();
emitBody("");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
OS.str("");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
CurrentRecord = nullptr;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
//===----------------------------------------------------------------------===//
// NeonEmitter implementation
//===----------------------------------------------------------------------===//
Intrinsic &NeonEmitter::getIntrinsic(StringRef Name, ArrayRef<Type> Types,
Optional<std::string> MangledName) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// First, look up the name in the intrinsic map.
assert_with_loc(IntrinsicMap.find(Name.str()) != IntrinsicMap.end(),
("Intrinsic '" + Name + "' not found!").str());
auto &V = IntrinsicMap.find(Name.str())->second;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::vector<Intrinsic *> GoodVec;
// Create a string to print if we end up failing.
std::string ErrMsg = "looking up intrinsic '" + Name.str() + "(";
for (unsigned I = 0; I < Types.size(); ++I) {
if (I != 0)
ErrMsg += ", ";
ErrMsg += Types[I].str();
}
ErrMsg += ")'\n";
ErrMsg += "Available overloads:\n";
// Now, look through each intrinsic implementation and see if the types are
// compatible.
for (auto &I : V) {
ErrMsg += " - " + I.getReturnType().str() + " " + I.getMangledName();
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
ErrMsg += "(";
for (unsigned A = 0; A < I.getNumParams(); ++A) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (A != 0)
ErrMsg += ", ";
ErrMsg += I.getParamType(A).str();
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
}
ErrMsg += ")\n";
if (MangledName && MangledName != I.getMangledName(true))
continue;
if (I.getNumParams() != Types.size())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
continue;
unsigned ArgNum = 0;
bool MatchingArgumentTypes =
std::all_of(Types.begin(), Types.end(), [&](const auto &Type) {
return Type == I.getParamType(ArgNum++);
});
if (MatchingArgumentTypes)
GoodVec.push_back(&I);
}
assert_with_loc(!GoodVec.empty(),
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
"No compatible intrinsic found - " + ErrMsg);
assert_with_loc(GoodVec.size() == 1, "Multiple overloads found - " + ErrMsg);
return *GoodVec.front();
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void NeonEmitter::createIntrinsic(Record *R,
SmallVectorImpl<Intrinsic *> &Out) {
std::string Name = std::string(R->getValueAsString("Name"));
std::string Proto = std::string(R->getValueAsString("Prototype"));
std::string Types = std::string(R->getValueAsString("Types"));
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Record *OperationRec = R->getValueAsDef("Operation");
bool CartesianProductOfTypes = R->getValueAsBit("CartesianProductOfTypes");
bool BigEndianSafe = R->getValueAsBit("BigEndianSafe");
std::string Guard = std::string(R->getValueAsString("ArchGuard"));
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
bool IsUnavailable = OperationRec->getValueAsBit("Unavailable");
// Set the global current record. This allows assert_with_loc to produce
// decent location information even when highly nested.
CurrentRecord = R;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
ListInit *Body = OperationRec->getValueAsListInit("Ops");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::vector<TypeSpec> TypeSpecs = TypeSpec::fromTypeSpecs(Types);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
ClassKind CK = ClassNone;
if (R->getSuperClasses().size() >= 2)
CK = ClassMap[R->getSuperClasses()[1].first];
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::vector<std::pair<TypeSpec, TypeSpec>> NewTypeSpecs;
for (auto TS : TypeSpecs) {
if (CartesianProductOfTypes) {
Type DefaultT(TS, ".");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (auto SrcTS : TypeSpecs) {
Type DefaultSrcT(SrcTS, ".");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (TS == SrcTS ||
DefaultSrcT.getSizeInBits() != DefaultT.getSizeInBits())
continue;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
NewTypeSpecs.push_back(std::make_pair(TS, SrcTS));
}
} else {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
NewTypeSpecs.push_back(std::make_pair(TS, TS));
}
}
llvm::sort(NewTypeSpecs);
NewTypeSpecs.erase(std::unique(NewTypeSpecs.begin(), NewTypeSpecs.end()),
NewTypeSpecs.end());
auto &Entry = IntrinsicMap[Name];
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (auto &I : NewTypeSpecs) {
Entry.emplace_back(R, Name, Proto, I.first, I.second, CK, Body, *this,
Guard, IsUnavailable, BigEndianSafe);
Out.push_back(&Entry.back());
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
CurrentRecord = nullptr;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
/// genBuiltinsDef: Generate the BuiltinsARM.def and BuiltinsAArch64.def
/// declaration of builtins, checking for unique builtin declarations.
void NeonEmitter::genBuiltinsDef(raw_ostream &OS,
SmallVectorImpl<Intrinsic *> &Defs) {
OS << "#ifdef GET_NEON_BUILTINS\n";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// We only want to emit a builtin once, and we want to emit them in
// alphabetical order, so use a std::set.
std::set<std::string> Builtins;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (auto *Def : Defs) {
if (Def->hasBody())
continue;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string S = "BUILTIN(__builtin_neon_" + Def->getMangledName() + ", \"";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
S += Def->getBuiltinTypeStr();
S += "\", \"n\")";
Builtins.insert(S);
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (auto &S : Builtins)
OS << S << "\n";
OS << "#endif\n\n";
}
/// Generate the ARM and AArch64 overloaded type checking code for
/// SemaChecking.cpp, checking for unique builtin declarations.
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
void NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS,
SmallVectorImpl<Intrinsic *> &Defs) {
OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
// We record each overload check line before emitting because subsequent Inst
// definitions may extend the number of permitted types (i.e. augment the
// Mask). Use std::map to avoid sorting the table by hash number.
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
struct OverloadInfo {
uint64_t Mask;
int PtrArgNum;
bool HasConstPtr;
OverloadInfo() : Mask(0ULL), PtrArgNum(0), HasConstPtr(false) {}
};
std::map<std::string, OverloadInfo> OverloadMap;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (auto *Def : Defs) {
// If the def has a body (that is, it has Operation DAGs), it won't call
// __builtin_neon_* so we don't need to generate a definition for it.
if (Def->hasBody())
continue;
// Functions which have a scalar argument cannot be overloaded, no need to
// check them if we are emitting the type checking code.
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (Def->protoHasScalar())
continue;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
uint64_t Mask = 0ULL;
Mask |= 1ULL << Def->getPolymorphicKeyType().getNeonEnum();
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Check if the function has a pointer or const pointer argument.
int PtrArgNum = -1;
bool HasConstPtr = false;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (unsigned I = 0; I < Def->getNumParams(); ++I) {
const auto &Type = Def->getParamType(I);
if (Type.isPointer()) {
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
PtrArgNum = I;
HasConstPtr = Type.isConstPointer();
}
}
// For sret builtins, adjust the pointer argument index.
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (PtrArgNum >= 0 && Def->getReturnType().getNumVectors() > 1)
PtrArgNum += 1;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string Name = Def->getName();
// Omit type checking for the pointer arguments of vld1_lane, vld1_dup,
// and vst1_lane intrinsics. Using a pointer to the vector element
// type with one of those operations causes codegen to select an aligned
// load/store instruction. If you want an unaligned operation,
// the pointer argument needs to have less alignment than element type,
// so just accept any pointer type.
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (Name == "vld1_lane" || Name == "vld1_dup" || Name == "vst1_lane") {
PtrArgNum = -1;
HasConstPtr = false;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (Mask) {
std::string Name = Def->getMangledName();
OverloadMap.insert(std::make_pair(Name, OverloadInfo()));
OverloadInfo &OI = OverloadMap[Name];
OI.Mask |= Mask;
OI.PtrArgNum |= PtrArgNum;
OI.HasConstPtr = HasConstPtr;
}
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (auto &I : OverloadMap) {
OverloadInfo &OI = I.second;
OS << "case NEON::BI__builtin_neon_" << I.first << ": ";
OS << "mask = 0x" << Twine::utohexstr(OI.Mask) << "ULL";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (OI.PtrArgNum >= 0)
OS << "; PtrArgNum = " << OI.PtrArgNum;
if (OI.HasConstPtr)
OS << "; HasConstPtr = true";
OS << "; break;\n";
}
OS << "#endif\n\n";
}
void NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS,
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
SmallVectorImpl<Intrinsic *> &Defs) {
OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::set<std::string> Emitted;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (auto *Def : Defs) {
if (Def->hasBody())
continue;
// Functions which do not have an immediate do not need to have range
// checking code emitted.
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (!Def->hasImmediate())
continue;
if (Emitted.find(Def->getMangledName()) != Emitted.end())
continue;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
std::string LowerBound, UpperBound;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Record *R = Def->getRecord();
if (R->getValueAsBit("isVCVT_N")) {
// VCVT between floating- and fixed-point values takes an immediate
// in the range [1, 32) for f32 or [1, 64) for f64 or [1, 16) for f16.
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
LowerBound = "1";
if (Def->getBaseType().getElementSizeInBits() == 16 ||
Def->getName().find('h') != std::string::npos)
// VCVTh operating on FP16 intrinsics in range [1, 16)
UpperBound = "15";
else if (Def->getBaseType().getElementSizeInBits() == 32)
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
UpperBound = "31";
else
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
UpperBound = "63";
} else if (R->getValueAsBit("isScalarShift")) {
// Right shifts have an 'r' in the name, left shifts do not. Convert
// instructions have the same bounds and right shifts.
if (Def->getName().find('r') != std::string::npos ||
Def->getName().find("cvt") != std::string::npos)
LowerBound = "1";
UpperBound = utostr(Def->getReturnType().getElementSizeInBits() - 1);
} else if (R->getValueAsBit("isShift")) {
// Builtins which are overloaded by type will need to have their upper
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// bound computed at Sema time based on the type constant.
// Right shifts have an 'r' in the name, left shifts do not.
if (Def->getName().find('r') != std::string::npos)
LowerBound = "1";
UpperBound = "RFT(TV, true)";
} else if (Def->getClassKind(true) == ClassB) {
// ClassB intrinsics have a type (and hence lane number) that is only
// known at runtime.
if (R->getValueAsBit("isLaneQ"))
UpperBound = "RFT(TV, false, true)";
else
UpperBound = "RFT(TV, false, false)";
} else {
// The immediate generally refers to a lane in the preceding argument.
assert(Def->getImmediateIdx() > 0);
Type T = Def->getParamType(Def->getImmediateIdx() - 1);
UpperBound = utostr(T.getNumElements() - 1);
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Calculate the index of the immediate that should be range checked.
unsigned Idx = Def->getNumParams();
if (Def->hasImmediate())
Idx = Def->getGeneratedParamIdx(Def->getImmediateIdx());
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
OS << "case NEON::BI__builtin_neon_" << Def->getMangledName() << ": "
<< "i = " << Idx << ";";
if (!LowerBound.empty())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
OS << " l = " << LowerBound << ";";
if (!UpperBound.empty())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
OS << " u = " << UpperBound << ";";
OS << " break;\n";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
Emitted.insert(Def->getMangledName());
}
OS << "#endif\n\n";
}
/// runHeader - Emit a file with sections defining:
/// 1. the NEON section of BuiltinsARM.def and BuiltinsAArch64.def.
/// 2. the SemaChecking code for the type overload checking.
/// 3. the SemaChecking code for validation of intrinsic immediate arguments.
void NeonEmitter::runHeader(raw_ostream &OS) {
std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
SmallVector<Intrinsic *, 128> Defs;
for (auto *R : RV)
createIntrinsic(R, Defs);
// Generate shared BuiltinsXXX.def
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
genBuiltinsDef(OS, Defs);
// Generate ARM overloaded type checking code for SemaChecking.cpp
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
genOverloadTypeCheckCode(OS, Defs);
// Generate ARM range checking code for shift/lane immediates.
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
genIntrinsicRangeCheckCode(OS, Defs);
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
/// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h
/// is comprised of type definitions and function declarations.
void NeonEmitter::run(raw_ostream &OS) {
OS << "/*===---- arm_neon.h - ARM Neon intrinsics "
"------------------------------"
"---===\n"
" *\n"
" * Permission is hereby granted, free of charge, to any person "
"obtaining "
"a copy\n"
" * of this software and associated documentation files (the "
"\"Software\"),"
" to deal\n"
" * in the Software without restriction, including without limitation "
"the "
"rights\n"
" * to use, copy, modify, merge, publish, distribute, sublicense, "
"and/or sell\n"
" * copies of the Software, and to permit persons to whom the Software "
"is\n"
" * furnished to do so, subject to the following conditions:\n"
" *\n"
" * The above copyright notice and this permission notice shall be "
"included in\n"
" * all copies or substantial portions of the Software.\n"
" *\n"
" * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, "
"EXPRESS OR\n"
" * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
"MERCHANTABILITY,\n"
" * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT "
"SHALL THE\n"
" * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR "
"OTHER\n"
" * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, "
"ARISING FROM,\n"
" * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER "
"DEALINGS IN\n"
" * THE SOFTWARE.\n"
" *\n"
" *===-----------------------------------------------------------------"
"---"
"---===\n"
" */\n\n";
OS << "#ifndef __ARM_NEON_H\n";
OS << "#define __ARM_NEON_H\n\n";
OS << "#if !defined(__ARM_NEON)\n";
OS << "#error \"NEON support not enabled\"\n";
OS << "#endif\n\n";
OS << "#include <stdint.h>\n\n";
// Emit NEON-specific scalar typedefs.
OS << "typedef float float32_t;\n";
OS << "typedef __fp16 float16_t;\n";
OS << "#ifdef __aarch64__\n";
OS << "typedef double float64_t;\n";
OS << "#endif\n\n";
// For now, signedness of polynomial types depends on target
OS << "#ifdef __aarch64__\n";
OS << "typedef uint8_t poly8_t;\n";
OS << "typedef uint16_t poly16_t;\n";
OS << "typedef uint64_t poly64_t;\n";
OS << "typedef __uint128_t poly128_t;\n";
OS << "#else\n";
OS << "typedef int8_t poly8_t;\n";
OS << "typedef int16_t poly16_t;\n";
OS << "typedef int64_t poly64_t;\n";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
OS << "#endif\n";
// Emit Neon vector typedefs.
std::string TypedefTypes(
"cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQdPcQPcPsQPsPlQPl");
std::vector<TypeSpec> TDTypeVec = TypeSpec::fromTypeSpecs(TypedefTypes);
// Emit vector typedefs.
bool InIfdef = false;
for (auto &TS : TDTypeVec) {
bool IsA64 = false;
Type T(TS, ".");
if (T.isDouble())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
IsA64 = true;
if (InIfdef && !IsA64) {
OS << "#endif\n";
InIfdef = false;
}
if (!InIfdef && IsA64) {
OS << "#ifdef __aarch64__\n";
InIfdef = true;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (T.isPoly())
OS << "typedef __attribute__((neon_polyvector_type(";
else
OS << "typedef __attribute__((neon_vector_type(";
Type T2 = T;
T2.makeScalar();
OS << T.getNumElements() << "))) ";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
OS << T2.str();
OS << " " << T.str() << ";\n";
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (InIfdef)
OS << "#endif\n";
OS << "\n";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Emit struct typedefs.
InIfdef = false;
for (unsigned NumMembers = 2; NumMembers <= 4; ++NumMembers) {
for (auto &TS : TDTypeVec) {
bool IsA64 = false;
Type T(TS, ".");
if (T.isDouble())
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
IsA64 = true;
if (InIfdef && !IsA64) {
OS << "#endif\n";
InIfdef = false;
}
if (!InIfdef && IsA64) {
OS << "#ifdef __aarch64__\n";
InIfdef = true;
}
const char Mods[] = { static_cast<char>('2' + (NumMembers - 2)), 0};
Type VT(TS, Mods);
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
OS << "typedef struct " << VT.str() << " {\n";
OS << " " << T.str() << " val";
OS << "[" << NumMembers << "]";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
OS << ";\n} ";
OS << VT.str() << ";\n";
OS << "\n";
}
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
if (InIfdef)
OS << "#endif\n";
OS << "\n";
OS << "#define __ai static __inline__ __attribute__((__always_inline__, "
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
"__nodebug__))\n\n";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
SmallVector<Intrinsic *, 128> Defs;
std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
for (auto *R : RV)
createIntrinsic(R, Defs);
for (auto *I : Defs)
I->indexBody();
llvm::stable_sort(Defs, llvm::deref<std::less<>>());
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Only emit a def when its requirements have been met.
// FIXME: This loop could be made faster, but it's fast enough for now.
bool MadeProgress = true;
std::string InGuard;
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
while (!Defs.empty() && MadeProgress) {
MadeProgress = false;
for (SmallVector<Intrinsic *, 128>::iterator I = Defs.begin();
I != Defs.end(); /*No step*/) {
bool DependenciesSatisfied = true;
for (auto *II : (*I)->getDependencies()) {
if (llvm::is_contained(Defs, II))
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
DependenciesSatisfied = false;
}
if (!DependenciesSatisfied) {
// Try the next one.
++I;
continue;
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Emit #endif/#if pair if needed.
if ((*I)->getGuard() != InGuard) {
if (!InGuard.empty())
OS << "#endif\n";
InGuard = (*I)->getGuard();
if (!InGuard.empty())
OS << "#if " << InGuard << "\n";
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
// Actually generate the intrinsic code.
OS << (*I)->generate();
MadeProgress = true;
I = Defs.erase(I);
}
}
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
assert(Defs.empty() && "Some requirements were not satisfied!");
if (!InGuard.empty())
OS << "#endif\n";
Rewrite ARM NEON intrinsic emission completely. There comes a time in the life of any amateur code generator when dumb string concatenation just won't cut it any more. For NeonEmitter.cpp, that time has come. There were a bunch of magic type codes which meant different things depending on the context. There were a bunch of special cases that really had no reason to be there but the whole thing was so creaky that removing them would cause something weird to fall over. There was a 1000 line switch statement for code generation involving string concatenation, which actually did lexical scoping to an extent (!!) with a bunch of semi-repeated cases. I tried to refactor this three times in three different ways without success. The only way forward was to rewrite the entire thing. Luckily the testing coverage on this stuff is absolutely massive, both with regression tests and the "emperor" random test case generator. The main change is that previously, in arm_neon.td a bunch of "Operation"s were defined with special names. NeonEmitter.cpp knew about these Operations and would emit code based on a huge switch. Actually this doesn't make much sense - the type information was held as strings, so type checking was impossible. Also TableGen's DAG type actually suits this sort of code generation very well (surprising that...) So now every operation is defined in terms of TableGen DAGs. There are a bunch of operators to use, including "op" (a generic unary or binary operator), "call" (to call other intrinsics) and "shuffle" (take a guess...). One of the main advantages of this apart from making it more obvious what is going on, is that we have proper type inference. This has two obvious advantages: 1) TableGen can error on bad intrinsic definitions easier, instead of just generating wrong code. 2) Calls to other intrinsics are typechecked too. So we no longer need to work out whether the thing we call needs to be the Q-lane version or the D-lane version - TableGen knows that itself! Here's an example: before: case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { // vabd results are always unsigned and must be zero-extended. std::string utype = "U" + typestr.str(); s += "(" + TypeString(proto[0], typestr) + ")"; abd = "(" + TypeString('d', utype) + ")" + abd; s += Extend(utype, abd) + ";"; } else { s += Extend(typestr, abd) + ";"; } break; } after: def OP_ABDL : Op<(cast "R", (call "vmovl", (cast $p0, "U", (call "vabd", $p0, $p1))))>; As an example of what happens if you do something wrong now, here's what happens if you make $p0 unsigned before the call to "vabd" - that is, $p0 -> (cast "U", $p0): arm_neon.td:574:1: error: No compatible intrinsic found - looking up intrinsic 'vabd(uint8x8_t, int8x8_t)' Available overloads: - float64x2_t vabdq_v(float64x2_t, float64x2_t) - float64x1_t vabd_v(float64x1_t, float64x1_t) - float64_t vabdd_f64(float64_t, float64_t) - float32_t vabds_f32(float32_t, float32_t) ... snip ... This makes it seriously easy to work out what you've done wrong in fairly nasty intrinsics. As part of this I've massively beefed up the documentation in arm_neon.td too. Things still to do / on the radar: - Testcase generation. This was implemented in the previous version and not in the new one, because - Autogenerated tests are not being run. The testcase in test/ differs from the autogenerated version. - There were a whole slew of special cases in the testcase generation that just felt (and looked) like hacks. If someone really feels strongly about this, I can try and reimplement it too. - Big endian. That's coming soon and should be a very small diff on top of this one. llvm-svn: 211101
2014-06-17 21:11:27 +08:00
OS << "\n";
OS << "#undef __ai\n\n";
OS << "#endif /* __ARM_NEON_H */\n";
}
/// run - Read the records in arm_fp16.td and output arm_fp16.h. arm_fp16.h
/// is comprised of type definitions and function declarations.
void NeonEmitter::runFP16(raw_ostream &OS) {
OS << "/*===---- arm_fp16.h - ARM FP16 intrinsics "
"------------------------------"
"---===\n"
" *\n"
" * Permission is hereby granted, free of charge, to any person "
"obtaining a copy\n"
" * of this software and associated documentation files (the "
"\"Software\"), to deal\n"
" * in the Software without restriction, including without limitation "
"the rights\n"
" * to use, copy, modify, merge, publish, distribute, sublicense, "
"and/or sell\n"
" * copies of the Software, and to permit persons to whom the Software "
"is\n"
" * furnished to do so, subject to the following conditions:\n"
" *\n"
" * The above copyright notice and this permission notice shall be "
"included in\n"
" * all copies or substantial portions of the Software.\n"
" *\n"
" * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, "
"EXPRESS OR\n"
" * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
"MERCHANTABILITY,\n"
" * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT "
"SHALL THE\n"
" * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR "
"OTHER\n"
" * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, "
"ARISING FROM,\n"
" * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER "
"DEALINGS IN\n"
" * THE SOFTWARE.\n"
" *\n"
" *===-----------------------------------------------------------------"
"---"
"---===\n"
" */\n\n";
OS << "#ifndef __ARM_FP16_H\n";
OS << "#define __ARM_FP16_H\n\n";
OS << "#include <stdint.h>\n\n";
OS << "typedef __fp16 float16_t;\n";
OS << "#define __ai static __inline__ __attribute__((__always_inline__, "
"__nodebug__))\n\n";
SmallVector<Intrinsic *, 128> Defs;
std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
for (auto *R : RV)
createIntrinsic(R, Defs);
for (auto *I : Defs)
I->indexBody();
llvm::stable_sort(Defs, llvm::deref<std::less<>>());
// Only emit a def when its requirements have been met.
// FIXME: This loop could be made faster, but it's fast enough for now.
bool MadeProgress = true;
std::string InGuard;
while (!Defs.empty() && MadeProgress) {
MadeProgress = false;
for (SmallVector<Intrinsic *, 128>::iterator I = Defs.begin();
I != Defs.end(); /*No step*/) {
bool DependenciesSatisfied = true;
for (auto *II : (*I)->getDependencies()) {
if (llvm::is_contained(Defs, II))
DependenciesSatisfied = false;
}
if (!DependenciesSatisfied) {
// Try the next one.
++I;
continue;
}
// Emit #endif/#if pair if needed.
if ((*I)->getGuard() != InGuard) {
if (!InGuard.empty())
OS << "#endif\n";
InGuard = (*I)->getGuard();
if (!InGuard.empty())
OS << "#if " << InGuard << "\n";
}
// Actually generate the intrinsic code.
OS << (*I)->generate();
MadeProgress = true;
I = Defs.erase(I);
}
}
assert(Defs.empty() && "Some requirements were not satisfied!");
if (!InGuard.empty())
OS << "#endif\n";
OS << "\n";
OS << "#undef __ai\n\n";
OS << "#endif /* __ARM_FP16_H */\n";
}
void clang::EmitNeon(RecordKeeper &Records, raw_ostream &OS) {
NeonEmitter(Records).run(OS);
}
void clang::EmitFP16(RecordKeeper &Records, raw_ostream &OS) {
NeonEmitter(Records).runFP16(OS);
}
void clang::EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) {
NeonEmitter(Records).runHeader(OS);
}
void clang::EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) {
llvm_unreachable("Neon test generation no longer implemented!");
}