[MachineVerifier][GlobalISel] Verifying generic extends and truncates

Making sure we don't truncate / extend pointers, don't try to change
vector topology or bitcast vectors to scalars or back, and most
importantly, don't extend to a smaller type or truncate to a large
one.

Reviewers: qcolombet t.p.northover aditya_nandakumar

Reviewed By: qcolombet

Subscribers: rovka, kristof.beyls, llvm-commits

Differential Revision: https://reviews.llvm.org/D46490

llvm-svn: 331718
This commit is contained in:
Roman Tereshin 2018-05-08 02:48:15 +00:00
parent de9f27a4ff
commit dc77820944
3 changed files with 145 additions and 6 deletions

View File

@ -986,6 +986,58 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
MI);
break;
}
case TargetOpcode::G_SEXT:
case TargetOpcode::G_ZEXT:
case TargetOpcode::G_ANYEXT:
case TargetOpcode::G_TRUNC:
case TargetOpcode::G_FPEXT:
case TargetOpcode::G_FPTRUNC: {
// Number of operands and presense of types is already checked (and
// reported in case of any issues), so no need to report them again. As
// we're trying to report as many issues as possible at once, however, the
// instructions aren't guaranteed to have the right number of operands or
// types attached to them at this point
assert(MCID.getNumOperands() == 2 && "Expected 2 operands G_*{EXT,TRUNC}");
if (MI->getNumOperands() < MCID.getNumOperands())
break;
LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
LLT SrcTy = MRI->getType(MI->getOperand(1).getReg());
if (!DstTy.isValid() || !SrcTy.isValid())
break;
LLT DstElTy = DstTy.isVector() ? DstTy.getElementType() : DstTy;
LLT SrcElTy = SrcTy.isVector() ? SrcTy.getElementType() : SrcTy;
if (DstElTy.isPointer() || SrcElTy.isPointer())
report("Generic extend/truncate can not operate on pointers", MI);
if (DstTy.isVector() != SrcTy.isVector()) {
report("Generic extend/truncate must be all-vector or all-scalar", MI);
// Generally we try to report as many issues as possible at once, but in
// this case it's not clear what should we be comparing the size of the
// scalar with: the size of the whole vector or its lane. Instead of
// making an arbitrary choice and emitting not so helpful message, let's
// avoid the extra noise and stop here.
break;
}
if (DstTy.isVector() && DstTy.getNumElements() != SrcTy.getNumElements())
report("Generic vector extend/truncate must preserve number of lanes",
MI);
unsigned DstSize = DstElTy.getSizeInBits();
unsigned SrcSize = SrcElTy.getSizeInBits();
switch (MI->getOpcode()) {
default:
if (DstSize <= SrcSize)
report("Generic extend has destination type no larger than source", MI);
break;
case TargetOpcode::G_TRUNC:
case TargetOpcode::G_FPTRUNC:
if (DstSize >= SrcSize)
report("Generic truncate has destination type no smaller than source",
MI);
break;
}
break;
}
case TargetOpcode::COPY: {
if (foundErrors)
break;

View File

@ -10,9 +10,9 @@ body: |
bb.0:
liveins: $sgpr0_sgpr1
; CHECK-LABEL: name: trunc_i64_to_i32_s
; CHECK: [[COPY:%[0-9]+]]:sgpr(s32) = COPY $sgpr0
; CHECK: [[TRUNC:%[0-9]+]]:sgpr(s32) = G_TRUNC [[COPY]](s32)
%0:_(s32) = COPY $sgpr0
; CHECK: [[COPY:%[0-9]+]]:sgpr(s64) = COPY $sgpr0
; CHECK: [[TRUNC:%[0-9]+]]:sgpr(s32) = G_TRUNC [[COPY]](s64)
%0:_(s64) = COPY $sgpr0_sgpr1
%1:_(s32) = G_TRUNC %0
...
@ -24,8 +24,8 @@ body: |
bb.0:
liveins: $vgpr0_vgpr1
; CHECK-LABEL: name: trunc_i64_to_i32_v
; CHECK: [[COPY:%[0-9]+]]:vgpr(s32) = COPY $vgpr0
; CHECK: [[TRUNC:%[0-9]+]]:vgpr(s32) = G_TRUNC [[COPY]](s32)
%0:_(s32) = COPY $vgpr0
; CHECK: [[COPY:%[0-9]+]]:vgpr(s64) = COPY $vgpr0
; CHECK: [[TRUNC:%[0-9]+]]:vgpr(s32) = G_TRUNC [[COPY]](s64)
%0:_(s64) = COPY $vgpr0_vgpr1
%1:_(s32) = G_TRUNC %0
...

View File

@ -0,0 +1,87 @@
# RUN: not llc -o - %s -mtriple=x86_64-- -verify-machineinstrs -run-pass=none 2>&1 | FileCheck %s
# CHECK: Bad machine code: Generic extend/truncate can not operate on pointers
# CHECK-NEXT: - function: bad_generic_extends_and_truncates
# CHECK-NEXT: - basic block: %bb.1
# CHECK-NEXT: - instruction: %t_p:_(s32) = G_TRUNC %p:_(p0)
# CHECK: Bad machine code: Generic extend/truncate must be all-vector or all-scalar
# CHECK-NEXT: - function: bad_generic_extends_and_truncates
# CHECK-NEXT: - basic block: %bb.2
# CHECK-NEXT: - instruction: %se_i32:_(<2 x s64>) = G_SEXT %i32:_(s32)
# CHECK: Bad machine code: Generic vector extend/truncate must preserve number of lanes
# CHECK-NEXT: - function: bad_generic_extends_and_truncates
# CHECK-NEXT: - basic block: %bb.3
# CHECK-NEXT: - instruction: %ze_v2i32:_(<4 x s64>) = G_ZEXT %v2i32:_(<2 x s32>)
# CHECK: Bad machine code: Generic extend has destination type no larger than source
# CHECK-NEXT: - function: bad_generic_extends_and_truncates
# CHECK-NEXT: - basic block: %bb.4
# CHECK-NEXT: - instruction: %ae_i32:_(s32) = G_ANYEXT %i32:_(s32)
# CHECK: Bad machine code: Generic truncate has destination type no smaller than source ***
# CHECK-NEXT: - function: bad_generic_extends_and_truncates
# CHECK-NEXT: - basic block: %bb.5
# CHECK-NEXT: - instruction: %ft_f32:_(s64) = G_FPTRUNC %f32:_(s32)
# CHECK: Bad machine code: Generic extend/truncate can not operate on pointers
# CHECK-NEXT: - function: bad_generic_extends_and_truncates
# CHECK-NEXT: - basic block: %bb.6
# CHECK-NEXT: - instruction: %ze_v2i128:_(<4 x p0>) = G_ZEXT %v2i128:_(<2 x s128>)
# CHECK: Bad machine code: Generic vector extend/truncate must preserve number of lanes
# CHECK-NEXT: - function: bad_generic_extends_and_truncates
# CHECK-NEXT: - basic block: %bb.6
# CHECK-NEXT: - instruction: %ze_v2i128:_(<4 x p0>) = G_ZEXT %v2i128:_(<2 x s128>)
# CHECK: Bad machine code: Generic extend has destination type no larger than source
# CHECK-NEXT: - function: bad_generic_extends_and_truncates
# CHECK-NEXT: - basic block: %bb.6
# CHECK-NEXT: - instruction: %ze_v2i128:_(<4 x p0>) = G_ZEXT %v2i128:_(<2 x s128>)
# CHECK: Bad machine code: Generic extend/truncate can not operate on pointers
# CHECK-NEXT: - function: bad_generic_extends_and_truncates
# CHECK-NEXT: - basic block: %bb.6
# CHECK-NEXT: - instruction: %fe_v2f128:_(p0) = G_FPEXT %v2f128:_(<2 x s128>)
# CHECK: Bad machine code: Generic extend/truncate must be all-vector or all-scalar
# CHECK-NEXT: - function: bad_generic_extends_and_truncates
# CHECK-NEXT: - basic block: %bb.6
# CHECK-NEXT: - instruction: %fe_v2f128:_(p0) = G_FPEXT %v2f128:_(<2 x s128>)
---
name: bad_generic_extends_and_truncates
tracksRegLiveness: true
body: |
bb.0:
liveins: $rdi, $esi, $rdx, $xmm0, $ymm1, $ymm2
%p:_(p0) = COPY $rdi
%i32:_(s32) = COPY $esi
%v2i32:_(<2 x s32>) = COPY $rdx
%f32:_(s32) = COPY $xmm0
%v2i128:_(<2 x s128>) = COPY $ymm1
%v2f128:_(<2 x s128>) = COPY $ymm2
bb.1:
%t_p:_(s32) = G_TRUNC %p
bb.2:
%se_i32:_(<2 x s64>) = G_SEXT %i32
bb.3:
%ze_v2i32:_(<4 x s64>) = G_ZEXT %v2i32
bb.4:
%ae_i32:_(s32) = G_ANYEXT %i32
bb.5:
%ft_f32:_(s64) = G_FPTRUNC %f32
bb.6:
%ze_v2i128:_(<4 x p0>) = G_ZEXT %v2i128
%fe_v2f128:_(p0) = G_FPEXT %v2f128
...