[WHLSL] Allow uniform buffers to be used in the interpreter
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 29 Sep 2018 02:27:54 +0000 (02:27 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 29 Sep 2018 02:27:54 +0000 (02:27 +0000)
https://bugs.webkit.org/show_bug.cgi?id=189210

Reviewed by Filip Pizlo.

Every lvalue is associated with an address space, and the propagation of these address spaces
matches the propagation of lvalues. Luckily, there was already the infrastructure to do most
of this, so this patch just goes the last few yards. It also updates the standard library to
allow for writing into all writable address spaces for out-params.

* WebGPUShadingLanguageRI/Checker.js:
(Checker.prototype.visitAssignment):
(Checker.prototype._finishVisitingPropertyAccess):
* WebGPUShadingLanguageRI/Intrinsics.js:
(Intrinsics.):
(Intrinsics.checkFalse):
(Intrinsics):
* WebGPUShadingLanguageRI/StandardLibrary.js:
(let.standardLibrary):
* WebGPUShadingLanguageRI/Test.js:
(tests.threadArrayRefLoad):
(tests.threadArrayRefLoadIntLiteral):
(tests.deviceArrayRefLoad):
(tests.threadArrayRefStore):
(tests.deviceArrayRefStore):
(tests.deviceArrayRefStoreIntLiteral):
(tests.threadPointerLoad):
(tests.threadPointerStore):
(tests.devicePointerLoad):
(tests.devicePointerStore):
(tests.arrayLoad):
(tests.constantAddressSpace):
(tests.standardLibraryDevicePointers):
(tests.threadArrayLoad): Deleted.
(tests.threadArrayLoadIntLiteral): Deleted.
(tests.deviceArrayLoad): Deleted.
(tests.threadArrayStore): Deleted.
(tests.deviceArrayStore): Deleted.
(tests.deviceArrayStoreIntLiteral): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@236635 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Tools/ChangeLog
Tools/WebGPUShadingLanguageRI/Checker.js
Tools/WebGPUShadingLanguageRI/Intrinsics.js
Tools/WebGPUShadingLanguageRI/StandardLibrary.js
Tools/WebGPUShadingLanguageRI/Test.js

index 92fa572..81fb0ec 100644 (file)
@@ -1,3 +1,45 @@
+2018-09-28  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [WHLSL] Allow uniform buffers to be used in the interpreter
+        https://bugs.webkit.org/show_bug.cgi?id=189210
+
+        Reviewed by Filip Pizlo.
+
+        Every lvalue is associated with an address space, and the propagation of these address spaces
+        matches the propagation of lvalues. Luckily, there was already the infrastructure to do most
+        of this, so this patch just goes the last few yards. It also updates the standard library to
+        allow for writing into all writable address spaces for out-params.
+
+        * WebGPUShadingLanguageRI/Checker.js:
+        (Checker.prototype.visitAssignment):
+        (Checker.prototype._finishVisitingPropertyAccess):
+        * WebGPUShadingLanguageRI/Intrinsics.js:
+        (Intrinsics.):
+        (Intrinsics.checkFalse):
+        (Intrinsics):
+        * WebGPUShadingLanguageRI/StandardLibrary.js:
+        (let.standardLibrary):
+        * WebGPUShadingLanguageRI/Test.js:
+        (tests.threadArrayRefLoad):
+        (tests.threadArrayRefLoadIntLiteral):
+        (tests.deviceArrayRefLoad):
+        (tests.threadArrayRefStore):
+        (tests.deviceArrayRefStore):
+        (tests.deviceArrayRefStoreIntLiteral):
+        (tests.threadPointerLoad):
+        (tests.threadPointerStore):
+        (tests.devicePointerLoad):
+        (tests.devicePointerStore):
+        (tests.arrayLoad):
+        (tests.constantAddressSpace):
+        (tests.standardLibraryDevicePointers):
+        (tests.threadArrayLoad): Deleted.
+        (tests.threadArrayLoadIntLiteral): Deleted.
+        (tests.deviceArrayLoad): Deleted.
+        (tests.threadArrayStore): Deleted.
+        (tests.deviceArrayStore): Deleted.
+        (tests.deviceArrayStoreIntLiteral): Deleted.
+
 2018-09-28  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         No DOM API to instantiate an attachment for an img element
index 8655cf3..1e99327 100644 (file)
@@ -539,6 +539,10 @@ class Checker extends Visitor {
         let lhsType = node.lhs.visit(this);
         if (!node.lhs.isLValue)
             throw new WTypeError(node.origin.originString, "LHS of assignment is not an LValue: " + node.lhs + node.lhs.notLValueReasonString);
+        if (!isAddressSpace(node.lhs.addressSpace))
+            throw new Error(`${node.origin.originString}: Unknown address space in node ${node.lhs}`);
+        if (node.lhs.addressSpace == "constant")
+            throw new WTypeError(node.origin.originString, "Cannot assign to variable in the constant address space.");
         let rhsType = node.rhs.visit(this);
         if (!lhsType.equalsWithCommit(rhsType))
             throw new WTypeError(node.origin.originString, "Type mismatch in assignment: " + lhsType + " versus " + rhsType);
@@ -699,7 +703,7 @@ class Checker extends Visitor {
             node.notLValueReason = "Base of property access is neither a lvalue nor an array reference";
         } else {
             node.isLValue = true;
-            node.addressSpace = node.base.isLValue ? node.base.addressSpace : baseType.addressSpace;
+            node.addressSpace = baseType.addressSpace ? baseType.addressSpace : node.base.addressSpace;
         }
 
         return node.resultType;
index 9ed6546..96f3c91 100644 (file)
@@ -859,259 +859,261 @@ class Intrinsics {
         for (let setter of BuiltinMatrixSetter.functions())
             this._map.set(setter.toString(), func => setter.instantiateImplementation(func));
 
-        for (let addressSpace of ["thread", "threadgroup", "device"]) {
-            this._map.set(
-                `native void InterlockedAdd(atomic_uint* ${addressSpace},uint,uint* thread)`,
-                func => {
-                    func.implementation = function([atomic, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = value.loadValue();
-                        let result = castToUint(a + b);
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                        atomic.loadValue().copyFrom(EPtr.box(result), 1);
-                    }
-                });
+        for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+            for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                this._map.set(
+                    `native void InterlockedAdd(atomic_uint* ${addressSpace1},uint,uint* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, value, originalValue], node) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = value.loadValue();
+                            let result = castToUint(a + b);
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                            atomic.loadValue().copyFrom(EPtr.box(result), 1);
+                        }
+                    });
 
-            this._map.set(
-                `native void InterlockedAdd(atomic_int* ${addressSpace},int,int* thread)`,
-                func => {
-                    func.implementation = function([atomic, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = value.loadValue();
-                        let result = castToInt(a + b);
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                        atomic.loadValue().copyFrom(EPtr.box(result), 1);
-                    }
-                });
+                this._map.set(
+                    `native void InterlockedAdd(atomic_int* ${addressSpace1},int,int* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, value, originalValue], node) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = value.loadValue();
+                            let result = castToInt(a + b);
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                            atomic.loadValue().copyFrom(EPtr.box(result), 1);
+                        }
+                    });
 
-            this._map.set(
-                `native void InterlockedAnd(atomic_uint* ${addressSpace},uint,uint* thread)`,
-                func => {
-                    func.implementation = function([atomic, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = value.loadValue();
-                        let result = castToUint(a & b);
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                        atomic.loadValue().copyFrom(EPtr.box(result), 1);
-                    }
-                });
+                this._map.set(
+                    `native void InterlockedAnd(atomic_uint* ${addressSpace1},uint,uint* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, value, originalValue], node) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = value.loadValue();
+                            let result = castToUint(a & b);
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                            atomic.loadValue().copyFrom(EPtr.box(result), 1);
+                        }
+                    });
 
-            this._map.set(
-                `native void InterlockedAnd(atomic_int* ${addressSpace},int,int* thread)`,
-                func => {
-                    func.implementation = function([atomic, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = value.loadValue();
-                        let result = castToInt(a & b);
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                        atomic.loadValue().copyFrom(EPtr.box(result), 1);
-                    }
-                });
+                this._map.set(
+                    `native void InterlockedAnd(atomic_int* ${addressSpace1},int,int* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, value, originalValue], node) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = value.loadValue();
+                            let result = castToInt(a & b);
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                            atomic.loadValue().copyFrom(EPtr.box(result), 1);
+                        }
+                    });
 
-            this._map.set(
-                `native void InterlockedExchange(atomic_uint* ${addressSpace},uint,uint* thread)`,
-                func => {
-                    func.implementation = function([atomic, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = value.loadValue();
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                        atomic.loadValue().copyFrom(EPtr.box(b), 1);
-                    }
-                });
+                this._map.set(
+                    `native void InterlockedExchange(atomic_uint* ${addressSpace1},uint,uint* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, value, originalValue], node) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = value.loadValue();
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                            atomic.loadValue().copyFrom(EPtr.box(b), 1);
+                        }
+                    });
 
-            this._map.set(
-                `native void InterlockedExchange(atomic_int* ${addressSpace},int,int* thread)`,
-                func => {
-                    func.implementation = function([atomic, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = value.loadValue();
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                        atomic.loadValue().copyFrom(EPtr.box(b), 1);
-                    }
-                });
+                this._map.set(
+                    `native void InterlockedExchange(atomic_int* ${addressSpace1},int,int* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, value, originalValue], node) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = value.loadValue();
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                            atomic.loadValue().copyFrom(EPtr.box(b), 1);
+                        }
+                    });
 
-            this._map.set(
-                `native void InterlockedMax(atomic_uint* ${addressSpace},uint,uint* thread)`,
-                func => {
-                    func.implementation = function([atomic, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = value.loadValue();
-                        let result = castToUint(a > b ? a : b);
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                        atomic.loadValue().copyFrom(EPtr.box(result), 1);
-                    }
-                });
+                this._map.set(
+                    `native void InterlockedMax(atomic_uint* ${addressSpace1},uint,uint* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, value, originalValue], node) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = value.loadValue();
+                            let result = castToUint(a > b ? a : b);
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                            atomic.loadValue().copyFrom(EPtr.box(result), 1);
+                        }
+                    });
 
-            this._map.set(
-                `native void InterlockedMax(atomic_int* ${addressSpace},int,int* thread)`,
-                func => {
-                    func.implementation = function([atomic, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = value.loadValue();
-                        let result = castToInt(a > b ? a : b);
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                        atomic.loadValue().copyFrom(EPtr.box(result), 1);
-                    }
-                });
+                this._map.set(
+                    `native void InterlockedMax(atomic_int* ${addressSpace1},int,int* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, value, originalValue], node) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = value.loadValue();
+                            let result = castToInt(a > b ? a : b);
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                            atomic.loadValue().copyFrom(EPtr.box(result), 1);
+                        }
+                    });
 
-            this._map.set(
-                `native void InterlockedMin(atomic_uint* ${addressSpace},uint,uint* thread)`,
-                func => {
-                    func.implementation = function([atomic, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = value.loadValue();
-                        let result = castToUint(a < b ? a : b);
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                        atomic.loadValue().copyFrom(EPtr.box(result), 1);
-                    }
-                });
+                this._map.set(
+                    `native void InterlockedMin(atomic_uint* ${addressSpace1},uint,uint* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, value, originalValue], node) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = value.loadValue();
+                            let result = castToUint(a < b ? a : b);
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                            atomic.loadValue().copyFrom(EPtr.box(result), 1);
+                        }
+                    });
 
-            this._map.set(
-                `native void InterlockedMin(atomic_int* ${addressSpace},int,int* thread)`,
-                func => {
-                    func.implementation = function([atomic, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = value.loadValue();
-                        let result = castToInt(a < b ? a : b);
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                        atomic.loadValue().copyFrom(EPtr.box(result), 1);
-                    }
-                });
+                this._map.set(
+                    `native void InterlockedMin(atomic_int* ${addressSpace1},int,int* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, value, originalValue], node) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = value.loadValue();
+                            let result = castToInt(a < b ? a : b);
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                            atomic.loadValue().copyFrom(EPtr.box(result), 1);
+                        }
+                    });
 
-            this._map.set(
-                `native void InterlockedOr(atomic_uint* ${addressSpace},uint,uint* thread)`,
-                func => {
-                    func.implementation = function([atomic, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = value.loadValue();
-                        let result = castToUint(a | b);
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                        atomic.loadValue().copyFrom(EPtr.box(result), 1);
-                    }
-                });
+                this._map.set(
+                    `native void InterlockedOr(atomic_uint* ${addressSpace1},uint,uint* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, value, originalValue], node) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = value.loadValue();
+                            let result = castToUint(a | b);
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                            atomic.loadValue().copyFrom(EPtr.box(result), 1);
+                        }
+                    });
 
-            this._map.set(
-                `native void InterlockedOr(atomic_int* ${addressSpace},int,int* thread)`,
-                func => {
-                    func.implementation = function([atomic, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = value.loadValue();
-                        let result = castToInt(a | b);
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                        atomic.loadValue().copyFrom(EPtr.box(result), 1);
-                    }
-                });
+                this._map.set(
+                    `native void InterlockedOr(atomic_int* ${addressSpace1},int,int* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, value, originalValue], node) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = value.loadValue();
+                            let result = castToInt(a | b);
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                            atomic.loadValue().copyFrom(EPtr.box(result), 1);
+                        }
+                    });
 
-            this._map.set(
-                `native void InterlockedXor(atomic_uint* ${addressSpace},uint,uint* thread)`,
-                func => {
-                    func.implementation = function([atomic, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = value.loadValue();
-                        let result = castToUint(a ^ b);
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                        atomic.loadValue().copyFrom(EPtr.box(result), 1);
-                    }
-                });
+                this._map.set(
+                    `native void InterlockedXor(atomic_uint* ${addressSpace1},uint,uint* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, value, originalValue], node) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = value.loadValue();
+                            let result = castToUint(a ^ b);
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                            atomic.loadValue().copyFrom(EPtr.box(result), 1);
+                        }
+                    });
 
-            this._map.set(
-                `native void InterlockedXor(atomic_int* ${addressSpace},int,int* thread)`,
-                func => {
-                    func.implementation = function([atomic, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = value.loadValue();
-                        let result = castToInt(a ^ b);
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                        atomic.loadValue().copyFrom(EPtr.box(result), 1);
-                    }
-                });
+                this._map.set(
+                    `native void InterlockedXor(atomic_int* ${addressSpace1},int,int* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, value, originalValue], node) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = value.loadValue();
+                            let result = castToInt(a ^ b);
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                            atomic.loadValue().copyFrom(EPtr.box(result), 1);
+                        }
+                    });
 
-            this._map.set(
-                `native void InterlockedCompareExchange(atomic_uint* ${addressSpace},uint,uint,uint* thread)`,
-                func => {
-                    func.implementation = function([atomic, compareValue, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = compareValue.loadValue();
-                        let c = value.loadValue();
-                        if (a == b)
-                            atomic.loadValue().copyFrom(EPtr.box(c), 1);
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                    }
-                });
+                this._map.set(
+                    `native void InterlockedCompareExchange(atomic_uint* ${addressSpace1},uint,uint,uint* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, compareValue, value, originalValue]) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = compareValue.loadValue();
+                            let c = value.loadValue();
+                            if (a == b)
+                                atomic.loadValue().copyFrom(EPtr.box(c), 1);
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                        }
+                    });
 
-            this._map.set(
-                `native void InterlockedCompareExchange(atomic_int* ${addressSpace},int,int,int* thread)`,
-                func => {
-                    func.implementation = function([atomic, compareValue, value, originalValue]) {
-                        if (!atomic.loadValue())
-                            throw new WTrapError("[Atomics]", "Null atomic pointer");
-                        let a = atomic.loadValue().loadValue();
-                        let b = compareValue.loadValue();
-                        let c = value.loadValue();
-                        if (a == b)
-                            atomic.loadValue().copyFrom(EPtr.box(c), 1);
-                        if (originalValue.loadValue())
-                            originalValue.loadValue().copyFrom(EPtr.box(a), 1);
-                    }
-                });
+                this._map.set(
+                    `native void InterlockedCompareExchange(atomic_int* ${addressSpace1},int,int,int* ${addressSpace2})`,
+                    func => {
+                        func.implementation = function([atomic, compareValue, value, originalValue]) {
+                            if (!atomic.loadValue())
+                                throw new WTrapError(node.origin.originString, "Null atomic pointer");
+                            let a = atomic.loadValue().loadValue();
+                            let b = compareValue.loadValue();
+                            let c = value.loadValue();
+                            if (a == b)
+                                atomic.loadValue().copyFrom(EPtr.box(c), 1);
+                            if (originalValue.loadValue())
+                                originalValue.loadValue().copyFrom(EPtr.box(a), 1);
+                        }
+                    });
+            }
         }
 
         function checkUndefined(origin, explanation, value)
         {
             if (value == undefined)
-                throw new WTrapError("[Load]", "Texture read out of bounds");
+                throw new WTrapError(origin, "Texture read out of bounds");
             return value;
         }
 
         function checkFalse(origin, explanation, value)
         {
             if (value == false)
-                throw new WTrapError("[Store]", "Texture store out of bounds");
+                throw new WTrapError(origin, "Texture store out of bounds");
         }
 
         function boxVector(a)
@@ -1160,33 +1162,37 @@ class Intrinsics {
                 this._map.set(
                     `native ${type}${length} Load(Texture1D<${type}${length}>,int2 location)`,
                     func => {
-                        func.implementation = function ([texture, location]) {
-                            return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(1), 0, 0, location.get(0))));
+                        func.implementation = function ([texture, location], node) {
+                            return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(1), 0, 0, location.get(0))));
                         }
                     });
                 this._map.set(
                     `native ${type}${length} Load(Texture1D<${type}${length}>,int2 location,int offset)`,
                     func => {
-                        func.implementation = function ([texture, location, offset]) {
-                            return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(1), 0, 0, location.get(0) + offset.loadValue())));
-                        }
-                    });
-                this._map.set(
-                    `native void GetDimensions(Texture1D<${type}${length}>,uint MipLevel,uint* thread Width,uint* thread NumberOfLevels)`,
-                    func => {
-                        func.implementation = function([texture, miplevel, width, numberOfLevels]) {
-                            let tex = texture.loadValue();
-                            let mipID = miplevel.loadValue();
-                            if (mipID >= tex.levelCount)
-                                throw new WTrapError("[GetDimensions]", "Reading from nonexistant mip level of texture");
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
-                            if (numberOfLevels.loadValue())
-                                numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+                        func.implementation = function ([texture, location, offset], node) {
+                            return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(1), 0, 0, location.get(0) + offset.loadValue())));
                         }
                     });
+                for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+                    for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                        this._map.set(
+                            `native void GetDimensions(Texture1D<${type}${length}>,uint MipLevel,uint* ${addressSpace1} Width,uint* ${addressSpace2} NumberOfLevels)`,
+                            func => {
+                                func.implementation = function([texture, miplevel, width, numberOfLevels], node) {
+                                    let tex = texture.loadValue();
+                                    let mipID = miplevel.loadValue();
+                                    if (mipID >= tex.levelCount)
+                                        throw new WTrapError(node.origin.originString, "Reading from nonexistant mip level of texture");
+                                    if (width.loadValue())
+                                        width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
+                                    if (numberOfLevels.loadValue())
+                                        numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+                                }
+                            });
+                    }
+                }
 
-                 this._map.set(
+                this._map.set(
                     `native ${type}${length} Sample(Texture1DArray<${type}${length}>,sampler,float2 location)`,
                     func => {
                         func.implementation = function([texture, sampler, location]) {
@@ -1206,35 +1212,41 @@ class Intrinsics {
                 this._map.set(
                     `native ${type}${length} Load(Texture1DArray<${type}${length}>,int3 location)`,
                     func => {
-                        func.implementation = function ([texture, location]) {
-                            return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(location.get(2), location.get(1), 0, 0, location.get(0))));
+                        func.implementation = function ([texture, location], node) {
+                            return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(location.get(2), location.get(1), 0, 0, location.get(0))));
                         }
                     });
                 this._map.set(
                     `native ${type}${length} Load(Texture1DArray<${type}${length}>,int3 location,int offset)`,
                     func => {
-                        func.implementation = function ([texture, location, offset]) {
-                            return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(location.get(2), location.get(1), 0, 0, location.get(0) + offset.loadValue())));
+                        func.implementation = function ([texture, location, offset], node) {
+                            return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(location.get(2), location.get(1), 0, 0, location.get(0) + offset.loadValue())));
                         }
                     });
-                this._map.set(
-                    `native void GetDimensions(Texture1DArray<${type}${length}>,uint MipLevel,uint* thread Width,uint* thread Elements,uint* thread NumberOfLevels)`,
-                    func => {
-                        func.implementation = function([texture, miplevel, width, elements, numberOfLevels]) {
-                            let tex = texture.loadValue();
-                            let mipID = miplevel.loadValue();
-                            if (mipID >= tex.levelCount)
-                                throw new WTrapError("[GetDimensions]", "Reading from nonexistant mip level of texture");
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
-                            if (elements.loadValue())
-                                elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
-                            if (numberOfLevels.loadValue())
-                                numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+                for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+                    for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                        for (let addressSpace3 of ["thread", "threadgroup", "device"]) {
+                            this._map.set(
+                                `native void GetDimensions(Texture1DArray<${type}${length}>,uint MipLevel,uint* ${addressSpace1} Width,uint* ${addressSpace2} Elements,uint* ${addressSpace3} NumberOfLevels)`,
+                                func => {
+                                    func.implementation = function([texture, miplevel, width, elements, numberOfLevels], node) {
+                                        let tex = texture.loadValue();
+                                        let mipID = miplevel.loadValue();
+                                        if (mipID >= tex.levelCount)
+                                            throw new WTrapError(node.origin.originString, "Reading from nonexistant mip level of texture");
+                                        if (width.loadValue())
+                                            width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
+                                        if (elements.loadValue())
+                                            elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
+                                        if (numberOfLevels.loadValue())
+                                            numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+                                    }
+                                });
                         }
-                    });
+                    }
+                }
 
-                 this._map.set(
+                this._map.set(
                     `native ${type}${length} Sample(Texture2D<${type}${length}>,sampler,float2 location)`,
                     func => {
                         func.implementation = function([texture, sampler, location]) {
@@ -1400,35 +1412,41 @@ class Intrinsics {
                 this._map.set(
                     `native ${type}${length} Load(Texture2D<${type}${length}>,int3 location)`,
                     func => {
-                        func.implementation = function ([texture, location]) {
-                            return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(2), 0, location.get(1), location.get(0))));
+                        func.implementation = function ([texture, location], node) {
+                            return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(2), 0, location.get(1), location.get(0))));
                         }
                     });
                 this._map.set(
                     `native ${type}${length} Load(Texture2D<${type}${length}>,int3 location,int2 offset)`,
                     func => {
-                        func.implementation = function ([texture, location, offset]) {
-                            return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(2), 0, location.get(1) + offset.get(1), location.get(0) + offset.get(0))));
+                        func.implementation = function ([texture, location, offset], node) {
+                            return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(2), 0, location.get(1) + offset.get(1), location.get(0) + offset.get(0))));
                         }
                     });
-                this._map.set(
-                    `native void GetDimensions(Texture2D<${type}${length}>,uint MipLevel,uint* thread Width,uint* thread Height,uint* thread NumberOfLevels)`,
-                    func => {
-                        func.implementation = function([texture, miplevel, width, height, numberOfLevels]) {
-                            let tex = texture.loadValue();
-                            let mipID = miplevel.loadValue();
-                            if (mipID >= tex.levelCount)
-                                throw new WTrapError("[GetDimensions]", "Reading from nonexistant mip level of texture");
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
-                            if (height.loadValue())
-                                height.loadValue().copyFrom(EPtr.box(tex.heightAtLevel(mipID)), 1);
-                            if (numberOfLevels.loadValue())
-                                numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+                for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+                    for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                        for (let addressSpace3 of ["thread", "threadgroup", "device"]) {
+                            this._map.set(
+                                `native void GetDimensions(Texture2D<${type}${length}>,uint MipLevel,uint* ${addressSpace1} Width,uint* ${addressSpace2} Height,uint* ${addressSpace3} NumberOfLevels)`,
+                                func => {
+                                    func.implementation = function([texture, miplevel, width, height, numberOfLevels], node) {
+                                        let tex = texture.loadValue();
+                                        let mipID = miplevel.loadValue();
+                                        if (mipID >= tex.levelCount)
+                                            throw new WTrapError(node.origin.originString, "Reading from nonexistant mip level of texture");
+                                        if (width.loadValue())
+                                            width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
+                                        if (height.loadValue())
+                                            height.loadValue().copyFrom(EPtr.box(tex.heightAtLevel(mipID)), 1);
+                                        if (numberOfLevels.loadValue())
+                                            numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+                                    }
+                                });
                         }
-                    });
+                    }
+                }
 
-                 this._map.set(
+                this._map.set(
                     `native ${type}${length} Sample(Texture2DArray<${type}${length}>,sampler,float3 location)`,
                     func => {
                         func.implementation = function([texture, sampler, location]) {
@@ -1594,37 +1612,45 @@ class Intrinsics {
                 this._map.set(
                     `native ${type}${length} Load(Texture2DArray<${type}${length}>,int4 location)`,
                     func => {
-                        func.implementation = function ([texture, location]) {
-                            return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(location.get(3), location.get(2), 0, location.get(1), location.get(0))));
+                        func.implementation = function ([texture, location], node) {
+                            return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(location.get(3), location.get(2), 0, location.get(1), location.get(0))));
                         }
                     });
                 this._map.set(
                     `native ${type}${length} Load(Texture2DArray<${type}${length}>,int4 location,int2 offset)`,
                     func => {
-                        func.implementation = function ([texture, location, offset]) {
-                            return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(location.get(3), location.get(2), 0, location.get(1) + offset.get(1), location.get(0) + offset.get(0))));
-                        }
-                    });
-                this._map.set(
-                    `native void GetDimensions(Texture2DArray<${type}${length}>,uint MipLevel,uint* thread Width,uint* thread Height,uint* thread Elements,uint* thread NumberOfLevels)`,
-                    func => {
-                        func.implementation = function([texture, miplevel, width, height, elements, numberOfLevels]) {
-                            let tex = texture.loadValue();
-                            let mipID = miplevel.loadValue();
-                            if (mipID >= tex.levelCount)
-                                throw new WTrapError("[GetDimensions]", "Reading from nonexistant mip level of texture");
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
-                            if (height.loadValue())
-                                height.loadValue().copyFrom(EPtr.box(tex.heightAtLevel(mipID)), 1);
-                            if (elements.loadValue())
-                                elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
-                            if (numberOfLevels.loadValue())
-                                numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+                        func.implementation = function ([texture, location, offset], node) {
+                            return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(location.get(3), location.get(2), 0, location.get(1) + offset.get(1), location.get(0) + offset.get(0))));
+                        }
+                    });
+                for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+                    for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                        for (let addressSpace3 of ["thread", "threadgroup", "device"]) {
+                            for (let addressSpace4 of ["thread", "threadgroup", "device"]) {
+                                this._map.set(
+                                    `native void GetDimensions(Texture2DArray<${type}${length}>,uint MipLevel,uint* ${addressSpace1} Width,uint* ${addressSpace2} Height,uint* ${addressSpace3} Elements,uint* ${addressSpace4} NumberOfLevels)`,
+                                    func => {
+                                        func.implementation = function([texture, miplevel, width, height, elements, numberOfLevels], node) {
+                                            let tex = texture.loadValue();
+                                            let mipID = miplevel.loadValue();
+                                            if (mipID >= tex.levelCount)
+                                                throw new WTrapError(node.origin.originString, "Reading from nonexistant mip level of texture");
+                                            if (width.loadValue())
+                                                width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
+                                            if (height.loadValue())
+                                                height.loadValue().copyFrom(EPtr.box(tex.heightAtLevel(mipID)), 1);
+                                            if (elements.loadValue())
+                                                elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
+                                            if (numberOfLevels.loadValue())
+                                                numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+                                        }
+                                    });
+                            }
                         }
-                    });
+                    }
+                }
 
-                 this._map.set(
+                this._map.set(
                     `native ${type}${length} Sample(Texture3D<${type}${length}>,sampler,float3 location)`,
                     func => {
                         func.implementation = function([texture, sampler, location]) {
@@ -1644,37 +1670,45 @@ class Intrinsics {
                 this._map.set(
                     `native ${type}${length} Load(Texture3D<${type}${length}>,int4 location)`,
                     func => {
-                        func.implementation = function ([texture, location]) {
-                            return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(3), location.get(2), location.get(1), location.get(0))));
+                        func.implementation = function ([texture, location], node) {
+                            return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(3), location.get(2), location.get(1), location.get(0))));
                         }
                     });
                 this._map.set(
                     `native ${type}${length} Load(Texture3D<${type}${length}>,int4 location,int3 offset)`,
                     func => {
-                        func.implementation = function ([texture, location, offset]) {
-                            return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(3), location.get(2) + offset.get(2), location.get(1) + offset.get(1), location.get(0) + offset.get(0))));
-                        }
-                    });
-                this._map.set(
-                    `native void GetDimensions(Texture3D<${type}${length}>,uint MipLevel,uint* thread Width,uint* thread Height,uint* thread Depth,uint* thread NumberOfLevels)`,
-                    func => {
-                        func.implementation = function([texture, miplevel, width, height, depth, numberOfLevels]) {
-                            let tex = texture.loadValue();
-                            let mipID = miplevel.loadValue();
-                            if (mipID >= tex.levelCount)
-                                throw new WTrapError("[GetDimensions]", "Reading from nonexistant mip level of texture");
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
-                            if (height.loadValue())
-                                height.loadValue().copyFrom(EPtr.box(tex.heightAtLevel(mipID)), 1);
-                            if (depth.loadValue())
-                                depth.loadValue().copyFrom(EPtr.box(tex.depthAtLevel(mipID)), 1);
-                            if (numberOfLevels.loadValue())
-                                numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+                        func.implementation = function ([texture, location, offset], node) {
+                            return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(3), location.get(2) + offset.get(2), location.get(1) + offset.get(1), location.get(0) + offset.get(0))));
+                        }
+                    });
+                for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+                    for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                        for (let addressSpace3 of ["thread", "threadgroup", "device"]) {
+                            for (let addressSpace4 of ["thread", "threadgroup", "device"]) {
+                                this._map.set(
+                                    `native void GetDimensions(Texture3D<${type}${length}>,uint MipLevel,uint* ${addressSpace1} Width,uint* ${addressSpace2} Height,uint* ${addressSpace3} Depth,uint* ${addressSpace4} NumberOfLevels)`,
+                                    func => {
+                                        func.implementation = function([texture, miplevel, width, height, depth, numberOfLevels], node) {
+                                            let tex = texture.loadValue();
+                                            let mipID = miplevel.loadValue();
+                                            if (mipID >= tex.levelCount)
+                                                throw new WTrapError(node.origin.originString, "Reading from nonexistant mip level of texture");
+                                            if (width.loadValue())
+                                                width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
+                                            if (height.loadValue())
+                                                height.loadValue().copyFrom(EPtr.box(tex.heightAtLevel(mipID)), 1);
+                                            if (depth.loadValue())
+                                                depth.loadValue().copyFrom(EPtr.box(tex.depthAtLevel(mipID)), 1);
+                                            if (numberOfLevels.loadValue())
+                                                numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+                                        }
+                                    });
+                            }
                         }
-                    });
+                    }
+                }
 
-                 this._map.set(
+                this._map.set(
                     `native ${type}${length} Sample(TextureCube<${type}${length}>,sampler,float3 location)`,
                     func => {
                         func.implementation = function([texture, sampler, location]) {
@@ -1754,209 +1788,237 @@ class Intrinsics {
                         }
                     }
                 }
-                this._map.set(
-                    `native void GetDimensions(TextureCube<${type}${length}>,uint MipLevel,uint* thread Width,uint* thread Height,uint* thread NumberOfLevels)`,
-                    func => {
-                        func.implementation = function([texture, miplevel, width, height, numberOfLevels]) {
-                            let tex = texture.loadValue();
-                            let mipID = miplevel.loadValue();
-                            if (tex.layerCount != 6)
-                                throw new Error("Cube texture doesn't have 6 faces");
-                            if (mipID >= tex.levelCount)
-                                throw new WTrapError("[GetDimensions]", "Reading from nonexistant mip level of texture");
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
-                            if (height.loadValue())
-                                height.loadValue().copyFrom(EPtr.box(tex.heightAtLevel(mipID)), 1);
-                            if (numberOfLevels.loadValue())
-                                numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+                for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+                    for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                        for (let addressSpace3 of ["thread", "threadgroup", "device"]) {
+                            this._map.set(
+                                `native void GetDimensions(TextureCube<${type}${length}>,uint MipLevel,uint* ${addressSpace1} Width,uint* ${addressSpace2} Height,uint* ${addressSpace3} NumberOfLevels)`,
+                                func => {
+                                    func.implementation = function([texture, miplevel, width, height, numberOfLevels], node) {
+                                        let tex = texture.loadValue();
+                                        let mipID = miplevel.loadValue();
+                                        if (tex.layerCount != 6)
+                                            throw new Error("Cube texture doesn't have 6 faces");
+                                        if (mipID >= tex.levelCount)
+                                            throw new WTrapError(node.origin.originString, "Reading from nonexistant mip level of texture");
+                                        if (width.loadValue())
+                                            width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
+                                        if (height.loadValue())
+                                            height.loadValue().copyFrom(EPtr.box(tex.heightAtLevel(mipID)), 1);
+                                        if (numberOfLevels.loadValue())
+                                            numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+                                    }
+                                });
                         }
-                    });
+                    }
+                }
 
-                 this._map.set(
-                    `native void GetDimensions(RWTexture1D<${type}${length}>,uint* thread Width)`,
-                    func => {
-                        func.implementation = function([texture, width]) {
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(texture.loadValue().width), 1);
-                        }
-                    });
-                this._map.set(
-                    `native void GetDimensions(RWTexture1D<${type}${length}>,float* thread Width)`,
-                    func => {
-                        func.implementation = function([texture, width]) {
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(texture.loadValue().width), 1);
-                        }
-                    });
+                for (let addressSpace of ["thread", "threadgroup", "device"]) {
+                    this._map.set(
+                        `native void GetDimensions(RWTexture1D<${type}${length}>,uint* ${addressSpace} Width)`,
+                        func => {
+                            func.implementation = function([texture, width]) {
+                                if (width.loadValue())
+                                    width.loadValue().copyFrom(EPtr.box(texture.loadValue().width), 1);
+                            }
+                        });
+                    this._map.set(
+                        `native void GetDimensions(RWTexture1D<${type}${length}>,float* ${addressSpace} Width)`,
+                        func => {
+                            func.implementation = function([texture, width]) {
+                                if (width.loadValue())
+                                    width.loadValue().copyFrom(EPtr.box(texture.loadValue().width), 1);
+                            }
+                        });
+                }
                 this._map.set(
                     `native ${type}${length} Load(RWTexture1D<${type}${length}>,int location)`,
                     func => {
-                        func.implementation = function ([texture, location]) {
-                            return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(0, 0, 0, 0, location.loadValue())));
+                        func.implementation = function ([texture, location], node) {
+                            return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(0, 0, 0, 0, location.loadValue())));
                         }
                     });
                 this._map.set(
                     `native void Store(RWTexture1D<${type}${length}>,${type}${length},uint location)`,
                     func => {
-                        func.implementation = function ([texture, value, location]) {
-                            checkFalse("[Store]", "Texture write out of bounds", texture.loadValue().setElementChecked(0, 0, 0, 0, location.loadValue(), unboxVector(value, length)));
+                        func.implementation = function ([texture, value, location], node) {
+                            checkFalse(node.origin.originString, "Texture write out of bounds", texture.loadValue().setElementChecked(0, 0, 0, 0, location.loadValue(), unboxVector(value, length)));
                         }
                     });
 
-                 this._map.set(
-                    `native void GetDimensions(RWTexture1DArray<${type}${length}>,uint* thread Width,uint* thread Elements)`,
-                    func => {
-                        func.implementation = function([texture, width, elements]) {
-                            let tex = texture.loadValue();
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(tex.width), 1);
-                            if (elements.loadValue())
-                                elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
-                        }
-                    });
-                this._map.set(
-                    `native void GetDimensions(RWTexture1DArray<${type}${length}>,float* thread Width,uint* thread Elements)`,
-                    func => {
-                        func.implementation = function([texture, width, elements]) {
-                            let tex = texture.loadValue();
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(tex.width), 1);
-                            if (elements.loadValue())
-                                elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
-                        }
-                    });
+                for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+                    for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                        this._map.set(
+                            `native void GetDimensions(RWTexture1DArray<${type}${length}>,uint* ${addressSpace1} Width,uint* ${addressSpace2} Elements)`,
+                            func => {
+                                func.implementation = function([texture, width, elements]) {
+                                    let tex = texture.loadValue();
+                                    if (width.loadValue())
+                                        width.loadValue().copyFrom(EPtr.box(tex.width), 1);
+                                    if (elements.loadValue())
+                                        elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
+                                }
+                            });
+                        this._map.set(
+                            `native void GetDimensions(RWTexture1DArray<${type}${length}>,float* ${addressSpace1} Width,uint* ${addressSpace2} Elements)`,
+                            func => {
+                                func.implementation = function([texture, width, elements]) {
+                                    let tex = texture.loadValue();
+                                    if (width.loadValue())
+                                        width.loadValue().copyFrom(EPtr.box(tex.width), 1);
+                                    if (elements.loadValue())
+                                        elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
+                                }
+                            });
+                    }
+                }
                 this._map.set(
                     `native ${type}${length} Load(RWTexture1DArray<${type}${length}>,int2 location)`,
                     func => {
-                        func.implementation = function ([texture, location]) {
-                            return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(location.get(1), 0, 0, 0, location.get(0))));
+                        func.implementation = function ([texture, location], node) {
+                            return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(location.get(1), 0, 0, 0, location.get(0))));
                         }
                     });
                 this._map.set(
                     `native void Store(RWTexture1DArray<${type}${length}>,${type}${length},uint2 location)`,
                     func => {
-                        func.implementation = function ([texture, value, location]) {
-                            checkFalse("[Store]", "Texture write out of bounds", texture.loadValue().setElementChecked(location.get(1), 0, 0, 0, location.get(0), unboxVector(value, length)));
+                        func.implementation = function ([texture, value, location], node) {
+                            checkFalse(node.origin.originString, "Texture write out of bounds", texture.loadValue().setElementChecked(location.get(1), 0, 0, 0, location.get(0), unboxVector(value, length)));
                         }
                     });
 
-                 this._map.set(
-                    `native void GetDimensions(RWTexture2D<${type}${length}>,uint* thread Width,uint* thread Height)`,
-                    func => {
-                        func.implementation = function([texture, width, height]) {
-                            let tex = texture.loadValue();
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(tex.width), 1);
-                            if (height.loadValue())
-                                height.loadValue().copyFrom(EPtr.box(tex.height), 1);
-                        }
-                    });
-                this._map.set(
-                    `native void GetDimensions(RWTexture2D<${type}${length}>,float* thread Width,float* thread Height)`,
-                    func => {
-                        func.implementation = function([texture, width, height]) {
-                            let tex = texture.loadValue();
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(tex.width), 1);
-                            if (height.loadValue())
-                                height.loadValue().copyFrom(EPtr.box(tex.height), 1);
-                        }
-                    });
+                for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+                    for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                        this._map.set(
+                            `native void GetDimensions(RWTexture2D<${type}${length}>,uint* ${addressSpace1} Width,uint* ${addressSpace2} Height)`,
+                            func => {
+                                func.implementation = function([texture, width, height]) {
+                                    let tex = texture.loadValue();
+                                    if (width.loadValue())
+                                        width.loadValue().copyFrom(EPtr.box(tex.width), 1);
+                                    if (height.loadValue())
+                                        height.loadValue().copyFrom(EPtr.box(tex.height), 1);
+                                }
+                            });
+                        this._map.set(
+                            `native void GetDimensions(RWTexture2D<${type}${length}>,float* ${addressSpace1} Width,float* ${addressSpace2} Height)`,
+                            func => {
+                                func.implementation = function([texture, width, height]) {
+                                    let tex = texture.loadValue();
+                                    if (width.loadValue())
+                                        width.loadValue().copyFrom(EPtr.box(tex.width), 1);
+                                    if (height.loadValue())
+                                        height.loadValue().copyFrom(EPtr.box(tex.height), 1);
+                                }
+                            });
+                    }
+                }
                 this._map.set(
                     `native ${type}${length} Load(RWTexture2D<${type}${length}>,int2 location)`,
                     func => {
-                        func.implementation = function ([texture, location]) {
-                            return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(0, 0, 0, location.get(1), location.get(0))));
+                        func.implementation = function ([texture, location], node) {
+                            return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(0, 0, 0, location.get(1), location.get(0))));
                         }
                     });
                 this._map.set(
                     `native void Store(RWTexture2D<${type}${length}>,${type}${length},uint2 location)`,
                     func => {
-                        func.implementation = function ([texture, value, location]) {
-                            checkFalse("[Store]", "Texture write out of bounds", texture.loadValue().setElementChecked(0, 0, 0, location.get(1), location.get(0), unboxVector(value, length)));
+                        func.implementation = function ([texture, value, location], node) {
+                            checkFalse(node.origin.originString, "Texture write out of bounds", texture.loadValue().setElementChecked(0, 0, 0, location.get(1), location.get(0), unboxVector(value, length)));
                         }
                     });
 
-                 this._map.set(
-                    `native void GetDimensions(RWTexture2DArray<${type}${length}>,uint* thread Width,uint* thread Height,uint* thread Elements)`,
-                    func => {
-                        func.implementation = function([texture, width, height, elements]) {
-                            let tex = texture.loadValue();
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(tex.width), 1);
-                            if (height.loadValue())
-                                height.loadValue().copyFrom(EPtr.box(tex.height), 1);
-                            if (elements.loadValue())
-                                elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
-                        }
-                    });
-                this._map.set(
-                    `native void GetDimensions(RWTexture2DArray<${type}${length}>,float* thread Width,float* thread Height,float* thread Elements)`,
-                    func => {
-                        func.implementation = function([texture, width, height, elements]) {
-                            let tex = texture.loadValue();
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(tex.width), 1);
-                            if (height.loadValue())
-                                height.loadValue().copyFrom(EPtr.box(tex.height), 1);
-                            if (elements.loadValue())
-                                elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
+                for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+                    for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                        for (let addressSpace3 of ["thread", "threadgroup", "device"]) {
+                            this._map.set(
+                                `native void GetDimensions(RWTexture2DArray<${type}${length}>,uint* ${addressSpace1} Width,uint* ${addressSpace2} Height,uint* ${addressSpace3} Elements)`,
+                                func => {
+                                    func.implementation = function([texture, width, height, elements]) {
+                                        let tex = texture.loadValue();
+                                        if (width.loadValue())
+                                            width.loadValue().copyFrom(EPtr.box(tex.width), 1);
+                                        if (height.loadValue())
+                                            height.loadValue().copyFrom(EPtr.box(tex.height), 1);
+                                        if (elements.loadValue())
+                                            elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
+                                    }
+                                });
+                            this._map.set(
+                                `native void GetDimensions(RWTexture2DArray<${type}${length}>,float* ${addressSpace1} Width,float* ${addressSpace2} Height,float* ${addressSpace3} Elements)`,
+                                func => {
+                                    func.implementation = function([texture, width, height, elements]) {
+                                        let tex = texture.loadValue();
+                                        if (width.loadValue())
+                                            width.loadValue().copyFrom(EPtr.box(tex.width), 1);
+                                        if (height.loadValue())
+                                            height.loadValue().copyFrom(EPtr.box(tex.height), 1);
+                                        if (elements.loadValue())
+                                            elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
+                                    }
+                                });
                         }
-                    });
+                    }
+                }
                 this._map.set(
                     `native ${type}${length} Load(RWTexture2DArray<${type}${length}>,int3 location)`,
                     func => {
-                        func.implementation = function ([texture, location]) {
-                            return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(location.get(2), 0, 0, location.get(1), location.get(0))));
+                        func.implementation = function ([texture, location], node) {
+                            return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(location.get(2), 0, 0, location.get(1), location.get(0))));
                         }
                     });
                 this._map.set(
                     `native void Store(RWTexture2DArray<${type}${length}>,${type}${length},uint3 location)`,
                     func => {
-                        func.implementation = function ([texture, value, location]) {
-                            checkFalse("[Store]", "Texture write out of bounds", texture.loadValue().setElementChecked(location.get(2), 0, 0, location.get(1), location.get(0), unboxVector(value, length)));
+                        func.implementation = function ([texture, value, location], node) {
+                            checkFalse(node.origin.originString, "Texture write out of bounds", texture.loadValue().setElementChecked(location.get(2), 0, 0, location.get(1), location.get(0), unboxVector(value, length)));
                         }
                     });
 
-                 this._map.set(
-                    `native void GetDimensions(RWTexture3D<${type}${length}>,uint* thread Width,uint* thread Height,uint* thread Depth)`,
-                    func => {
-                        func.implementation = function([texture, width, height, depth]) {
-                            let tex = texture.loadValue();
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(tex.width), 1);
-                            if (height.loadValue())
-                                height.loadValue().copyFrom(EPtr.box(tex.height), 1);
-                            if (depth.loadValue())
-                                depth.loadValue().copyFrom(EPtr.box(tex.depth), 1);
-                        }
-                    });
-                this._map.set(
-                    `native void GetDimensions(RWTexture3D<${type}${length}>,float* thread Width,float* thread Height,float* thread Depth)`,
-                    func => {
-                        func.implementation = function([texture, width, height, depth]) {
-                            let tex = texture.loadValue();
-                            if (width.loadValue())
-                                width.loadValue().copyFrom(EPtr.box(tex.width), 1);
-                            if (height.loadValue())
-                                height.loadValue().copyFrom(EPtr.box(tex.height), 1);
-                            if (depth.loadValue())
-                                depth.loadValue().copyFrom(EPtr.box(tex.depth), 1);
+                for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+                    for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                        for (let addressSpace3 of ["thread", "threadgroup", "device"]) {
+                             this._map.set(
+                                `native void GetDimensions(RWTexture3D<${type}${length}>,uint* ${addressSpace1} Width,uint* ${addressSpace2} Height,uint* ${addressSpace3} Depth)`,
+                                func => {
+                                    func.implementation = function([texture, width, height, depth]) {
+                                        let tex = texture.loadValue();
+                                        if (width.loadValue())
+                                            width.loadValue().copyFrom(EPtr.box(tex.width), 1);
+                                        if (height.loadValue())
+                                            height.loadValue().copyFrom(EPtr.box(tex.height), 1);
+                                        if (depth.loadValue())
+                                            depth.loadValue().copyFrom(EPtr.box(tex.depth), 1);
+                                    }
+                                });
+                            this._map.set(
+                                `native void GetDimensions(RWTexture3D<${type}${length}>,float* ${addressSpace1} Width,float* ${addressSpace2} Height,float* ${addressSpace3} Depth)`,
+                                func => {
+                                    func.implementation = function([texture, width, height, depth]) {
+                                        let tex = texture.loadValue();
+                                        if (width.loadValue())
+                                            width.loadValue().copyFrom(EPtr.box(tex.width), 1);
+                                        if (height.loadValue())
+                                            height.loadValue().copyFrom(EPtr.box(tex.height), 1);
+                                        if (depth.loadValue())
+                                            depth.loadValue().copyFrom(EPtr.box(tex.depth), 1);
+                                    }
+                                });
                         }
-                    });
+                    }
+                }
                 this._map.set(
                     `native ${type}${length} Load(RWTexture3D<${type}${length}>,int3 location)`,
                     func => {
-                        func.implementation = function ([texture, location]) {
-                            return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(0, 0, location.get(2), location.get(1), location.get(0))));
+                        func.implementation = function ([texture, location], node) {
+                            return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(0, 0, location.get(2), location.get(1), location.get(0))));
                         }
                     });
                 this._map.set(
                     `native void Store(RWTexture3D<${type}${length}>,${type}${length},uint3 location)`,
                     func => {
-                        func.implementation = function ([texture, value, location]) {
-                            checkFalse("[Store]", "Texture write out of bounds", texture.loadValue().setElementChecked(0, 0, location.get(2), location.get(1), location.get(0), unboxVector(value, length)));
+                        func.implementation = function ([texture, value, location], node) {
+                            checkFalse(node.origin.originString, "Texture write out of bounds", texture.loadValue().setElementChecked(0, 0, location.get(2), location.get(1), location.get(0), unboxVector(value, length)));
                         }
                     });
             }
@@ -2140,33 +2202,39 @@ class Intrinsics {
             this._map.set(
                 `native ${type} Load(TextureDepth2D<${type}>,int3 location)`,
                 func => {
-                    func.implementation = function ([texture, location]) {
-                        return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(2), 0, location.get(1), location.get(0))));
+                    func.implementation = function ([texture, location], node) {
+                        return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(2), 0, location.get(1), location.get(0))));
                     }
                 });
             this._map.set(
                 `native ${type} Load(TextureDepth2D<${type}>,int3 location,int2 offset)`,
                 func => {
-                    func.implementation = function ([texture, location, offset]) {
-                        return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(2), 0, location.get(1) + offset.get(1), location.get(0) + offset.get(0))));
+                    func.implementation = function ([texture, location, offset], node) {
+                        return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(0, location.get(2), 0, location.get(1) + offset.get(1), location.get(0) + offset.get(0))));
                     }
                 });
-            this._map.set(
-                `native void GetDimensions(TextureDepth2D<${type}>,uint MipLevel,uint* thread Width,uint* thread Height,uint* thread NumberOfLevels)`,
-                func => {
-                    func.implementation = function ([texture, miplevel, width, height, numberOfLevels]) {
-                        let tex = texture.loadValue();
-                        let mipID = miplevel.loadValue();
-                        if (mipID >= tex.levelCount)
-                            throw new WTrapError("[GetDimensions]", "Reading from nonexistant mip level of texture");
-                        if (width.loadValue())
-                            width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
-                        if (height.loadValue())
-                            height.loadValue().copyFrom(EPtr.box(tex.heightAtLevel(mipID)), 1);
-                        if (numberOfLevels.loadValue())
-                            numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+            for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+                for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                    for (let addressSpace3 of ["thread", "threadgroup", "device"]) {
+                        this._map.set(
+                            `native void GetDimensions(TextureDepth2D<${type}>,uint MipLevel,uint* ${addressSpace1} Width,uint* ${addressSpace2} Height,uint* ${addressSpace3} NumberOfLevels)`,
+                            func => {
+                                func.implementation = function ([texture, miplevel, width, height, numberOfLevels], node) {
+                                    let tex = texture.loadValue();
+                                    let mipID = miplevel.loadValue();
+                                    if (mipID >= tex.levelCount)
+                                        throw new WTrapError(node.origin.originString, "Reading from nonexistant mip level of texture");
+                                    if (width.loadValue())
+                                        width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
+                                    if (height.loadValue())
+                                        height.loadValue().copyFrom(EPtr.box(tex.heightAtLevel(mipID)), 1);
+                                    if (numberOfLevels.loadValue())
+                                        numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+                                }
+                            });
                     }
-                });
+                }
+            }
             this._map.set(
                 `native ${type} Sample(TextureDepth2DArray<${type}>,sampler,float3 location)`,
                 func => {
@@ -2344,35 +2412,43 @@ class Intrinsics {
             this._map.set(
                 `native ${type} Load(TextureDepth2DArray<${type}>,int4 location)`,
                 func => {
-                    func.implementation = function ([texture, location]) {
-                        return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(location.get(3), location.get(2), 0, location.get(1), location.get(0))));
+                    func.implementation = function ([texture, location], node) {
+                        return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(location.get(3), location.get(2), 0, location.get(1), location.get(0))));
                     }
                 });
             this._map.set(
                 `native ${type} Load(TextureDepth2DArray<${type}>,int4 location,int2 offset)`,
                 func => {
-                    func.implementation = function ([texture, location, offset]) {
-                        return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(location.get(3), location.get(2), 0, location.get(1) + offset.get(1), location.get(0) + offset.get(0))));
+                    func.implementation = function ([texture, location, offset], node) {
+                        return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(location.get(3), location.get(2), 0, location.get(1) + offset.get(1), location.get(0) + offset.get(0))));
                     }
                 });
-            this._map.set(
-                `native void GetDimensions(TextureDepth2DArray<${type}>,uint MipLevel,uint* thread Width,uint* thread Height,uint* thread Elements,uint* thread NumberOfLevels)`,
-                func => {
-                    func.implementation = function ([texture, miplevel, width, height, elements, numberOfLevels]) {
-                        let tex = texture.loadValue();
-                        let mipID = miplevel.loadValue();
-                        if (mipID >= tex.levelCount)
-                            throw new WTrapError("[GetDimensions]", "Reading from nonexistant mip level of texture");
-                        if (width.loadValue())
-                            width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
-                        if (height.loadValue())
-                            height.loadValue().copyFrom(EPtr.box(tex.heightAtLevel(mipID)), 1);
-                        if (elements.loadValue())
-                            elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
-                        if (numberOfLevels.loadValue())
-                            numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+            for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+                for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                    for (let addressSpace3 of ["thread", "threadgroup", "device"]) {
+                        for (let addressSpace4 of ["thread", "threadgroup", "device"]) {
+                            this._map.set(
+                                `native void GetDimensions(TextureDepth2DArray<${type}>,uint MipLevel,uint* ${addressSpace1} Width,uint* ${addressSpace2} Height,uint* ${addressSpace3} Elements,uint* ${addressSpace4} NumberOfLevels)`,
+                                func => {
+                                    func.implementation = function ([texture, miplevel, width, height, elements, numberOfLevels], node) {
+                                        let tex = texture.loadValue();
+                                        let mipID = miplevel.loadValue();
+                                        if (mipID >= tex.levelCount)
+                                            throw new WTrapError(node.origin.originString, "Reading from nonexistant mip level of texture");
+                                        if (width.loadValue())
+                                            width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
+                                        if (height.loadValue())
+                                            height.loadValue().copyFrom(EPtr.box(tex.heightAtLevel(mipID)), 1);
+                                        if (elements.loadValue())
+                                            elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
+                                        if (numberOfLevels.loadValue())
+                                            numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+                                    }
+                                });
+                        }
                     }
-                });
+                }
+            }
             this._map.set(
                 `native ${type} Sample(TextureDepthCube<${type}>,sampler,float3 location)`,
                 func => {
@@ -2455,98 +2531,114 @@ class Intrinsics {
                         return boxVector(gatherTexture(texture.loadValue(), sampler.loadValue(), locationArray, undefined, undefined, undefined, undefined, undefined, compareValue.loadValue(), 0));
                     }
                 });
-            this._map.set(
-                `native void GetDimensions(TextureDepthCube<${type}>,uint MipLevel,uint* thread Width,uint* thread Height,uint* thread NumberOfLevels)`,
-                func => {
-                    func.implementation = function ([texture, miplevel, width, height, numberOfLevels]) {
-                        let tex = texture.loadValue();
-                        let mipID = miplevel.loadValue();
-                        if (tex.layerCount != 6)
-                            throw new Error("Cube texture doesn't have 6 faces");
-                        if (mipID >= tex.levelCount)
-                            throw new WTrapError("[GetDimensions]", "Reading from nonexistant mip level of texture");
-                        if (width.loadValue())
-                            width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
-                        if (height.loadValue())
-                            height.loadValue().copyFrom(EPtr.box(tex.heightAtLevel(mipID)), 1);
-                        if (numberOfLevels.loadValue())
-                            numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
-                    }
-                });
-            this._map.set(
-                `native void GetDimensions(RWTextureDepth2D<${type}>,uint* thread Width,uint* thread Height)`,
-                func => {
-                    func.implementation = function ([texture, width, height]) {
-                        let tex = texture.loadValue();
-                        if (width.loadValue())
-                            width.loadValue().copyFrom(EPtr.box(tex.width), 1);
-                        if (height.loadValue())
-                            height.loadValue().copyFrom(EPtr.box(tex.height), 1);
-                    }
-                });
-            this._map.set(
-                `native void GetDimensions(RWTextureDepth2D<${type}>,float* thread Width,float* thread Height)`,
-                func => {
-                    func.implementation = function ([texture, width, height]) {
-                        let tex = texture.loadValue();
-                        if (width.loadValue())
-                            width.loadValue().copyFrom(EPtr.box(tex.width), 1);
-                        if (height.loadValue())
-                            height.loadValue().copyFrom(EPtr.box(tex.height), 1);
+            for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+                for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                    for (let addressSpace3 of ["thread", "threadgroup", "device"]) {
+                        this._map.set(
+                            `native void GetDimensions(TextureDepthCube<${type}>,uint MipLevel,uint* ${addressSpace1} Width,uint* ${addressSpace2} Height,uint* ${addressSpace3} NumberOfLevels)`,
+                            func => {
+                                func.implementation = function ([texture, miplevel, width, height, numberOfLevels], node) {
+                                    let tex = texture.loadValue();
+                                    let mipID = miplevel.loadValue();
+                                    if (tex.layerCount != 6)
+                                        throw new Error("Cube texture doesn't have 6 faces");
+                                    if (mipID >= tex.levelCount)
+                                        throw new WTrapError(node.origin.originString, "Reading from nonexistant mip level of texture");
+                                    if (width.loadValue())
+                                        width.loadValue().copyFrom(EPtr.box(tex.widthAtLevel(mipID)), 1);
+                                    if (height.loadValue())
+                                        height.loadValue().copyFrom(EPtr.box(tex.heightAtLevel(mipID)), 1);
+                                    if (numberOfLevels.loadValue())
+                                        numberOfLevels.loadValue().copyFrom(EPtr.box(tex.levelCount), 1);
+                                }
+                            });
                     }
-                });
+                }
+            }
+            for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+                for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                    this._map.set(
+                        `native void GetDimensions(RWTextureDepth2D<${type}>,uint* ${addressSpace1} Width,uint* ${addressSpace2} Height)`,
+                        func => {
+                            func.implementation = function ([texture, width, height]) {
+                                let tex = texture.loadValue();
+                                if (width.loadValue())
+                                    width.loadValue().copyFrom(EPtr.box(tex.width), 1);
+                                if (height.loadValue())
+                                    height.loadValue().copyFrom(EPtr.box(tex.height), 1);
+                            }
+                        });
+                    this._map.set(
+                        `native void GetDimensions(RWTextureDepth2D<${type}>,float* ${addressSpace1} Width,float* ${addressSpace2} Height)`,
+                        func => {
+                            func.implementation = function ([texture, width, height]) {
+                                let tex = texture.loadValue();
+                                if (width.loadValue())
+                                    width.loadValue().copyFrom(EPtr.box(tex.width), 1);
+                                if (height.loadValue())
+                                    height.loadValue().copyFrom(EPtr.box(tex.height), 1);
+                            }
+                        });
+                }
+            }
             this._map.set(
                 `native ${type} Load(RWTextureDepth2D<${type}>,int2 location)`,
                 func => {
-                    func.implementation = function ([texture, location]) {
-                        return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(0, 0, 0, location.get(1), location.get(0))));
+                    func.implementation = function ([texture, location], node) {
+                        return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(0, 0, 0, location.get(1), location.get(0))));
                     }
                 });
             this._map.set(
                 `native void Store(RWTextureDepth2D<${type}>,${type},uint2 location)`,
                 func => {
-                    func.implementation = function ([texture, value, location]) {
-                        checkFalse("[Store]", "Texture write out of bounds", texture.loadValue().setElementChecked(0, 0, 0, location.get(1), location.get(0), unboxVector(value, "")));
-                    }
-                });
-            this._map.set(
-                `native void GetDimensions(RWTextureDepth2DArray<${type}>,uint* thread Width,uint* thread Height,uint* thread Elements)`,
-                func => {
-                    func.implementation = function ([texture, width, height, elements]) {
-                        let tex = texture.loadValue();
-                        if (width.loadValue())
-                            width.loadValue().copyFrom(EPtr.box(tex.width), 1);
-                        if (height.loadValue())
-                            height.loadValue().copyFrom(EPtr.box(tex.height), 1);
-                        if (elements.loadValue())
-                            elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
+                    func.implementation = function ([texture, value, location], node) {
+                        checkFalse(node.origin.originString, "Texture write out of bounds", texture.loadValue().setElementChecked(0, 0, 0, location.get(1), location.get(0), unboxVector(value, "")));
                     }
                 });
-            this._map.set(
-                `native void GetDimensions(RWTextureDepth2DArray<${type}>,float* thread Width,float* thread Height,float* thread Elements)`,
-                func => {
-                    func.implementation = function ([texture, width, height, elements]) {
-                        let tex = texture.loadValue();
-                        if (width.loadValue())
-                            width.loadValue().copyFrom(EPtr.box(tex.width), 1);
-                        if (height.loadValue())
-                            height.loadValue().copyFrom(EPtr.box(tex.height), 1);
-                        if (elements.loadValue())
-                            elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
+            for (let addressSpace1 of ["thread", "threadgroup", "device"]) {
+                for (let addressSpace2 of ["thread", "threadgroup", "device"]) {
+                    for (let addressSpace3 of ["thread", "threadgroup", "device"]) {
+                        this._map.set(
+                            `native void GetDimensions(RWTextureDepth2DArray<${type}>,uint* ${addressSpace1} Width,uint* ${addressSpace2} Height,uint* ${addressSpace3} Elements)`,
+                            func => {
+                                func.implementation = function ([texture, width, height, elements]) {
+                                    let tex = texture.loadValue();
+                                    if (width.loadValue())
+                                        width.loadValue().copyFrom(EPtr.box(tex.width), 1);
+                                    if (height.loadValue())
+                                        height.loadValue().copyFrom(EPtr.box(tex.height), 1);
+                                    if (elements.loadValue())
+                                        elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
+                                }
+                            });
+                        this._map.set(
+                            `native void GetDimensions(RWTextureDepth2DArray<${type}>,float* ${addressSpace1} Width,float* ${addressSpace2} Height,float* ${addressSpace3} Elements)`,
+                            func => {
+                                func.implementation = function ([texture, width, height, elements]) {
+                                    let tex = texture.loadValue();
+                                    if (width.loadValue())
+                                        width.loadValue().copyFrom(EPtr.box(tex.width), 1);
+                                    if (height.loadValue())
+                                        height.loadValue().copyFrom(EPtr.box(tex.height), 1);
+                                    if (elements.loadValue())
+                                        elements.loadValue().copyFrom(EPtr.box(tex.layerCount), 1);
+                                }
+                            });
                     }
-                });
+                }
+            }
             this._map.set(
                 `native ${type} Load(RWTextureDepth2DArray<${type}>,int3 location)`,
                 func => {
-                    func.implementation = function ([texture, location]) {
-                        return boxVector(checkUndefined("[Load]", "Texture read out of bounds", texture.loadValue().elementChecked(location.get(2), 0, 0, location.get(1), location.get(0))));
+                    func.implementation = function ([texture, location], node) {
+                        return boxVector(checkUndefined(node.origin.originString, "Texture read out of bounds", texture.loadValue().elementChecked(location.get(2), 0, 0, location.get(1), location.get(0))));
                     }
                 });
             this._map.set(
                 `native void Store(RWTextureDepth2DArray<${type}>,${type},uint3 location)`,
                 func => {
-                    func.implementation = function ([texture, value, location]) {
-                        checkFalse("[Store]", "Texture write out of bounds", texture.loadValue().setElementChecked(location.get(2), 0, 0, location.get(1), location.get(0), unboxVector(value, "")));
+                    func.implementation = function ([texture, value, location], node) {
+                        checkFalse(node.origin.originString, "Texture write out of bounds", texture.loadValue().setElementChecked(location.get(2), 0, 0, location.get(1), location.get(0), unboxVector(value, "")));
                     }
                 });
         }
index fea56ec..4624e6d 100644 (file)
@@ -35,7 +35,7 @@ let standardLibrary = (function() {
     (function() {
         print(`// This was autogenerated from Generate_Standard_Library.swift! Do not edit!!`);
         print();
-        
+
         for (let type of [`void`, `bool`, `uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`, `atomic_int`, `atomic_uint`]) {
             print(`native typedef ${type};`);
         }
@@ -46,7 +46,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         for (let type of [`half`, `float`]) {
             for (let i of [2, 3, 4]) {
                 for (let j of [2, 3, 4]) {
@@ -69,7 +69,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         for (let type1 of [`uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
             for (let type2 of [`uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
                 if (type1 != type2) {
@@ -78,38 +78,38 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         for (let type of [`uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
             print(`operator bool(${type} x) {`);
             print(`    return x != 0;`);
             print(`}`);
         }
         print();
-        
+
         print(`native operator int(atomic_int);`);
         print(`native operator uint(atomic_uint);`);
         print();
-        
+
         print(`native bool operator==(bool, bool);`);
-        
+
         print(`bool operator&(bool a, bool b) {`);
         print(`    return a && b;`);
         print(`}`);
-        
+
         print(`bool operator|(bool a, bool b) {`);
         print(`    return a || b;`);
         print(`}`);
-        
+
         print(`bool operator^(bool a, bool b) {`);
         print(`    if (a)`);
         print(`        return !b;`);
         print(`    return b;`);
         print(`}`);
-        
+
         print(`bool operator~(bool value) {`);
         print(`    return !value;`);
         print(`}`);
-        
+
         for (let type of [`int`, `uint`, `float`]) {
             print(`native ${type} operator+(${type}, ${type});`);
             print(`native ${type} operator-(${type}, ${type});`);
@@ -121,7 +121,7 @@ let standardLibrary = (function() {
             print(`native bool operator>(${type}, ${type});`);
             print(`native bool operator>=(${type}, ${type});`);
         }
-        
+
         for (let type of [`int`, `uint`]) {
             print(`native ${type} operator&(${type}, ${type});`);
             print(`native ${type} operator|(${type}, ${type});`);
@@ -130,7 +130,7 @@ let standardLibrary = (function() {
             print(`native ${type} operator<<(${type}, uint);`);
             print(`native ${type} operator>>(${type}, uint);`);
         }
-        
+
         for (let type of [`uchar`, `ushort`]) {
             print(`${type} operator+(${type} a, ${type} b) {`);
             print(`    return ${type}(uint(a) + uint(b));`);
@@ -184,7 +184,7 @@ let standardLibrary = (function() {
         print(`ushort operator>>(ushort a, uint b) {`);
         print(`    return ushort(uint(a) >> (b & 65535));`);
         print(`}`);
-        
+
         for (let type of [`char`, `short`]) {
             print(`${type} operator+(${type} a, ${type} b) {`);
             print(`    return ${type}(int(a) + int(b));`);
@@ -238,7 +238,7 @@ let standardLibrary = (function() {
         print(`short operator>>(short a, uint b) {`);
         print(`    return short(int(a) >> (b & 65535));`);
         print(`}`);
-        
+
         for (let type of [`uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
             print(`${type} operator++(${type} value) {`);
             print(`    return value + 1;`);
@@ -247,7 +247,7 @@ let standardLibrary = (function() {
             print(`    return value - 1;`);
             print(`}`);
         }
-        
+
         print(`half operator+(half a, half b) {`);
         print(`    return half(float(a) + float(b));`);
         print(`}`);
@@ -287,7 +287,7 @@ let standardLibrary = (function() {
         print(`native int operator-(int);`);
         print(`native float operator-(float);`);
         print();
-        
+
         for (let type of [`uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
             for (let size of [2, 3, 4]) {
                 print(`${type}${size} operator+(${type}${size} a, ${type}${size} b) {`);
@@ -446,7 +446,7 @@ let standardLibrary = (function() {
                 }
             }
         }
-        
+
         for (let type of [`bool`, `uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
             print(`operator ${type}2(${type} x, ${type} y) {`);
             print(`    ${type}2 result;`);
@@ -542,7 +542,7 @@ let standardLibrary = (function() {
             print(`}`);
         }
         print();
-        
+
         for (let type of [`half`, `float`]) {
             let variables = [`a`, `b`, `c`, `d`];
             for (let m of [2, 3, 4]) {
@@ -566,7 +566,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         for (let type of [`bool`, `uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
             print(`bool operator==(${type}2 a, ${type}2 b) {`);
             print(`    return a.x == b.x && a.y == b.y;`);
@@ -681,7 +681,7 @@ let standardLibrary = (function() {
             print(`}`);
         }
         print();
-        
+
         for (let type of [`half`, `float`]) {
             for (let m of [2, 3, 4]) {
                 for (let n of [2, 3, 4]) {
@@ -691,7 +691,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         for (let type of [`half`, `float`]) {
             for (let i of [2, 3, 4]) {
                 for (let j of [2, 3, 4]) {
@@ -707,7 +707,7 @@ let standardLibrary = (function() {
                 }
             }
         }
-        
+
         function computeSwizzle(components, maxValue, maxLength) {
             if (components.length == maxLength) {
                 return [components];
@@ -719,7 +719,7 @@ let standardLibrary = (function() {
                 return result;
             }
         }
-        
+
         function component(value) {
             switch (value) {
                 case 0:
@@ -734,7 +734,7 @@ let standardLibrary = (function() {
                     fatalError();
             }
         }
-        
+
         function uniqueLength(swizzle) {
             let has0 = false;
             let has1 = false;
@@ -799,28 +799,28 @@ let standardLibrary = (function() {
                 }
             }
         }
-        
+
         // These functions are unary floating-point scalar functions,
         // which can also be applied to vectors and matrices component-wise.
         (function() {
             let nativeFunctions = [`cos`, `sin`, `tan`, `acos`, `asin`, `atan`, `cosh`, `sinh`, `tanh`, `ceil`, `exp`, `floor`, `log`, `round`, `trunc`];
             let nativeFragmentFunctions = [`ddx`, `ddy`];
             let nonNativeFunctions = [`sqrt`, `log2`, `log10`, `frac`, `exp2`, `degrees`, `radians`, `rcp`, `rsqrt`, `saturate`, `ddx_coarse`, `ddx_fine`, `ddy_coarse`, `ddy_fine`, `fwidth`];
-        
+
             for (let nativeFunction of nativeFunctions) {
                 print(`native float ${nativeFunction}(float);`);
                 print(`half ${nativeFunction}(half x) {`);
                 print(`    return half(${nativeFunction}(float(x)));`);
                 print(`}`);
             }
-        
+
             for (let nativeFunction of nativeFragmentFunctions) {
                 print(`native fragment float ${nativeFunction}(float);`);
                 print(`half ${nativeFunction}(half x) {`);
                 print(`    return half(${nativeFunction}(float(x)));`);
                 print(`}`);
             }
-        
+
             for (let type of [`half`, `float`]) {
                 print(`${type} sqrt(${type} x) {`);
                 print(`    return pow(x, 0.5);`);
@@ -867,7 +867,7 @@ let standardLibrary = (function() {
                 print(`${type} fwidth(${type} x) {`);
                 print(`    return abs(ddx(x)) + abs(ddy(x));`);
                 print(`}`);
-        
+
                 for (let outputFunction of nativeFunctions.concat(nativeFragmentFunctions.concat(nonNativeFunctions))) {
                     for (let size of [2, 3, 4]) {
                         print(`${type}${size} ${outputFunction}(${type}${size} x) {`);
@@ -895,22 +895,22 @@ let standardLibrary = (function() {
                 print();
             }
         })();
-        
+
         // These functions are binary floating-point scalar functions,
         // which can also be applied to vectors and matrices component-wise.
         (function() {
             let nativeFunctions = [`pow`];
-        
+
             for (let nativeFunction of nativeFunctions) {
                 print(`native float ${nativeFunction}(float, float);`);
                 print(`half ${nativeFunction}(half x, half y) {`);
                 print(`    return half(${nativeFunction}(float(x), float(y)));`);
                 print(`}`);
             }
-        
+
             for (let type of [`half`, `float`]) {
                 let nonNativeFunctions = [`step`, `ldexp`, `fmod`];
-        
+
                 print(`${type} step(${type} y, ${type} x) {`);
                 print(`    return x >= y ? 1 : 0;`);
                 print(`}`);
@@ -922,7 +922,7 @@ let standardLibrary = (function() {
                 print(`    ${type} multiple = ${type}(whole) * y;`);
                 print(`    return x - multiple;`);
                 print(`}`);
-        
+
                 for (let outputFunction of nativeFunctions.concat(nonNativeFunctions)) {
                     for (let size of [2, 3, 4]) {
                         print(`${type}${size} ${outputFunction}(${type}${size} x, ${type}${size} y) {`);
@@ -950,12 +950,12 @@ let standardLibrary = (function() {
                 print();
             }
         })();
-        
+
         // These functions are ternary floating-point scalar functions,
         // which can also be applied to vectors and matrices component-wise.
         for (let type of [`half`, `float`]) {
             let nonNativeFunctions = [`smoothstep`, `lerp`, `fma`, `mad`];
-        
+
             print(`${type} smoothstep(${type} edge0, ${type} edge1, ${type} x) {`);
             print(`    ${type} t = clamp((x - edge0) / (edge1 - edge0), 0, 1);`);
             print(`    return t * t * (3 - 2 * t);`);
@@ -969,7 +969,7 @@ let standardLibrary = (function() {
             print(`${type} mad(${type} x, ${type} y, ${type} z) {`);
             print(`    return x * y + z;`);
             print(`}`);
-        
+
             for (let nonNativeFunction of nonNativeFunctions) {
                 for (let size of [2, 3, 4]) {
                     print(`${type}${size} ${nonNativeFunction}(${type}${size} x, ${type}${size} y, ${type}${size} z) {`);
@@ -996,7 +996,7 @@ let standardLibrary = (function() {
             }
             print();
         }
-        
+
         print(`native bool isnormal(half);`);
         print(`native bool isnormal(float);`);
         for (let type of [`half`, `float`]) {
@@ -1011,17 +1011,17 @@ let standardLibrary = (function() {
             }
             print();
         }
-        
+
         (function() {
             let nativeFunctions = [`isfinite`, `isinf`, `isnan`];
-        
+
             for (let nativeFunction of nativeFunctions) {
                 print(`native bool ${nativeFunction}(float);`);
                 print(`bool ${nativeFunction}(half x) {`);
                 print(`    return ${nativeFunction}(float(x));`);
                 print(`}`);
             }
-        
+
             for (let type of [`half`, `float`]) {
                 for (let nativeFunction of nativeFunctions) {
                     for (let size of [2, 3, 4]) {
@@ -1037,17 +1037,17 @@ let standardLibrary = (function() {
                 print();
             }
         })()
-        
+
         for (let type of [`half`, `float`]) {
             let nonNativeFunctions = [`isordered`, `isunordered`];
-        
+
             print(`bool isordered(${type} x, ${type} y) {`);
             print(`    return (x == x) && (y == y);`);
             print(`}`);
             print(`bool isunordered(${type} x, ${type} y) {`);
             print(`    return isnan(x) || isnan(y);`);
             print(`}`);
-        
+
             for (let nonNativeFunction of nonNativeFunctions) {
                 for (let size of [2, 3, 4]) {
                     print(`bool${size} ${nonNativeFunction}(${type}${size} x, ${type}${size} y) {`);
@@ -1061,7 +1061,7 @@ let standardLibrary = (function() {
             }
             print();
         }
-        
+
         print(`native float atan2(float, float);`);
         print(`half atan2(half x, half y) {`);
         print(`    return half(atan2(float(x), float(y)));`);
@@ -1091,49 +1091,53 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
-        for (let type of [`half`, `float`]) {
-            print(`void sincos(${type} x, thread ${type}* y, thread ${type}* z) {`);
-            print(`    if (y != null)`);
-            print(`        *y = sin(x);`);
-            print(`    if (z != null)`);
-            print(`        *z = cos(x);`);
-            print(`}`);
-            for (let size of [2, 3, 4]) {
-                print(`void sincos(${type}${size} x, thread ${type}${size}* y, thread ${type}${size}* z) {`);
-                // Can't take a pointer to a member of a vector.
-                print(`    ${type} sinResult;`);
-                print(`    ${type} cosResult;`);
-                for (let i = 0; i < size; ++i) {
-                    print(`    sincos(x[${i}], &sinResult, &cosResult);`);
+
+        for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+            for (let addressSpace2 of [`thread`, `device`, `threadgroup`]) {
+                for (let type of [`half`, `float`]) {
+                    print(`void sincos(${type} x, ${addressSpace1} ${type}* y, ${addressSpace2} ${type}* z) {`);
                     print(`    if (y != null)`);
-                    print(`        (*y)[${i}] = sinResult;`);
+                    print(`        *y = sin(x);`);
                     print(`    if (z != null)`);
-                    print(`        (*z)[${i}] = cosResult;`);
-                }
-                print(`}`);
-            }
-            for (let i of [2, 3, 4]) {
-                for (let j of [2, 3, 4]) {
-                    print(`void sincos(${type}${i}x${j} x, thread ${type}${i}x${j}* y, thread ${type}${i}x${j}* z) {`);
-                    // Can't take a pointer to a member of a matrix.
-                    print(`    ${type} sinResult;`);
-                    print(`    ${type} cosResult;`);
-                    for (let m = 0; m < i; ++m) {
-                        for (let n = 0; n < j; ++n) {
-                            print(`    sincos(x[${m}][${n}], &sinResult, &cosResult);`);
+                    print(`        *z = cos(x);`);
+                    print(`}`);
+                    for (let size of [2, 3, 4]) {
+                        print(`void sincos(${type}${size} x, ${addressSpace1} ${type}${size}* y, ${addressSpace2} ${type}${size}* z) {`);
+                        // Can't take a pointer to a member of a vector.
+                        print(`    ${type} sinResult;`);
+                        print(`    ${type} cosResult;`);
+                        for (let i = 0; i < size; ++i) {
+                            print(`    sincos(x[${i}], &sinResult, &cosResult);`);
                             print(`    if (y != null)`);
-                            print(`        (*y)[${m}][${n}] = sinResult;`);
+                            print(`        (*y)[${i}] = sinResult;`);
                             print(`    if (z != null)`);
-                            print(`        (*z)[${m}][${n}] = cosResult;`);
+                            print(`        (*z)[${i}] = cosResult;`);
+                        }
+                        print(`}`);
+                    }
+                    for (let i of [2, 3, 4]) {
+                        for (let j of [2, 3, 4]) {
+                            print(`void sincos(${type}${i}x${j} x, ${addressSpace1} ${type}${i}x${j}* y, ${addressSpace2} ${type}${i}x${j}* z) {`);
+                            // Can't take a pointer to a member of a matrix.
+                            print(`    ${type} sinResult;`);
+                            print(`    ${type} cosResult;`);
+                            for (let m = 0; m < i; ++m) {
+                                for (let n = 0; n < j; ++n) {
+                                    print(`    sincos(x[${m}][${n}], &sinResult, &cosResult);`);
+                                    print(`    if (y != null)`);
+                                    print(`        (*y)[${m}][${n}] = sinResult;`);
+                                    print(`    if (z != null)`);
+                                    print(`        (*z)[${m}][${n}] = cosResult;`);
+                                }
+                            }
+                            print(`}`);
                         }
                     }
-                    print(`}`);
                 }
             }
         }
         print();
-        
+
         for (let binaryFunction of [[`all`, `true`, `&&`], [`any`, `false`, `||`]]) {
             print(`bool ${binaryFunction[0]}(bool x) {`);
             print(`    return x;`);
@@ -1178,7 +1182,7 @@ let standardLibrary = (function() {
             }
             print();
         }
-        
+
         for (let type of [`uchar`, `ushort`, `uint`]) {
             print(`${type} abs(${type} x) {`);
             print(`    return x;`);
@@ -1218,7 +1222,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         for (let type of [`uchar`, `ushort`, `uint`]) {
             print(`${type} sign(${type} x) {`);
             print(`    return x == 0 ? 0 : 1;`);
@@ -1260,17 +1264,17 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         for (let type of [`uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
             let nonNativeFunctions = [`min`, `max`];
-        
+
             print(`${type} min(${type} x, ${type} y) {`);
             print(`    return x > y ? y : x;`);
             print(`}`);
             print(`${type} max(${type} x, ${type} y) {`);
             print(`    return x > y ? x : y;`);
             print(`}`);
-        
+
             for (let nonNativeFunction of nonNativeFunctions) {
                 for (let size of [2, 3, 4]) {
                     print(`${type}${size} ${nonNativeFunction}(${type}${size} x, ${type}${size} y) {`);
@@ -1299,14 +1303,14 @@ let standardLibrary = (function() {
             }
             print();
         }
-        
+
         for (let type of [`uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
             let nonNativeFunctions = [`clamp`];
-        
+
             print(`${type} clamp(${type} x, ${type} lower, ${type} upper) {`);
             print(`    return max(min(upper, x), lower);`);
             print(`}`);
-        
+
             for (let nonNativeFunction of nonNativeFunctions) {
                 for (let size of [2, 3, 4]) {
                     print(`${type}${size} ${nonNativeFunction}(${type}${size} x, ${type}${size} y, ${type}${size} z) {`);
@@ -1335,48 +1339,50 @@ let standardLibrary = (function() {
             }
             print();
         }
-        
-        for (let type of [`half`, `float`]) {
-            print(`${type} modf(${type} x, thread ${type}* ip) {`);
-            print(`    uint result = uint(x);`);
-            print(`    if (ip != null)`);
-            print(`        *ip = x - ${type}(result);`);
-            print(`    return ${type}(result);`);
-            print(`}`);
-        
-            for (let size of [2, 3, 4]) {
-                print(`${type}${size} modf(${type}${size} x, thread ${type}${size}* y) {`);
-                print(`    ${type}${size} result;`);
-                // Can't take a pointer to a member of a vector.
-                print(`    ${type} buffer;`);
-                for (let i = 0; i < size; ++i) {
-                    print(`    result[${i}] = modf(x[${i}], &buffer);`);
-                    print(`    if (y != null)`);
-                    print(`        (*y)[${i}] = buffer;`);
-                }
-                print(`    return result;`);
+
+        for (let addressSpace of [`thread`, `device`, `threadgroup`]) {
+            for (let type of [`half`, `float`]) {
+                print(`${type} modf(${type} x, ${addressSpace} ${type}* ip) {`);
+                print(`    uint result = uint(x);`);
+                print(`    if (ip != null)`);
+                print(`        *ip = x - ${type}(result);`);
+                print(`    return ${type}(result);`);
                 print(`}`);
-            }
-            for (let i of [2, 3, 4]) {
-                for (let j of [2, 3, 4]) {
-                    print(`${type}${i}x${j} modf(${type}${i}x${j} x, thread ${type}${i}x${j}* y) {`);
-                    print(`    ${type}${i}x${j} result;`);
-                    // Can't take a pointer to a member of a matrix.
+
+                for (let size of [2, 3, 4]) {
+                    print(`${type}${size} modf(${type}${size} x, ${addressSpace} ${type}${size}* y) {`);
+                    print(`    ${type}${size} result;`);
+                    // Can't take a pointer to a member of a vector.
                     print(`    ${type} buffer;`);
-                    for (let m = 0; m < i; ++m) {
-                        for (let n = 0; n < j; ++n) {
-                            print(`    result[${m}][${n}] = modf(x[${m}][${n}], &buffer);`);
-                            print(`    if (y != null)`);
-                            print(`        (*y)[${m}][${n}] = buffer;`);
-                        }
+                    for (let i = 0; i < size; ++i) {
+                        print(`    result[${i}] = modf(x[${i}], &buffer);`);
+                        print(`    if (y != null)`);
+                        print(`        (*y)[${i}] = buffer;`);
                     }
                     print(`    return result;`);
                     print(`}`);
                 }
+                for (let i of [2, 3, 4]) {
+                    for (let j of [2, 3, 4]) {
+                        print(`${type}${i}x${j} modf(${type}${i}x${j} x, ${addressSpace} ${type}${i}x${j}* y) {`);
+                        print(`    ${type}${i}x${j} result;`);
+                        // Can't take a pointer to a member of a matrix.
+                        print(`    ${type} buffer;`);
+                        for (let m = 0; m < i; ++m) {
+                            for (let n = 0; n < j; ++n) {
+                                print(`    result[${m}][${n}] = modf(x[${m}][${n}], &buffer);`);
+                                print(`    if (y != null)`);
+                                print(`        (*y)[${m}][${n}] = buffer;`);
+                            }
+                        }
+                        print(`    return result;`);
+                        print(`}`);
+                    }
+                }
+                print();
             }
-            print();
         }
-        
+
         print(`uchar count_bits(uchar x) {`);
         print(`    return uchar(((x | uchar(1 << 0)) == 0 ? 0 : 1) +`);
         for (let i = 1; i < 7; ++i) {
@@ -1445,7 +1451,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         print(`uint firstbithigh(uchar x) {`);
         for (let i = 0; i <= 7; ++i) {
             print(`    if ((x & uchar(1 << ${7 - i})) != 0)`);
@@ -1520,7 +1526,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         // Row-major, so the first index selects which row, and the second index selects which column
         for (let type of [`half`, `float`]) {
             print(`${type} determinant(${type} x) {`);
@@ -1584,7 +1590,7 @@ let standardLibrary = (function() {
             print(`}`);
         }
         print();
-        
+
         for (let type of [`uchar4`, `ushort4`, `uint4`, `char4`, `short4`, `int4`, `half4`, `float4`]) {
             print(`${type} dst(${type} src0, ${type} src1) {`);
             print(`    ${type} result;`);
@@ -1596,7 +1602,7 @@ let standardLibrary = (function() {
             print(`}`);
         }
         print();
-        
+
         for (let type of [`half`, `float`]) {
             print(`${type} distance(${type} x, ${type} y) {`);
             print(`    return length(x - y);`);
@@ -1608,7 +1614,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         for (let type of [`half3`, `float3`]) {
             print(`${type} cross(${type} u, ${type} v) {`);
             print(`    ${type} result;`);
@@ -1619,7 +1625,7 @@ let standardLibrary = (function() {
             print(`}`);
         }
         print();
-        
+
         for (let type of [`uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
             print(`${type} dot(${type} a, ${type} b) {`);
             print(`    return a * b;`);
@@ -1635,7 +1641,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         for (let type of [`half`, `float`]) {
             for (let size of [``, `2`, `3`, `4`]) {
                 print(`${type}${size} faceforward(${type}${size} n, ${type}${size} i, ${type}${size} ng) {`);
@@ -1644,7 +1650,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         for (let type of [`half`, `float`]) {
             for (let size of [``, `2`, `3`, `4`]) {
                 print(`${type} length(${type}${size} x) {`);
@@ -1653,7 +1659,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         for (let type of [`half`, `float`]) {
             print(`${type}4 lit(${type} n_dot_l, ${type} n_dot_h, ${type} m) {`);
             print(`    ${type} ambient = 1;`);
@@ -1668,7 +1674,7 @@ let standardLibrary = (function() {
             print(`}`);
         }
         print();
-        
+
         for (let type of [`half`, `float`]) {
             for (let size of [``, `2`, `3`, `4`]) {
                 print(`${type}${size} normalize(${type}${size} x) {`);
@@ -1677,7 +1683,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         for (let type of [`half`, `float`]) {
             for (let size of [``, `2`, `3`, `4`]) {
                 print(`${type}${size} reflect(${type}${size} i, ${type}${size} n) {`);
@@ -1686,7 +1692,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         // OpenGL ES v3.30 section 8.4
         for (let type of [`half`, `float`]) {
             for (let size of [``, `2`, `3`, `4`]) {
@@ -1700,7 +1706,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         for (let type of [`half`, `float`]) {
             print(`${type} transpose(${type} x) {`);
             print(`    return x;`);
@@ -1720,7 +1726,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         for (let resultType of [`int`, `uint`, `float`]) {
             for (let type of [`int`, `uint`, `float`]) {
                 if (type == resultType) {
@@ -1773,7 +1779,7 @@ let standardLibrary = (function() {
             }
         }
         print();
-        
+
         print(`native float f16tof32(uint);`);
         print(`native uint f32tof16(float);`);
         for (let size of [2, 3, 4]) {
@@ -1793,18 +1799,18 @@ let standardLibrary = (function() {
             print(`}`);
         }
         print();
-        
+
         print(`native compute void AllMemoryBarrierWithGroupSync();`);
         print(`native compute void DeviceMemoryBarrierWithGroupSync();`);
         print(`native compute void GroupMemoryBarrierWithGroupSync();`);
         print();
-        
+
         for (let type of [`uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
             print(`${type} mul(${type} x, ${type} y) {`);
             print(`    return x * y;`);
             print(`}`);
         }
-        
+
         for (let type of [`uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
             for (let size of [2, 3, 4]) {
                 print(`${type}${size} mul(${type} x, ${type}${size} y) {`);
@@ -1823,7 +1829,7 @@ let standardLibrary = (function() {
                 print(`}`);
             }
         }
-        
+
         for (let type of [`half`, `float`]) {
             for (let i of [2, 3, 4]) {
                 for (let j of [2, 3, 4]) {
@@ -1848,7 +1854,7 @@ let standardLibrary = (function() {
                 }
             }
         }
-        
+
         for (let type of [`uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
             for (let size of [2, 3, 4]) {
                 print(`${type} mul(${type}${size} x, ${type}${size} y) {`);
@@ -1856,7 +1862,7 @@ let standardLibrary = (function() {
                 print(`}`);
             }
         }
-        
+
         for (let type of [`half`, `float`]) {
             for (let i of [2, 3, 4]) {
                 for (let j of [2, 3, 4]) {
@@ -1883,7 +1889,7 @@ let standardLibrary = (function() {
                 }
             }
         }
-        
+
         for (let type of [`half`, `float`]) {
             for (let i of [2, 3, 4]) {
                 for (let j of [2, 3, 4]) {
@@ -1906,15 +1912,14 @@ let standardLibrary = (function() {
         }
         print();
 
-        for (let type of [`uint`, `int`]) {
-            for (let functionName of [`Add`, `And`, `Exchange`, `Max`, `Min`, `Or`, `Xor`]) {
-                print(`native void Interlocked${functionName}(thread atomic_${type}*, ${type}, thread ${type}*);`);
-                print(`native void Interlocked${functionName}(threadgroup atomic_${type}*, ${type}, thread ${type}*);`);
-                print(`native void Interlocked${functionName}(device atomic_${type}*, ${type}, thread ${type}*);`);
+        for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+            for (let addressSpace2 of [`thread`, `device`, `threadgroup`]) {
+                for (let type of [`uint`, `int`]) {
+                    for (let functionName of [`Add`, `And`, `Exchange`, `Max`, `Min`, `Or`, `Xor`])
+                        print(`native void Interlocked${functionName}(${addressSpace1} atomic_${type}*, ${type}, ${addressSpace2} ${type}*);`);
+                    print(`native void InterlockedCompareExchange(${addressSpace1} atomic_${type}*, ${type}, ${type}, ${addressSpace2} ${type}*);`);
+                }
             }
-            print(`native void InterlockedCompareExchange(thread atomic_${type}*, ${type}, ${type}, thread ${type}*);`);
-            print(`native void InterlockedCompareExchange(threadgroup atomic_${type}*, ${type}, ${type}, thread ${type}*);`);
-            print(`native void InterlockedCompareExchange(device atomic_${type}*, ${type}, ${type}, thread ${type}*);`);
         }
         print();
 
@@ -1926,13 +1931,21 @@ let standardLibrary = (function() {
                 print(`native ${type}${length} Sample(Texture1D<${type}${length}>, sampler, float location, int offset);`);
                 print(`native ${type}${length} Load(Texture1D<${type}${length}>, int2 location);`);
                 print(`native ${type}${length} Load(Texture1D<${type}${length}>, int2 location, int offset);`);
-                print(`native void GetDimensions(Texture1D<${type}${length}>, uint MipLevel, thread uint* Width, thread uint* NumberOfLevels);`);
+                for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+                    for (let addressSpace2 of [`thread`, `device`, `threadgroup`])
+                        print(`native void GetDimensions(Texture1D<${type}${length}>, uint MipLevel, ${addressSpace1} uint* Width, ${addressSpace2} uint* NumberOfLevels);`);
+                }
                 print();
                 print(`native ${type}${length} Sample(Texture1DArray<${type}${length}>, sampler, float2 location);`);
                 print(`native ${type}${length} Sample(Texture1DArray<${type}${length}>, sampler, float2 location, int offset);`);
                 print(`native ${type}${length} Load(Texture1DArray<${type}${length}>, int3 location);`);
                 print(`native ${type}${length} Load(Texture1DArray<${type}${length}>, int3 location, int offset);`);
-                print(`native void GetDimensions(Texture1DArray<${type}${length}>, uint MipLevel, thread uint* Width, thread uint* Elements, thread uint* NumberOfLevels);`);
+                for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+                    for (let addressSpace2 of [`thread`, `device`, `threadgroup`]) {
+                        for (let addressSpace3 of [`thread`, `device`, `threadgroup`])
+                            print(`native void GetDimensions(Texture1DArray<${type}${length}>, uint MipLevel, ${addressSpace1} uint* Width, ${addressSpace2} uint* Elements, ${addressSpace3} uint* NumberOfLevels);`);
+                    }
+                }
                 print();
                 print(`native ${type}${length} Sample(Texture2D<${type}${length}>, sampler, float2 location);`);
                 print(`native ${type}${length} Sample(Texture2D<${type}${length}>, sampler, float2 location, int2 offset);`);
@@ -1960,7 +1973,12 @@ let standardLibrary = (function() {
                 }
                 print(`native ${type}${length} Load(Texture2D<${type}${length}>, int3 location);`);
                 print(`native ${type}${length} Load(Texture2D<${type}${length}>, int3 location, int2 offset);`);
-                print(`native void GetDimensions(Texture2D<${type}${length}>, uint MipLevel, thread uint* Width, thread uint* Height, thread uint* NumberOfLevels);`);
+                for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+                    for (let addressSpace2 of [`thread`, `device`, `threadgroup`])
+                        for (let addressSpace3 of [`thread`, `device`, `threadgroup`]) {
+                            print(`native void GetDimensions(Texture2D<${type}${length}>, uint MipLevel, ${addressSpace1} uint* Width, ${addressSpace2} uint* Height, ${addressSpace3} uint* NumberOfLevels);`);
+                    }
+                }
                 print();
                 print(`native ${type}${length} Sample(Texture2DArray<${type}${length}>, sampler, float3 location);`);
                 print(`native ${type}${length} Sample(Texture2DArray<${type}${length}>, sampler, float3 location, int2 offset);`);
@@ -1988,13 +2006,27 @@ let standardLibrary = (function() {
                 }
                 print(`native ${type}${length} Load(Texture2DArray<${type}${length}>, int4 location);`);
                 print(`native ${type}${length} Load(Texture2DArray<${type}${length}>, int4 location, int2 offset);`);
-                print(`native void GetDimensions(Texture2DArray<${type}${length}>, uint MipLevel, thread uint* Width, thread uint* Height, thread uint* Elements, thread uint* NumberOfLevels);`);
+                for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+                    for (let addressSpace2 of [`thread`, `device`, `threadgroup`]) {
+                        for (let addressSpace3 of [`thread`, `device`, `threadgroup`]) {
+                            for (let addressSpace4 of [`thread`, `device`, `threadgroup`])
+                                print(`native void GetDimensions(Texture2DArray<${type}${length}>, uint MipLevel, ${addressSpace1} uint* Width, ${addressSpace2} uint* Height, ${addressSpace3} uint* Elements, ${addressSpace4} uint* NumberOfLevels);`);
+                        }
+                    }
+                }
                 print();
                 print(`native ${type}${length} Sample(Texture3D<${type}${length}>, sampler, float3 location);`);
                 print(`native ${type}${length} Sample(Texture3D<${type}${length}>, sampler, float3 location, int3 offset);`);
                 print(`native ${type}${length} Load(Texture3D<${type}${length}>, int4 location);`);
                 print(`native ${type}${length} Load(Texture3D<${type}${length}>, int4 location, int3 offset);`);
-                print(`native void GetDimensions(Texture3D<${type}${length}>, uint MipLevel, thread uint* Width, thread uint* Height, thread uint* Depth, thread uint* NumberOfLevels);`);
+                for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+                    for (let addressSpace2 of [`thread`, `device`, `threadgroup`]) {
+                        for (let addressSpace3 of [`thread`, `device`, `threadgroup`]) {
+                            for (let addressSpace4 of [`thread`, `device`, `threadgroup`])
+                                print(`native void GetDimensions(Texture3D<${type}${length}>, uint MipLevel, ${addressSpace1} uint* Width, ${addressSpace2} uint* Height, ${addressSpace3} uint* Depth, ${addressSpace4} uint* NumberOfLevels);`);
+                        }
+                    }
+                }
                 print();
                 print(`native ${type}${length} Sample(TextureCube<${type}${length}>, sampler, float3 location);`);
                 print(`native ${type}${length} SampleBias(TextureCube<${type}${length}>, sampler, float3 location, float Bias);`);
@@ -2010,30 +2042,57 @@ let standardLibrary = (function() {
                             print(`native ${type}4 GatherAlpha(TextureCube<${type}${length}>, sampler, float3 location);`);
                     }
                 }
-                print(`native void GetDimensions(TextureCube<${type}${length}>, uint MipLevel, thread uint* Width, thread uint* Height, thread uint* NumberOfLevels);`);
+                for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+                    for (let addressSpace2 of [`thread`, `device`, `threadgroup`]) {
+                        for (let addressSpace3 of [`thread`, `device`, `threadgroup`])
+                            print(`native void GetDimensions(TextureCube<${type}${length}>, uint MipLevel, ${addressSpace1} uint* Width, ${addressSpace2} uint* Height, ${addressSpace3} uint* NumberOfLevels);`);
+                    }
+                }
                 print();
-                print(`native void GetDimensions(RWTexture1D<${type}${length}>, thread uint* Width);`);
-                print(`native void GetDimensions(RWTexture1D<${type}${length}>, thread float* Width);`);
+                for (let addressSpace of [`thread`, `device`, `threadgroup`]) {
+                    print(`native void GetDimensions(RWTexture1D<${type}${length}>, ${addressSpace} uint* Width);`);
+                    print(`native void GetDimensions(RWTexture1D<${type}${length}>, ${addressSpace} float* Width);`);
+                }
                 print(`native ${type}${length} Load(RWTexture1D<${type}${length}>, int location);`);
                 print(`native void Store(RWTexture1D<${type}${length}>, ${type}${length}, uint location);`);
                 print();
-                print(`native void GetDimensions(RWTexture1DArray<${type}${length}>, thread uint* Width, thread uint* Elements);`);
-                print(`native void GetDimensions(RWTexture1DArray<${type}${length}>, thread float* Width, thread uint* Elements);`);
+                for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+                    for (let addressSpace2 of [`thread`, `device`, `threadgroup`]) {
+                        print(`native void GetDimensions(RWTexture1DArray<${type}${length}>, ${addressSpace1} uint* Width, ${addressSpace2} uint* Elements);`);
+                        print(`native void GetDimensions(RWTexture1DArray<${type}${length}>, ${addressSpace1} float* Width, ${addressSpace2} uint* Elements);`);
+                    }
+                }
                 print(`native ${type}${length} Load(RWTexture1DArray<${type}${length}>, int2 location);`);
                 print(`native void Store(RWTexture1DArray<${type}${length}>, ${type}${length}, uint2 location);`);
                 print();
-                print(`native void GetDimensions(RWTexture2D<${type}${length}>, thread uint* Width, thread uint* Height);`);
-                print(`native void GetDimensions(RWTexture2D<${type}${length}>, thread float* Width, thread float* Height);`);
+                for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+                    for (let addressSpace2 of [`thread`, `device`, `threadgroup`]) {
+                        print(`native void GetDimensions(RWTexture2D<${type}${length}>, ${addressSpace1} uint* Width, ${addressSpace2} uint* Height);`);
+                        print(`native void GetDimensions(RWTexture2D<${type}${length}>, ${addressSpace1} float* Width, ${addressSpace2} float* Height);`);
+                    }
+                }
                 print(`native ${type}${length} Load(RWTexture2D<${type}${length}>, int2 location);`);
                 print(`native void Store(RWTexture2D<${type}${length}>, ${type}${length}, uint2 location);`);
                 print();
-                print(`native void GetDimensions(RWTexture2DArray<${type}${length}>, thread uint* Width, thread uint* Height, thread uint* Elements);`);
-                print(`native void GetDimensions(RWTexture2DArray<${type}${length}>, thread float* Width, thread float* Height, thread float* Elements);`);
+                for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+                    for (let addressSpace2 of [`thread`, `device`, `threadgroup`]) {
+                        for (let addressSpace3 of [`thread`, `device`, `threadgroup`]) {
+                            print(`native void GetDimensions(RWTexture2DArray<${type}${length}>, ${addressSpace1} uint* Width, ${addressSpace2} uint* Height, ${addressSpace3} uint* Elements);`);
+                            print(`native void GetDimensions(RWTexture2DArray<${type}${length}>, ${addressSpace1} float* Width, ${addressSpace2} float* Height, ${addressSpace3} float* Elements);`);
+                        }
+                    }
+                }
                 print(`native ${type}${length} Load(RWTexture2DArray<${type}${length}>, int3 location);`);
                 print(`native void Store(RWTexture2DArray<${type}${length}>, ${type}${length}, uint3 location);`);
                 print();
-                print(`native void GetDimensions(RWTexture3D<${type}${length}>, thread uint* Width, thread uint* Height, thread uint* Depth);`);
-                print(`native void GetDimensions(RWTexture3D<${type}${length}>, thread float* Width, thread float* Height, thread float* Depth);`);
+                for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+                    for (let addressSpace2 of [`thread`, `device`, `threadgroup`]) {
+                        for (let addressSpace3 of [`thread`, `device`, `threadgroup`]) {
+                            print(`native void GetDimensions(RWTexture3D<${type}${length}>, ${addressSpace1} uint* Width, ${addressSpace2} uint* Height, ${addressSpace3} uint* Depth);`);
+                            print(`native void GetDimensions(RWTexture3D<${type}${length}>, ${addressSpace1} float* Width, ${addressSpace2} float* Height, ${addressSpace3} float* Depth);`);
+                        }
+                    }
+                }
                 print(`native ${type}${length} Load(RWTexture3D<${type}${length}>, int3 location);`);
                 print(`native void Store(RWTexture3D<${type}${length}>, ${type}${length}, uint3 location);`);
                 print();
@@ -2063,7 +2122,12 @@ let standardLibrary = (function() {
             print(`native ${type}4 GatherCmpRed(TextureDepth2D<${type}>, sampler, float2 location, float compare_value, int2 offset);`);
             print(`native ${type} Load(TextureDepth2D<${type}>, int3 location);`);
             print(`native ${type} Load(TextureDepth2D<${type}>, int3 location, int2 offset);`);
-            print(`native void GetDimensions(TextureDepth2D<${type}>, uint MipLevel, thread uint* Width, thread uint* Height, thread uint* NumberOfLevels);`);
+            for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+                for (let addressSpace2 of [`thread`, `device`, `threadgroup`]) {
+                    for (let addressSpace3 of [`thread`, `device`, `threadgroup`])
+                        print(`native void GetDimensions(TextureDepth2D<${type}>, uint MipLevel, ${addressSpace1} uint* Width, ${addressSpace2} uint* Height, ${addressSpace3} uint* NumberOfLevels);`);
+                }
+            }
             print();
             print(`native ${type} Sample(TextureDepth2DArray<${type}>, sampler, float3 location);`);
             print(`native ${type} Sample(TextureDepth2DArray<${type}>, sampler, float3 location, int2 offset);`);
@@ -2087,7 +2151,14 @@ let standardLibrary = (function() {
             print(`native ${type}4 GatherCmpRed(TextureDepth2DArray<${type}>, sampler, float3 location, float compare_value, int2 offset);`);
             print(`native ${type} Load(TextureDepth2DArray<${type}>, int4 location);`);
             print(`native ${type} Load(TextureDepth2DArray<${type}>, int4 location, int2 offset);`);
-            print(`native void GetDimensions(TextureDepth2DArray<${type}>, uint MipLevel, thread uint* Width, thread uint* Height, thread uint* Elements, thread uint* NumberOfLevels);`);
+            for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+                for (let addressSpace2 of [`thread`, `device`, `threadgroup`]) {
+                    for (let addressSpace3 of [`thread`, `device`, `threadgroup`]) {
+                        for (let addressSpace4 of [`thread`, `device`, `threadgroup`])
+                            print(`native void GetDimensions(TextureDepth2DArray<${type}>, uint MipLevel, ${addressSpace1} uint* Width, ${addressSpace2} uint* Height, ${addressSpace3} uint* Elements, ${addressSpace4} uint* NumberOfLevels);`);
+                    }
+                }
+            }
             print();
             print(`native ${type} Sample(TextureDepthCube<${type}>, sampler, float3 location);`);
             print(`native ${type} SampleCmp(TextureDepthCube<${type}>, sampler, float3 location, ${type} CompareValue);`);
@@ -2099,15 +2170,30 @@ let standardLibrary = (function() {
             print(`native ${type}4 GatherRed(TextureDepthCube<${type}>, sampler, float3 location);`);
             print(`native ${type}4 GatherCmp(TextureDepthCube<${type}>, sampler, float3 location, float compare_value);`);
             print(`native ${type}4 GatherCmpRed(TextureDepthCube<${type}>, sampler, float3 location, float compare_value);`);
-            print(`native void GetDimensions(TextureDepthCube<${type}>, uint MipLevel, thread uint* Width, thread uint* Height, thread uint* NumberOfLevels);`);
+            for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+                for (let addressSpace2 of [`thread`, `device`, `threadgroup`]) {
+                    for (let addressSpace3 of [`thread`, `device`, `threadgroup`])
+                        print(`native void GetDimensions(TextureDepthCube<${type}>, uint MipLevel, ${addressSpace1} uint* Width, ${addressSpace2} uint* Height, ${addressSpace3} uint* NumberOfLevels);`);
+                }
+            }
             print();
-            print(`native void GetDimensions(RWTextureDepth2D<${type}>, thread uint* Width, thread uint* Height);`);
-            print(`native void GetDimensions(RWTextureDepth2D<${type}>, thread float* Width, thread float* Height);`);
+            for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+                for (let addressSpace2 of [`thread`, `device`, `threadgroup`]) {
+                    print(`native void GetDimensions(RWTextureDepth2D<${type}>, ${addressSpace1} uint* Width, ${addressSpace2} uint* Height);`);
+                    print(`native void GetDimensions(RWTextureDepth2D<${type}>, ${addressSpace1} float* Width, ${addressSpace2} float* Height);`);
+                }
+            }
             print(`native ${type} Load(RWTextureDepth2D<${type}>, int2 location);`);
             print(`native void Store(RWTextureDepth2D<${type}>, ${type}, uint2 location);`);
             print();
-            print(`native void GetDimensions(RWTextureDepth2DArray<${type}>, thread uint* Width, thread uint* Height, thread uint* Elements);`);
-            print(`native void GetDimensions(RWTextureDepth2DArray<${type}>, thread float* Width, thread float* Height, thread float* Elements);`);
+            for (let addressSpace1 of [`thread`, `device`, `threadgroup`]) {
+                for (let addressSpace2 of [`thread`, `device`, `threadgroup`]) {
+                    for (let addressSpace3 of [`thread`, `device`, `threadgroup`]) {
+                        print(`native void GetDimensions(RWTextureDepth2DArray<${type}>, ${addressSpace1} uint* Width, ${addressSpace2} uint* Height, ${addressSpace3} uint* Elements);`);
+                        print(`native void GetDimensions(RWTextureDepth2DArray<${type}>, ${addressSpace1} float* Width, ${addressSpace2} float* Height, ${addressSpace3} float* Elements);`);
+                    }
+                }
+            }
             print(`native ${type} Load(RWTextureDepth2DArray<${type}>, int3 location);`);
             print(`native void Store(RWTextureDepth2DArray<${type}>, ${type}, uint3 location);`);
             print();
index e118333..f316f54 100644 (file)
@@ -646,7 +646,7 @@ tests.simpleMakePtr = function()
         throw new Error("Expected 42 but got: " + value);
 }
 
-tests.threadArrayLoad = function()
+tests.threadArrayRefLoad = function()
 {
     let program = doPrep(`
         test int foo(thread int[] array)
@@ -660,7 +660,7 @@ tests.threadArrayLoad = function()
     checkInt(program, result, 89);
 }
 
-tests.threadArrayLoadIntLiteral = function()
+tests.threadArrayRefLoadIntLiteral = function()
 {
     let program = doPrep(`
         test int foo(thread int[] array)
@@ -674,7 +674,7 @@ tests.threadArrayLoadIntLiteral = function()
     checkInt(program, result, 89);
 }
 
-tests.deviceArrayLoad = function()
+tests.deviceArrayRefLoad = function()
 {
     let program = doPrep(`
         test int foo(device int[] array)
@@ -688,7 +688,7 @@ tests.deviceArrayLoad = function()
     checkInt(program, result, 89);
 }
 
-tests.threadArrayStore = function()
+tests.threadArrayRefStore = function()
 {
     let program = doPrep(`
         test void foo(thread int[] array, int value)
@@ -709,7 +709,7 @@ tests.threadArrayStore = function()
         throw new Error("Bad value stored into buffer (expected -111): " + buffer.get(0));
 }
 
-tests.deviceArrayStore = function()
+tests.deviceArrayRefStore = function()
 {
     let program = doPrep(`
         test void foo(device int[] array, int value)
@@ -730,7 +730,7 @@ tests.deviceArrayStore = function()
         throw new Error("Bad value stored into buffer (expected -111): " + buffer.get(0));
 }
 
-tests.deviceArrayStoreIntLiteral = function()
+tests.deviceArrayRefStoreIntLiteral = function()
 {
     let program = doPrep(`
         test void foo(device int[] array, int value)
@@ -751,6 +751,102 @@ tests.deviceArrayStoreIntLiteral = function()
         throw new Error("Bad value stored into buffer (expected -111): " + buffer.get(0));
 }
 
+tests.threadPointerLoad = function()
+{
+    let program = doPrep(`
+        test int foo(thread int* ptr)
+        {
+            return *ptr;
+        }
+    `);
+    let buffer = new EBuffer(1);
+    buffer.set(0, 89);
+    let result = callFunction(program, "foo", [TypedValue.box(new PtrType(externalOrigin, "thread", program.intrinsics.int), new EPtr(buffer, 0))]);
+    checkInt(program, result, 89);
+}
+
+tests.threadPointerStore = function()
+{
+    let program = doPrep(`
+        test void foo(thread int* ptr, int value)
+        {
+            *ptr = value;
+        }
+    `);
+    let buffer = new EBuffer(1);
+    buffer.set(0, 89);
+    let pointer = TypedValue.box(new PtrType(externalOrigin, "thread", program.intrinsics.int), new EPtr(buffer, 0));
+    callFunction(program, "foo", [pointer, makeInt(program, 123)]);
+    if (buffer.get(0) != 123)
+        throw new Error("Bad value stored into buffer (expected 123): " + buffer.get(0));
+    callFunction(program, "foo", [pointer, makeInt(program, 321)]);
+    if (buffer.get(0) != 321)
+        throw new Error("Bad value stored into buffer (expected 321): " + buffer.get(0));
+}
+
+tests.devicePointerLoad = function()
+{
+    let program = doPrep(`
+        test int foo(device int* ptr)
+        {
+            return *ptr;
+        }
+    `);
+    let buffer = new EBuffer(1);
+    buffer.set(0, 89);
+    let result = callFunction(program, "foo", [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int), new EPtr(buffer, 0))]);
+    checkInt(program, result, 89);
+}
+
+tests.devicePointerStore = function()
+{
+    let program = doPrep(`
+        test void foo(device int* ptr, int value)
+        {
+            *ptr = value;
+        }
+    `);
+    let buffer = new EBuffer(1);
+    buffer.set(0, 89);
+    let pointer = TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int), new EPtr(buffer, 0));
+    callFunction(program, "foo", [pointer, makeInt(program, 123)]);
+    if (buffer.get(0) != 123)
+        throw new Error("Bad value stored into buffer (expected 123): " + buffer.get(0));
+    callFunction(program, "foo", [pointer, makeInt(program, 321)]);
+    if (buffer.get(0) != 321)
+        throw new Error("Bad value stored into buffer (expected 321): " + buffer.get(0));
+}
+
+tests.arrayLoad = function()
+{
+    let program = doPrep(`
+        typedef IntArray = int[3];
+        test int foo(IntArray a)
+        {
+            return a[0];
+        }
+        test int bar(IntArray a)
+        {
+            return a[1];
+        }
+        test int baz(IntArray a)
+        {
+            return a[2];
+        }
+    `);
+    let buffer = new EBuffer(3);
+    buffer.set(0, 89);
+    buffer.set(1, 91);
+    buffer.set(2, 103);
+    let array = new TypedValue(program.types.get("IntArray").type, new EPtr(buffer, 0));
+    let result = callFunction(program, "foo", [array]);
+    checkInt(program, result, 89);
+    result = callFunction(program, "bar", [array]);
+    checkInt(program, result, 91);
+    result = callFunction(program, "baz", [array]);
+    checkInt(program, result, 103);
+}
+
 tests.typeMismatchReturn = function()
 {
     checkFail(
@@ -6856,6 +6952,185 @@ tests.numThreads = function() {
         }
     `), e => e instanceof WSyntaxError);
 
+tests.constantAddressSpace = function() {
+    checkFail(
+        () => doPrep(`
+            void foo(constant int* bar)
+            {
+                *bar = 0;
+            }
+        `),
+        (e) => e instanceof WTypeError && e.message.indexOf("constant address space") !== -1);
+    checkFail(
+        () => doPrep(`
+            void foo(constant int[] bar)
+            {
+                bar[0] = 0;
+            }
+        `),
+        (e) => e instanceof WTypeError && e.message.indexOf("constant address space") !== -1);
+    checkFail(
+        () => doPrep(`
+            typedef ConstantIntArrayRef = constant int[];
+            void foo(ConstantIntArrayRef[3] bar)
+            {
+                bar[0][0] = 0;
+            }
+        `),
+        (e) => e instanceof WTypeError && e.message.indexOf("constant address space") !== -1);
+    checkFail(
+        () => doPrep(`
+            typedef IntArray = int[3];
+            void foo(constant IntArray[] bar)
+            {
+                bar[0][0] = 0;
+            }
+        `),
+        (e) => e instanceof WTypeError && e.message.indexOf("constant address space") !== -1);
+    checkFail(
+        () => doPrep(`
+            typedef IntArray = int[3];
+            struct Bar {
+                IntArray baz;
+            }
+            void foo(constant Bar[] bar)
+            {
+                bar[0].baz[0] = 0;
+            }
+        `),
+        (e) => e instanceof WTypeError && e.message.indexOf("constant address space") !== -1);
+    checkFail(
+        () => doPrep(`
+            struct Bar {
+                int baz;
+            }
+            typedef BarArray = Bar[3];
+            void foo(constant BarArray[] bar)
+            {
+                bar[0][0].baz = 0;
+            }
+        `),
+        (e) => e instanceof WTypeError && e.message.indexOf("constant address space") !== -1);
+    checkFail(
+        () => doPrep(`
+            typedef IntArray = int[3];
+            struct Bar {
+                constant IntArray[] baz;
+            }
+            void foo(Bar bar)
+            {
+                bar.baz[0][0] = 0;
+            }
+        `),
+        (e) => e instanceof WTypeError && e.message.indexOf("constant address space") !== -1);
+    checkFail(
+        () => doPrep(`
+            typedef ConstantIntArrayRef = constant int[];
+            struct Bar {
+                ConstantIntArrayRef[3] baz;
+            }
+            void foo(Bar bar)
+            {
+                bar.baz[0][0] = 0;
+            }
+        `),
+        (e) => e instanceof WTypeError && e.message.indexOf("constant address space") !== -1);
+    checkFail(
+        () => doPrep(`
+            struct Bar {
+                int baz;
+            }
+            typedef ConstantBarArrayRef = constant Bar[];
+            void foo(ConstantBarArrayRef[3] bar)
+            {
+                bar[0][0].baz = 0;
+            }
+        `),
+        (e) => e instanceof WTypeError && e.message.indexOf("constant address space") !== -1);
+    checkFail(
+        () => doPrep(`
+            struct Bar {
+                constant int[] baz;
+            }
+            void foo(Bar[3] bar)
+            {
+                bar[0].baz[0] = 0;
+            }
+        `),
+        (e) => e instanceof WTypeError && e.message.indexOf("constant address space") !== -1);
+}
+
+tests.standardLibraryDevicePointers = function() {
+    let program = doPrep(`
+        test float foo1() {
+            float s;
+            float c;
+            sincos(0, &s, &c);
+            return c;
+        }
+        test float foo2() {
+            float s;
+            float c;
+            sincos(0, &s, &c);
+            return s;
+        }
+        test float foo3() {
+            thread float* s = null;
+            float c;
+            sincos(0, s, &c);
+            return c;
+        }
+        test float foo4() {
+            float s;
+            thread float* c = null;
+            sincos(0, &s, c);
+            return s;
+        }
+        test void foo5(device float* s) {
+            thread float* c = null;
+            sincos(0, s, c);
+        }
+        test void foo6(device float* c) {
+            thread float* s = null;
+            sincos(0, s, c);
+        }
+        test void foo7(device float* s, device float* c) {
+            sincos(0, s, c);
+        }
+        test void foo8(device float[] result) {
+            sincos(0, &result[0], &result[1]);
+        }
+    `);
+    checkFloat(program, callFunction(program, "foo1", []), 1);
+    checkFloat(program, callFunction(program, "foo2", []), 0);
+    checkFloat(program, callFunction(program, "foo3", []), 1);
+    checkFloat(program, callFunction(program, "foo4", []), 0);
+
+    let buffer = new EBuffer(2);
+    callFunction(program, "foo5", [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.float), new EPtr(buffer, 0))]);
+    if (buffer.get(0) != 0)
+        throw new Error("Bad value stored into buffer (expected 0): " + buffer.get(0));
+
+    callFunction(program, "foo6", [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.float), new EPtr(buffer, 0))]);
+    if (buffer.get(0) != 1)
+        throw new Error("Bad value stored into buffer (expected 1): " + buffer.get(0));
+    callFunction(program, "foo7", [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.float), new EPtr(buffer, 0)), TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.float), new EPtr(buffer, 1))]);
+    if (buffer.get(0) != 0)
+        throw new Error("Bad value stored into buffer (expected 0): " + buffer.get(0));
+    if (buffer.get(1) != 1)
+        throw new Error("Bad value stored into buffer (expected 1): " + buffer.get(1));
+
+    buffer.set(0, 0);
+    buffer.set(1, 0);
+    let arrayRef = TypedValue.box(
+        new ArrayRefType(externalOrigin, "device", program.intrinsics.float),
+        new EArrayRef(new EPtr(buffer, 0), 2));
+    callFunction(program, "foo8", [arrayRef]);
+    if (buffer.get(0) != 0)
+        throw new Error("Bad value stored into buffer (expected 0): " + buffer.get(0));
+    if (buffer.get(1) != 1)
+        throw new Error("Bad value stored into buffer (expected 1): " + buffer.get(1));
+}
 
     checkFail(() => doPrep(`
         struct R {