summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2022-08-03 12:08:37 -0700
committerGitHub <noreply@github.com>2022-08-03 12:08:37 -0700
commite81a5fe56f3177fc3c7040e2320ae083e3746eb7 (patch)
tree884c15287bc10050e7883897dd266b27e62bff66
parent260fc5fbe58f2cf976d64993054c638769bc280f (diff)
Basic pointer usages. (#2342)
-rw-r--r--build/visual-studio/slang/slang.vcxproj1
-rw-r--r--build/visual-studio/slang/slang.vcxproj.filters3
-rw-r--r--examples/heterogeneous-hello-world/main.slang9
-rw-r--r--source/slang/core.meta.slang115
-rw-r--r--source/slang/slang-ast-expr.h15
-rw-r--r--source/slang/slang-ast-support-types.cpp13
-rw-r--r--source/slang/slang-ast-support-types.h8
-rw-r--r--source/slang/slang-check-conversion.cpp5
-rw-r--r--source/slang/slang-check-expr.cpp29
-rw-r--r--source/slang/slang-check-impl.h7
-rw-r--r--source/slang/slang-check-overload.cpp5
-rw-r--r--source/slang/slang-emit-c-like.cpp6
-rw-r--r--source/slang/slang-ir-inst-defs.h2
-rw-r--r--source/slang/slang-ir-peephole.cpp11
-rw-r--r--source/slang/slang-ir-util.cpp5
-rw-r--r--source/slang/slang-ir-util.h2
-rw-r--r--source/slang/slang-lower-to-ir.cpp38
-rw-r--r--source/slang/slang-parser.cpp91
-rw-r--r--tests/cpu-program/pointer-basics.slang26
-rw-r--r--tests/cpu-program/pointer-basics.slang.expected6
20 files changed, 363 insertions, 34 deletions
diff --git a/build/visual-studio/slang/slang.vcxproj b/build/visual-studio/slang/slang.vcxproj
index 534effb16..f0cccb341 100644
--- a/build/visual-studio/slang/slang.vcxproj
+++ b/build/visual-studio/slang/slang.vcxproj
@@ -471,6 +471,7 @@ IF EXIST ..\..\..\external\slang-glslang\bin\windows-aarch64\release\slang-glsla
<ClCompile Include="..\..\..\source\slang\slang-ast-print.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ast-reflect.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ast-substitutions.cpp" />
+ <ClCompile Include="..\..\..\source\slang\slang-ast-support-types.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ast-type.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ast-val.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-capability.cpp" />
diff --git a/build/visual-studio/slang/slang.vcxproj.filters b/build/visual-studio/slang/slang.vcxproj.filters
index afbd5ff8e..ea1fd80ea 100644
--- a/build/visual-studio/slang/slang.vcxproj.filters
+++ b/build/visual-studio/slang/slang.vcxproj.filters
@@ -506,6 +506,9 @@
<ClCompile Include="..\..\..\source\slang\slang-ast-substitutions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\source\slang\slang-ast-support-types.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\source\slang\slang-ast-type.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/examples/heterogeneous-hello-world/main.slang b/examples/heterogeneous-hello-world/main.slang
index 2a9c1eaf1..b852ca1a1 100644
--- a/examples/heterogeneous-hello-world/main.slang
+++ b/examples/heterogeneous-hello-world/main.slang
@@ -4,9 +4,9 @@ __target_intrinsic(cpp, "printf(\"%s\", ($0).getBuffer())")
public void writeln(String text);
[DllImport("User32")]
-int MessageBoxA(Ptr<void> hwnd, String text, String caption, uint flags);
+int MessageBoxA(void* hwnd, String text, String caption, uint flags);
-[COM]
+[COM("111702C2-2FD7-46F9-A318-DCCEEC96357E")]
interface IObject
{
int getValue(int value) throws int;
@@ -17,9 +17,8 @@ IObject createObject();
public __extern_cpp void main() throws int
{
- //writeln("hello world");
- //MessageBoxA(nullptr, "hello world!", "example", 0);
-
+ writeln("hello world");
+ MessageBoxA(nullptr, "hello world!", "example", 0);
IObject object = createObject();
int rs = try object.getValue(2);
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index fb39b43f2..1991eb583 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -358,9 +358,99 @@ __magic_type(PtrType)
__intrinsic_type($(kIROp_PtrType))
struct Ptr
{
+ __intrinsic_op($(kIROp_Load))
+ static T __load(Ptr<T> ptr);
+
+ __intrinsic_op($(kIROp_Store))
+ static void __store(Ptr<T> ptr, T val);
+
+ __intrinsic_op($(kIROp_getElementPtr))
+ static Ptr<T> __getElementPtr(Ptr<T> ptr, int index);
+
+ __intrinsic_op($(kIROp_Neq))
+ __generic<U:__BuiltinArithmeticType>
+ static bool __neq(Ptr<T> ptr, U val);
+
+ __intrinsic_op($(kIROp_Eql))
+ __generic<U:__BuiltinArithmeticType>
+ static bool __eql(Ptr<T> ptr, U val);
+
+ __generic<U>
+ __intrinsic_op($(kIROp_BitCast))
+ __init(Ptr<U> ptr);
+
+ __intrinsic_op($(kIROp_BitCast))
+ __init(uint64_t val);
+
+ __intrinsic_op($(kIROp_BitCast))
+ __init(int64_t val);
+
+ __subscript(int index) -> T
+ {
+ [__unsafeForceInlineEarly]
+ get
+ {
+ return __load(__getElementPtr(this, index));
+ }
+
+ [__unsafeForceInlineEarly]
+ set(T newValue)
+ {
+ __store(__getElementPtr(this, index), newValue);
+ }
+
+ __intrinsic_op($(kIROp_getElementPtr))
+ ref;
+ }
};
__generic<T>
+__intrinsic_op($(kIROp_Less))
+bool operator<(Ptr<T> p1, Ptr<T> p2);
+
+__generic<T>
+__intrinsic_op($(kIROp_Leq))
+bool operator<=(Ptr<T> p1, Ptr<T> p2);
+
+__generic<T>
+__intrinsic_op($(kIROp_Greater))
+bool operator>(Ptr<T> p1, Ptr<T> p2);
+
+__generic<T>
+__intrinsic_op($(kIROp_Geq))
+bool operator>=(Ptr<T> p1, Ptr<T> p2);
+
+__generic<T>
+__intrinsic_op($(kIROp_Neq))
+bool operator!=(Ptr<T> p1, Ptr<T> p2);
+
+__generic<T>
+__intrinsic_op($(kIROp_Eql))
+bool operator==(Ptr<T> p1, Ptr<T> p2);
+
+extension bool
+{
+ __generic<T>
+ __implicit_conversion($(kConversionCost_PtrToBool))
+ __intrinsic_op($(kIROp_CastPtrToBool))
+ __init(Ptr<T> ptr);
+}
+
+extension uint64_t
+{
+ __generic<T>
+ __intrinsic_op($(kIROp_Construct))
+ __init(Ptr<T> ptr);
+}
+
+extension int64_t
+{
+ __generic<T>
+ __intrinsic_op($(kIROp_Construct))
+ __init(Ptr<T> ptr);
+}
+
+__generic<T>
__magic_type(OutType)
__intrinsic_type($(kIROp_OutType))
struct Out
@@ -1620,6 +1710,25 @@ for (auto op : intrinsicUnaryOps)
}}}}
+__generic<T>
+__intrinsic_op(0)
+__prefix Ref<T> operator*(Ptr<T> value);
+
+__generic<T>
+__intrinsic_op(0)
+__prefix Ptr<T> operator&(__ref T value);
+
+__generic<T>
+__intrinsic_op($(kIROp_getElementPtr))
+Ptr<T> operator+(Ptr<T> value, int64_t offset);
+
+__generic<T>
+[__unsafeForceInlineEarly]
+Ptr<T> operator-(Ptr<T> value, int64_t offset)
+{
+ return Ptr<T>.__getElementPtr(value, -offset);
+}
+
__generic<T : __BuiltinArithmeticType>
[__unsafeForceInlineEarly]
__prefix T operator+(T value)
@@ -1679,6 +1788,12 @@ __generic<T : __BuiltinArithmeticType, let R : int, let C : int>
matrix<T,R,C> operator$(op.name)(in out matrix<T,R,C> value)
{$(fixity.bodyPrefix) value = value $(op.binOp) T(1); return $(fixity.returnVal); }
+$(fixity.qual)
+__generic<T>
+[__unsafeForceInlineEarly]
+Ptr<T> operator$(op.name)(in out Ptr<T> value)
+{$(fixity.bodyPrefix) value = value $(op.binOp) 1; return $(fixity.returnVal); }
+
${{{{
}
diff --git a/source/slang/slang-ast-expr.h b/source/slang/slang-ast-expr.h
index 3fbbe05ea..4a9cc475d 100644
--- a/source/slang/slang-ast-expr.h
+++ b/source/slang/slang-ast-expr.h
@@ -374,6 +374,13 @@ class ExtractExistentialValueExpr: public Expr
DeclRef<VarDeclBase> declRef;
};
+class OpenRefExpr : public Expr
+{
+ SLANG_AST_CLASS(OpenRefExpr)
+
+ Expr* innerExpr = nullptr;
+};
+
/// An expression of the form `__jvp(fn)` to access the
/// forward-mode derivative version of the function `fn`
///
@@ -424,4 +431,12 @@ class ModifiedTypeExpr : public Expr
TypeExp base;
};
+ /// A type expression that rrepresents a pointer type, e.g. T*
+class PointerTypeExpr : public Expr
+{
+ SLANG_AST_CLASS(PointerTypeExpr)
+
+ TypeExp base;
+};
+
} // namespace Slang
diff --git a/source/slang/slang-ast-support-types.cpp b/source/slang/slang-ast-support-types.cpp
new file mode 100644
index 000000000..badb524bb
--- /dev/null
+++ b/source/slang/slang-ast-support-types.cpp
@@ -0,0 +1,13 @@
+#include "slang-ast-support-types.h"
+#include "slang-ast-base.h"
+#include "slang-ast-type.h"
+
+Slang::QualType::QualType(Type* type)
+ : type(type)
+ , isLeftValue(false)
+{
+ if (as<RefType>(type))
+ {
+ isLeftValue = true;
+ }
+}
diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h
index e8ab51fbd..3c161877c 100644
--- a/source/slang/slang-ast-support-types.h
+++ b/source/slang/slang-ast-support-types.h
@@ -98,6 +98,9 @@ namespace Slang
// Cost of converting an integer to a floating-point type
kConversionCost_IntegerToFloatConversion = 400,
+ // Cost of converting a pointer to bool
+ kConversionCost_PtrToBool = 400,
+
// Default case (usable for user-defined conversions)
kConversionCost_Default = 500,
@@ -472,10 +475,7 @@ namespace Slang
: isLeftValue(false)
{}
- QualType(Type* type)
- : type(type)
- , isLeftValue(false)
- {}
+ QualType(Type* type);
Type* Ptr() { return type; }
diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp
index b4c5ebb4a..6290acbd9 100644
--- a/source/slang/slang-check-conversion.cpp
+++ b/source/slang/slang-check-conversion.cpp
@@ -639,6 +639,11 @@ namespace Slang
return true;
}
+ if (auto refType = as<RefType>(toType))
+ {
+ return _coerce(refType->getValueType(), outToExpr, fromType, fromExpr, outCost);
+ }
+
// If both are string types we assume they are convertable in both directions
if (as<StringTypeBase>(fromType) && as<StringTypeBase>(toType))
{
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index 1895da70b..addd3a5c4 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -231,6 +231,21 @@ namespace Slang
return expr;
}
+ Expr* SemanticsVisitor::maybeOpenRef(Expr* expr)
+ {
+ auto exprType = expr->type.type;
+
+ if (auto refType = as<RefType>(exprType))
+ {
+ auto openRef = m_astBuilder->create<OpenRefExpr>();
+ openRef->innerExpr = expr;
+ openRef->type.isLeftValue = true;
+ openRef->type.type = refType->getValueType();
+ return openRef;
+ }
+ return expr;
+ }
+
static SourceLoc _getMemberOpLoc(Expr* expr)
{
if (auto m = as<MemberExpr>(expr))
@@ -1329,8 +1344,8 @@ namespace Slang
Expr* SemanticsVisitor::checkAssignWithCheckedOperands(AssignExpr* expr)
{
auto type = expr->left->type;
-
- expr->right = coerce(type, expr->right);
+ auto right = maybeOpenRef(expr->right);
+ expr->right = coerce(type, right);
if (!type.isLeftValue)
{
@@ -2514,6 +2529,16 @@ namespace Slang
return expr;
}
+ Expr* SemanticsExprVisitor::visitPointerTypeExpr(PointerTypeExpr* expr)
+ {
+ expr->base = CheckProperType(expr->base);
+ if (as<ErrorType>(expr->base.type))
+ expr->type = expr->base.type;
+ auto ptrType = m_astBuilder->getPtrType(expr->base.type);
+ expr->type = m_astBuilder->getTypeType(ptrType);
+ return expr;
+ }
+
Expr* SemanticsExprVisitor::visitModifiedTypeExpr(ModifiedTypeExpr* expr)
{
// The base type should be a proper type (not an expression, generic, etc.)
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index ce1093d09..c7b3f432a 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -499,6 +499,10 @@ namespace Slang
///
Expr* maybeOpenExistential(Expr* expr);
+ /// If `expr` has Ref<T> Type, convert it into an l-value expr that has T type.
+ Expr* maybeOpenRef(Expr* expr);
+
+
Expr* ConstructDeclRefExpr(
DeclRef<Decl> declRef,
Expr* baseExpr,
@@ -1722,6 +1726,7 @@ namespace Slang
CASE(ModifierCastExpr)
CASE(LetExpr)
CASE(ExtractExistentialValueExpr)
+ CASE(OpenRefExpr)
#undef CASE
@@ -1734,12 +1739,14 @@ namespace Slang
Expr* visitThisExpr(ThisExpr* expr);
Expr* visitThisTypeExpr(ThisTypeExpr* expr);
Expr* visitAndTypeExpr(AndTypeExpr* expr);
+ Expr* visitPointerTypeExpr(PointerTypeExpr* expr);
Expr* visitModifiedTypeExpr(ModifiedTypeExpr* expr);
Expr* visitJVPDifferentiateExpr(JVPDifferentiateExpr* expr);
/// Perform semantic checking on a `modifier` that is being applied to the given `type`
Val* checkTypeModifier(Modifier* modifier, Type* type);
+
};
struct SemanticsStmtVisitor
diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp
index 7f2386eb4..abb049a84 100644
--- a/source/slang/slang-check-overload.cpp
+++ b/source/slang/slang-check-overload.cpp
@@ -1438,6 +1438,11 @@ namespace Slang
for (auto& arg : expr->arguments)
{
+ arg = maybeOpenRef(arg);
+ }
+
+ for (auto& arg : expr->arguments)
+ {
arg = maybeOpenExistential(arg);
}
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp
index c3ae31894..b6540b5f1 100644
--- a/source/slang/slang-emit-c-like.cpp
+++ b/source/slang/slang-emit-c-like.cpp
@@ -1943,7 +1943,10 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO
auto rightSidePrec = rightSide(outerPrec, info);
auto postfixInfo = getInfo(EmitOp::Postfix);
bool rightSideNeedClose = maybeEmitParens(rightSidePrec, postfixInfo);
- emitDereferenceOperand(inst->getOperand(0), leftSide(rightSidePrec, postfixInfo));
+ if (isPtrToArrayType(inst->getOperand(0)->getDataType()))
+ emitDereferenceOperand(inst->getOperand(0), leftSide(rightSidePrec, postfixInfo));
+ else
+ emitOperand(inst->getOperand(0), leftSide(rightSidePrec, postfixInfo));
m_writer->emit("[");
emitOperand(inst->getOperand(1), getInfo(EmitOp::General));
m_writer->emit("]");
@@ -2061,7 +2064,6 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO
m_writer->emit(")");
}
break;
-
case kIROp_GlobalConstant:
case kIROp_GetValueFromBoundInterface:
emitOperand(inst->getOperand(0), outerPrec);
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index 8a62e34d4..afb132af7 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -738,7 +738,7 @@ INST(ExtractTaggedUnionPayload, extractTaggedUnionPayload, 1, 0)
INST(BitCast, bitCast, 1, 0)
INST(Reinterpret, reinterpret, 1, 0)
-
+INST(CastPtrToBool, CastPtrToBool, 1, 0)
INST(JVPDifferentiate, jvpDifferentiate, 1, 0)
// Converts other resources (such as ByteAddressBuffer) to the equivalent StructuredBuffer
diff --git a/source/slang/slang-ir-peephole.cpp b/source/slang/slang-ir-peephole.cpp
index 6cb5d2971..ffdb84c4a 100644
--- a/source/slang/slang-ir-peephole.cpp
+++ b/source/slang/slang-ir-peephole.cpp
@@ -85,6 +85,17 @@ struct PeepholeContext : InstPassBase
}
}
break;
+ case kIROp_CastPtrToBool:
+ {
+ auto ptr = inst->getOperand(0);
+ IRBuilder builder(&sharedBuilderStorage);
+ builder.setInsertBefore(inst);
+ auto neq = builder.emitNeq(ptr, builder.getPtrValue(nullptr));
+ inst->replaceUsesWith(neq);
+ inst->removeAndDeallocate();
+ changed = true;
+ }
+ break;
default:
break;
}
diff --git a/source/slang/slang-ir-util.cpp b/source/slang/slang-ir-util.cpp
index a515217d9..d91252fcc 100644
--- a/source/slang/slang-ir-util.cpp
+++ b/source/slang/slang-ir-util.cpp
@@ -38,4 +38,9 @@ bool isPtrToClassType(IRInst* type)
return isPointerOfType(type, kIROp_ClassType);
}
+bool isPtrToArrayType(IRInst* type)
+{
+ return isPointerOfType(type, kIROp_ArrayType) || isPointerOfType(type, kIROp_UnsizedArrayType);
+}
+
}
diff --git a/source/slang/slang-ir-util.h b/source/slang/slang-ir-util.h
index 2c11374e3..5a09638d4 100644
--- a/source/slang/slang-ir-util.h
+++ b/source/slang/slang-ir-util.h
@@ -11,6 +11,8 @@ namespace Slang
bool isPtrToClassType(IRInst* type);
+bool isPtrToArrayType(IRInst* type);
+
// True if ptrType is a pointer type to elementType
bool isPointerOfType(IRInst* ptrType, IRInst* elementType);
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 66f314d06..be7373d40 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -704,6 +704,11 @@ LoweredValInfo emitCallToDeclRef(
// so we will emit an instruction with the chosen
// opcode, and the arguments to the call as its operands.
//
+ if (intrinsicOpModifier->op == 0) // Identity, just pass operand 0 through.
+ {
+ SLANG_RELEASE_ASSERT(argCount == 1);
+ return LoweredValInfo::simple(args[0]);
+ }
auto intrinsicOp = getIntrinsicOp(funcDecl, intrinsicOpModifier);
return LoweredValInfo::simple(builder->emitIntrinsicInst(
type,
@@ -4002,6 +4007,12 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
UNREACHABLE_RETURN(LoweredValInfo());
}
+ LoweredValInfo visitPointerTypeExpr(PointerTypeExpr* /*expr*/)
+ {
+ SLANG_UNIMPLEMENTED_X("'*' type expression during code generation");
+ UNREACHABLE_RETURN(LoweredValInfo());
+ }
+
LoweredValInfo visitAssocTypeDecl(AssocTypeDecl* decl)
{
SLANG_UNIMPLEMENTED_X("associatedtype expression during code generation");
@@ -4105,6 +4116,11 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
context->shared->extValues.add(info);
return LoweredValInfo::extractedExistential(info);
}
+
+ LoweredValInfo visitOpenRefExpr(OpenRefExpr* expr)
+ {
+ return lowerLValueExpr(context, expr->innerExpr);
+ }
};
struct LValueExprLoweringVisitor : ExprLoweringVisitorBase<LValueExprLoweringVisitor>
@@ -4264,6 +4280,14 @@ struct RValueExprLoweringVisitor : ExprLoweringVisitorBase<RValueExprLoweringVis
return LoweredValInfo::simple(irSwizzle);
}
+
+ LoweredValInfo visitOpenRefExpr(OpenRefExpr* expr)
+ {
+ auto inner = lowerLValueExpr(context, expr->innerExpr);
+ auto builder = getBuilder();
+ auto irLoad = builder->emitLoad(inner.val);
+ return LoweredValInfo::simple(irLoad);
+ }
};
LoweredValInfo lowerLValueExpr(
@@ -4274,7 +4298,12 @@ LoweredValInfo lowerLValueExpr(
LValueExprLoweringVisitor visitor;
visitor.context = context;
- return visitor.dispatch(expr);
+ auto info = visitor.dispatch(expr);
+ if (as<RefType>(expr->type))
+ {
+ info.flavor = LoweredValInfo::Flavor::Ptr;
+ }
+ return info;
}
LoweredValInfo lowerRValueExpr(
@@ -4285,7 +4314,12 @@ LoweredValInfo lowerRValueExpr(
RValueExprLoweringVisitor visitor;
visitor.context = context;
- return visitor.dispatch(expr);
+ auto info = visitor.dispatch(expr);
+ if (as<RefType>(expr->type))
+ {
+ info.val = context->irBuilder->emitLoad(info.val);
+ }
+ return info;
}
struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor>
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index dbf329e9a..cdf418d3d 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -1807,9 +1807,10 @@ namespace Slang
case Declarator::Flavor::Pointer:
{
auto ptrDeclarator = (PointerDeclarator*) declarator.Ptr();
-
- // TODO(tfoley): we don't support pointers for now
- // ioInfo->typeSpec = new PointerTypeExpr(ioInfo->typeSpec);
+ auto ptrTypeExpr = astBuilder->create<PointerTypeExpr>();
+ ptrTypeExpr->loc = ptrDeclarator->starLoc;
+ ptrTypeExpr->base.exp = ioInfo->typeSpec;
+ ioInfo->typeSpec = ptrTypeExpr;
declarator = ptrDeclarator->inner;
}
@@ -2014,6 +2015,17 @@ namespace Slang
memberExpr->name = expectIdentifier(parser).name;
return memberExpr;
}
+ static Expr* parseStaticMemberType(Parser* parser, Expr* base, SourceLoc opLoc)
+ {
+ // When called the :: or . have been consumed, so don't need to consume here.
+
+ StaticMemberExpr* memberExpr = parser->astBuilder->create<StaticMemberExpr>();
+ memberExpr->memberOperatorLoc = opLoc;
+ parser->FillPosition(memberExpr);
+ memberExpr->baseExpression = base;
+ memberExpr->name = expectIdentifier(parser).name;
+ return memberExpr;
+ }
// Parse option `[]` braces after a type expression, that indicate an array type
static Expr* parsePostfixTypeSuffix(
@@ -2021,18 +2033,31 @@ namespace Slang
Expr* inTypeExpr)
{
auto typeExpr = inTypeExpr;
- while (parser->LookAheadToken(TokenType::LBracket))
+ for (;;)
{
- IndexExpr* arrType = parser->astBuilder->create<IndexExpr>();
- arrType->loc = typeExpr->loc;
- arrType->baseExpression = typeExpr;
- parser->ReadToken(TokenType::LBracket);
- if (!parser->LookAheadToken(TokenType::RBracket))
+ Token token;
+ if (parser->LookAheadToken(TokenType::LBracket))
{
- arrType->indexExpression = parser->ParseExpression();
+ IndexExpr* arrType = parser->astBuilder->create<IndexExpr>();
+ arrType->loc = typeExpr->loc;
+ arrType->baseExpression = typeExpr;
+ parser->ReadToken(TokenType::LBracket);
+ if (!parser->LookAheadToken(TokenType::RBracket))
+ {
+ arrType->indexExpression = parser->ParseExpression();
+ }
+ parser->ReadToken(TokenType::RBracket);
+ typeExpr = arrType;
}
- parser->ReadToken(TokenType::RBracket);
- typeExpr = arrType;
+ else if (AdvanceIf(parser, TokenType::OpMul, &token))
+ {
+ PointerTypeExpr* ptrType = parser->astBuilder->create<PointerTypeExpr>();
+ ptrType->loc = token.loc;
+ ptrType->base.exp = typeExpr;
+ typeExpr = ptrType;
+ }
+ else
+ break;
}
return typeExpr;
}
@@ -2309,7 +2334,7 @@ namespace Slang
case TokenType::Scope:
{
auto opToken = parser->ReadToken(TokenType::Scope);
- typeExpr = parseMemberType(parser, typeExpr, opToken.loc);
+ typeExpr = parseStaticMemberType(parser, typeExpr, opToken.loc);
break;
}
case TokenType::Dot:
@@ -4368,7 +4393,7 @@ namespace Slang
// with any side effects.
//
//
- if (LookAheadToken(TokenType::Identifier))
+ if (LookAheadToken(TokenType::Identifier) || LookAheadToken(TokenType::OpMul))
{
// Reset the cursor and try to parse a declaration now.
// Note: the declaration will consume any modifiers
@@ -5171,6 +5196,10 @@ namespace Slang
static bool _isCast(Parser* parser, Expr* expr)
{
+ if (as<PointerTypeExpr>(expr))
+ {
+ return true;
+ }
// We can't just look at expr and look up if it's a type, because we allow
// out-of-order declarations. So to a first approximation we'll try and
@@ -5231,6 +5260,8 @@ namespace Slang
}
case TokenType::OpAdd:
case TokenType::OpSub:
+ case TokenType::OpMul:
+ case TokenType::OpBitAnd:
{
// + - are ambiguous, it could be a binary + or - so -> expression, or unary -> cast
//
@@ -5300,6 +5331,24 @@ namespace Slang
return false;
}
+ static bool tryParseExpression(Parser* parser, Expr* &outExpr, TokenType tokenTypeAfter)
+ {
+ auto cursor = parser->tokenReader.getCursor();
+ auto isRecovering = parser->isRecovering;
+ auto oldSink = parser->sink;
+ DiagnosticSink newSink(parser->sink->getSourceManager(), nullptr);
+ parser->sink = &newSink;
+ outExpr = parser->ParseExpression();
+ parser->sink = oldSink;
+ parser->isRecovering = isRecovering;
+ if (outExpr && newSink.getErrorCount() == 0 && parser->LookAheadToken(tokenTypeAfter))
+ {
+ return true;
+ }
+ parser->tokenReader.setCursor(cursor);
+ return false;
+ }
+
static Expr* parseAtomicExpr(Parser* parser)
{
switch( peekTokenType(parser) )
@@ -5319,12 +5368,12 @@ namespace Slang
case TokenType::LParent:
{
Token openParen = parser->ReadToken(TokenType::LParent);
-
- if (peekTypeName(parser) && parser->LookAheadToken(TokenType::RParent, 1))
+ Expr* typeExpr = nullptr;
+ if (peekTypeName(parser) && parser->LookAheadToken(TokenType::RParent))
{
TypeCastExpr* tcexpr = parser->astBuilder->create<ExplicitCastExpr>();
parser->FillPosition(tcexpr);
- tcexpr->functionExpr = parser->ParseType();
+ tcexpr->functionExpr = typeExpr;
parser->ReadToken(TokenType::RParent);
auto arg = parsePrefixExpr(parser);
@@ -5339,7 +5388,11 @@ namespace Slang
// branch will be taken. This is okay in so far as SomeScope::Thing will parse
// as an expression.
- Expr* base = parser->ParseExpression();
+ Expr* base = nullptr;
+ if (!tryParseExpression(parser, base, TokenType::RParent))
+ {
+ base = parser->ParseType();
+ }
parser->ReadToken(TokenType::RParent);
@@ -5853,6 +5906,8 @@ namespace Slang
case TokenType::OpNot:
case TokenType::OpInc:
case TokenType::OpDec:
+ case TokenType::OpMul:
+ case TokenType::OpBitAnd:
{
PrefixExpr* prefixExpr = parser->astBuilder->create<PrefixExpr>();
parser->FillPosition(prefixExpr);
diff --git a/tests/cpu-program/pointer-basics.slang b/tests/cpu-program/pointer-basics.slang
new file mode 100644
index 000000000..3054cda1c
--- /dev/null
+++ b/tests/cpu-program/pointer-basics.slang
@@ -0,0 +1,26 @@
+//TEST:EXECUTABLE:
+__target_intrinsic(cpp, "printf(\"%s\\n\", ($0).getBuffer())")
+void writeln(String text);
+
+public __extern_cpp int main()
+{
+ uint2 value;
+ int *pValue = (int*)&value;
+ *pValue = 1;
+ (*pValue)++;
+ ++pValue[0];
+ ++pValue;
+ *pValue = 1;
+ pValue = (int *)&value;
+ int64_t ptrVal = int64_t(pValue);
+ pValue = (int *)ptrVal;
+ if (pValue
+ && pValue != nullptr
+ && ptrVal != 0
+ && value[0] == 3
+ && pValue[1] == 1)
+ writeln("Success");
+ else
+ writeln("Fail");
+ return 0;
+} \ No newline at end of file
diff --git a/tests/cpu-program/pointer-basics.slang.expected b/tests/cpu-program/pointer-basics.slang.expected
new file mode 100644
index 000000000..9e97ae031
--- /dev/null
+++ b/tests/cpu-program/pointer-basics.slang.expected
@@ -0,0 +1,6 @@
+result code = 0
+standard error = {
+}
+standard output = {
+Success
+}