[tint][ir][fuzz] Gracefully handle builtin calls with null results

Fixes: 354724070
Change-Id: I72149d1e9b29ff766166a5e5ba50d4d29c290406
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/199778
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Auto-Submit: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index cef04d5..e78cca0 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -1212,15 +1212,23 @@
         symbols_,
     };
 
-    auto result = core::intrinsic::LookupFn(context, call->FriendlyName().c_str(), call->FuncId(),
-                                            Empty, args, core::EvaluationStage::kRuntime);
-    if (result != Success) {
-        AddError(call) << result.Failure();
+    auto builtin = core::intrinsic::LookupFn(context, call->FriendlyName().c_str(), call->FuncId(),
+                                             Empty, args, core::EvaluationStage::kRuntime);
+    if (builtin != Success) {
+        AddError(call) << builtin.Failure();
         return;
     }
 
-    if (result->return_type != call->Result(0)->Type()) {
+    TINT_ASSERT(builtin->return_type);
+
+    if (call->Result(0) == nullptr) {
+        AddError(call) << "call to builtin does not have a return type";
+        return;
+    }
+
+    if (builtin->return_type != call->Result(0)->Type()) {
         AddError(call) << "call result type does not match builtin return type";
+        return;
     }
 }
 
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index b2aac77..32b1cc5 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -702,6 +702,72 @@
 )");
 }
 
+TEST_F(IR_ValidatorTest, CallToBuiltinMissingResult) {
+    auto* f = b.Function("f", ty.void_());
+    b.Append(f->Block(), [&] {
+        auto* c = b.Call(ty.f32(), BuiltinFn::kAbs, 1_f);
+        c->SetResults(Vector{static_cast<ir::InstructionResult*>(nullptr)});
+        b.Return(f);
+    });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_EQ(res.Failure().reason.Str(),
+              R"(:3:5 error: abs: result is undefined
+    undef = abs 1.0f
+    ^^^^^
+
+:2:3 note: in block
+  $B1: {
+  ^^^
+
+:3:13 error: abs: call to builtin does not have a return type
+    undef = abs 1.0f
+            ^^^
+
+:2:3 note: in block
+  $B1: {
+  ^^^
+
+note: # Disassembly
+%f = func():void {
+  $B1: {
+    undef = abs 1.0f
+    ret
+  }
+}
+)");
+}
+
+TEST_F(IR_ValidatorTest, CallToBuiltinMismatchResultType) {
+    auto* f = b.Function("f", ty.void_());
+    b.Append(f->Block(), [&] {
+        auto* c = b.Call(ty.f32(), BuiltinFn::kAbs, 1_f);
+        c->Result(0)->SetType(ty.i32());
+        b.Return(f);
+    });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_EQ(res.Failure().reason.Str(),
+              R"(:3:14 error: abs: call result type does not match builtin return type
+    %2:i32 = abs 1.0f
+             ^^^
+
+:2:3 note: in block
+  $B1: {
+  ^^^
+
+note: # Disassembly
+%f = func():void {
+  $B1: {
+    %2:i32 = abs 1.0f
+    ret
+  }
+}
+)");
+}
+
 TEST_F(IR_ValidatorTest, Construct_Struct_ZeroValue) {
     auto* str_ty = ty.Struct(mod.symbols.New("MyStruct"), {
                                                               {mod.symbols.New("a"), ty.i32()},