summaryrefslogtreecommitdiff
path: root/source/slang/lower-to-ir.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoley@nvidia.com>2017-09-06 14:56:28 -0700
committerTim Foley <tfoley@nvidia.com>2017-09-07 09:16:41 -0700
commitad3539574f52634c51523cfec1747e7565ad8876 (patch)
treef32462f6c191a30aa1333e6695c9be0aa2fd4df1 /source/slang/lower-to-ir.cpp
parentca16ede67d3fc34ec1cc81b8f835199c5ef1ab9a (diff)
Replace old notion of "intrinsic" operations
The code previously had an enumerated type for "intrinsic" operations, and allowed functions to be marked `__intrinsic_op(...)` to indicate the operation they map to. The nature of the IR meant that each of these intrinsic ops had to have a corresponding IR opcode, but the `enum` types weren't the same. This change cleans things up a bit by deciding that the `__intrinsic_op(...)` modifier names an actual IR opcode, and so the `IntrinsicOp` enum is gone. The biggest source of complexity here is that there are certain operations that need to be "intrinsic"-ish for the purposes of the current AST-based translation path, because we need them to round-trip from source to AST and back. Right now this is being handled by defining a bunch of "pseudo-ops" which can be used in the `__intrinsic_op` modifier, but which are *not* meant to be represented in the IR. Currently I don't actually handle this during IR generation. In the long run, once we are using IR for everything that needs cross-compilation, we should be able to eliminate the pseudo-ops in favor of just having these be ordinary (inline) functions defined in the stdlib (e.g., the `+=` operator can just have a direct definition). There was a second category of modifier that gets a little caught up in this, which is the `__intrinsic` modifier, which got used in two ways: 1. A function marked `__intrinsic(glsl, ...)` had what I call a "target intrinsic" modifier, which specified how to lower it for a specific target (e.g., GLSL). 2. A function just marked `__intrinsic` was supposed to be a marker for "this function shouldn't be emitted in the output, because the implementation is expected to be provided" The latter category of function should really be an `__intrinsic_op`, so I translated all those uses. I added a tiny bit of sugar so that `__intrinsic_op` without an explicit opcode will look up an opcode based on the name of the function being called, so that an operation like `sin` can automatically be plumbed through to an equivalent IR op. (The first category is a stopgap for the AST-based cross-compilation, and will hopefully be replaced by something better as we get the IR-based path working). Getting the switch from `__intrinsic` to `__intrinsic_op` working required shuffling around some code in `emit.cpp` that handles looking up those modifiers and emitting builtin operations appropriately during cross-compilation. Depending on where we go with things, a possible extension of this approach is to allow multiple operands to `__intrinsic_op` so that the first specifies the opcode, and then the rest are literal arguments to specify "sub-ops." This could help us handle stuff like texture-fetch operations without an explosion in the number of opcodes. I still need to think about whether this is a good idea or not.
Diffstat (limited to 'source/slang/lower-to-ir.cpp')
-rw-r--r--source/slang/lower-to-ir.cpp23
1 files changed, 21 insertions, 2 deletions
diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp
index d4cac0337..a8acadb59 100644
--- a/source/slang/lower-to-ir.cpp
+++ b/source/slang/lower-to-ir.cpp
@@ -407,7 +407,7 @@ struct ExprLoweringVisitor : ExprVisitor<ExprLoweringVisitor, LoweredValInfo>
LoweredValInfo lowerIntrinsicCall(
InvokeExpr* expr,
- IntrinsicOp intrinsicOp)
+ IROp intrinsicOp)
{
auto type = lowerSimpleType(context, expr->type);
@@ -431,6 +431,24 @@ struct ExprLoweringVisitor : ExprVisitor<ExprLoweringVisitor, LoweredValInfo>
return LoweredValInfo::simple(getBuilder()->emitCallInst(type, getSimpleVal(loweredFunc), argCount, irArgs.Buffer()));
}
+ IROp getIntrinsicOp(
+ Decl* decl,
+ IntrinsicOpModifier* intrinsicOpMod)
+ {
+ if (int(intrinsicOpMod->op) != 0)
+ return intrinsicOpMod->op;
+
+ // No specified modifier? Then we need to look it up
+ // based on the name of the declaration...
+
+ auto name = decl->getName();
+ auto nameText = getText(name);
+
+ IROp op = findIROp(nameText.Buffer());
+ assert(op != kIROp_Invalid);
+ return op;
+ }
+
LoweredValInfo visitInvokeExpr(InvokeExpr* expr)
{
// TODO: need to detect calls to builtins here, so that we can expand
@@ -443,7 +461,8 @@ struct ExprLoweringVisitor : ExprVisitor<ExprLoweringVisitor, LoweredValInfo>
auto funcDecl = funcDeclRef.getDecl();
if(auto intrinsicOpModifier = funcDecl->FindModifier<IntrinsicOpModifier>())
{
- return lowerIntrinsicCall(expr, intrinsicOpModifier->op);
+ auto op = getIntrinsicOp(funcDecl, intrinsicOpModifier);
+ return lowerIntrinsicCall(expr, op);
//
}
// TODO: handle target intrinsic modifier too...